Skip to content

Commit d82997b

Browse files
committed
Adds unsafe_store operation
1 parent 43ab248 commit d82997b

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
@@ -109,6 +109,27 @@ Value &trade_v1::Private::store(atom_t<Value> &atom, Forwardable &&value) {
109109
return access->m_current;
110110
}
111111

112+
template <class Value>
113+
const Value &trade_v1::Private::unsafe_store(atom_t<Value> &atom,
114+
const Value &value) {
115+
auto &lock = s_locks[lock_ix_of(&atom)];
116+
molecular::backoff backoff;
117+
while (true) {
118+
auto u = lock.m_clock.load();
119+
if (0 <= static_cast<signed_clock_t>(u)) {
120+
if (lock.m_clock.compare_exchange_weak(
121+
u, ~u, std::memory_order_acquire)) {
122+
atom.m_value.store(value, std::memory_order_relaxed);
123+
if (auto first = lock.m_first)
124+
signal(first);
125+
lock.m_clock.store(s_clock++, std::memory_order_release);
126+
return value;
127+
}
128+
}
129+
backoff();
130+
}
131+
}
132+
112133
template <class Value> Value &trade_v1::Private::ref(atom_t<Value> &atom) {
113134
auto transaction = s_transaction;
114135
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
@@ -106,6 +106,9 @@ class Private {
106106
template <class Value, class Forwardable>
107107
static Value &store(atom_t<Value> &atom, Forwardable &&value);
108108

109+
template <class Value>
110+
static const Value &unsafe_store(atom_t<Value> &atom, const Value &value);
111+
109112
template <class Value> static Value &ref(atom_t<Value> &atom);
110113

111114
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)