Skip to content

Commit ef209c6

Browse files
committed
Adds unsafe_store operation
1 parent d4a1a1c commit ef209c6

File tree

5 files changed

+37
-1
lines changed

5 files changed

+37
-1
lines changed

internals/testing/smoke_test.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ using namespace trade_v1;
99

1010
auto smoke_test = test([]() {
1111
atom<int> xA = 1;
12-
atom<float> yA = 2.f;
12+
atom<float> yA = 1.f;
1313
atom<int> zA = 3;
1414
atom<std::shared_ptr<int>> p(std::make_shared<int>(32));
1515

1616
verify(atomically(assume_readonly, []() { return true; }));
1717

18+
yA.unsafe_store(2);
19+
1820
{
1921
verify(1 == xA.unsafe_load());
2022
verify(2 == yA.unsafe_load());

provides/include/trade_v1/private/private-methods.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,27 @@ Value &trade_v1::Private::store(atom_t<Value> &atom, Forwardable &&value) {
107107
return access->m_current;
108108
}
109109

110+
template <class Value>
111+
const Value &trade_v1::Private::unsafe_store(atom_t<Value> &atom,
112+
const Value &value) {
113+
auto &lock = s_locks[lock_ix_of(&atom)];
114+
backoff_t backoff;
115+
while (true) {
116+
auto u = lock.m_clock.load();
117+
if (0 <= static_cast<signed_clock_t>(u)) {
118+
if (lock.m_clock.compare_exchange_weak(
119+
u, ~u, std::memory_order_acquire)) {
120+
atom.m_value.store(value, std::memory_order_relaxed);
121+
if (auto first = lock.m_first)
122+
signal(first);
123+
lock.m_clock.store(s_clock++, std::memory_order_release);
124+
return value;
125+
}
126+
}
127+
backoff();
128+
}
129+
}
130+
110131
template <class Value> Value &trade_v1::Private::ref(atom_t<Value> &atom) {
111132
auto transaction = s_transaction;
112133
auto access = insert(transaction, &atom);

provides/include/trade_v1/private/private.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ class Private {
108108
template <class Value, class Forwardable>
109109
static Value &store(atom_t<Value> &atom, Forwardable &&value);
110110

111+
template <class Value>
112+
static const Value &unsafe_store(atom_t<Value> &atom, const Value &value);
113+
111114
template <class Value> static Value &ref(atom_t<Value> &atom);
112115

113116
template <class Config, class Action>

provides/include/trade_v1/synopsis.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ template <class Value> struct atom : Private::atom_t<Value> {
4141
/// value` is equivalent to `atom.store(value)`.
4242
template <class Forwardable> Value &store(Forwardable &&value);
4343

44+
/// Store the given value to the given atom as a single transaction. Note
45+
/// that this cannot be used safely inside an `atomically` block, because it
46+
/// can prevent the `atomically` block from ever completing.
47+
const Value &unsafe_store(const Value &value);
48+
4449
/// Returns a mutable reference to the current value of the atom within a
4550
/// transaction. `atom.ref()` is roughly equivalent to
4651
/// `atom.store(atom.load())`, but accesses the transaction log only once.

provides/include/trade_v1/trade.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ Value &trade_v1::atom<Value>::store(Forwardable &&value) {
3939
return Private::store(*this, std::forward<Forwardable>(value));
4040
}
4141

42+
template <class Value>
43+
const Value &trade_v1::atom<Value>::unsafe_store(const Value &value) {
44+
return Private::unsafe_store(*this, value);
45+
}
46+
4247
template <class Config, class Action>
4348
std::invoke_result_t<Action> trade_v1::atomically(Config config,
4449
Action &&action) {

0 commit comments

Comments
 (0)