|
9 | 9 |
|
10 | 10 | #include "reaction/graph/batch.h" |
11 | 11 | #include "reaction/expression/expression.h" |
| 12 | +#include "reaction/expression/atomic_operations.h" |
12 | 13 | #include "reaction/policy/invalidation.h" |
13 | 14 | #include "reaction/concurrency/thread_safety.h" |
14 | 15 | #include "reaction/core/exception.h" |
@@ -116,6 +117,31 @@ class ReactImpl final : public Expression<Expr, Type, TR>, public IV { |
116 | 117 | } |
117 | 118 | } |
118 | 119 |
|
| 120 | + /** |
| 121 | + * @brief Generic atomic operation helper. |
| 122 | + * |
| 123 | + * @tparam F Operation function type (should take Type& and return bool indicating if changed). |
| 124 | + * @param operation The operation to perform on the value. |
| 125 | + * @param alwaysChanged If true, always consider the operation as changing the value. |
| 126 | + */ |
| 127 | + template <typename F> |
| 128 | + void atomicOperation(F &&operation, bool alwaysChanged = false) { |
| 129 | + REACTION_REGISTER_THREAD(); |
| 130 | + bool changed = false; |
| 131 | + { |
| 132 | + ConditionalUniqueLock<ConditionalSharedMutex> lock(this->m_valueMutex); |
| 133 | + if (this->m_ptr) { |
| 134 | + changed = operation(*this->m_ptr); |
| 135 | + if (alwaysChanged) { |
| 136 | + changed = true; |
| 137 | + } |
| 138 | + } |
| 139 | + } |
| 140 | + if (!g_batch_execute && changed) { |
| 141 | + this->notify(true); |
| 142 | + } |
| 143 | + } |
| 144 | + |
119 | 145 | private: |
120 | 146 | std::atomic<int> m_weakRefCount{0}; ///< Reference counter for weak lifetime tracking. |
121 | 147 | }; |
@@ -254,6 +280,120 @@ class React { |
254 | 280 | return ObserverGraph::getInstance().getName(getPtr()); |
255 | 281 | } |
256 | 282 |
|
| 283 | + // ==================== Compound Assignment Operators ==================== |
| 284 | + |
| 285 | + /// @brief Compound addition assignment operator (+=) |
| 286 | + template <typename U> |
| 287 | + requires(IsVarExpr<Expr> && !ConstType<Type> && AddAssignable<Type, U>) |
| 288 | + React &operator+=(const U &rhs) { |
| 289 | + atomicAddAssign(*getPtr(), rhs); |
| 290 | + return *this; |
| 291 | + } |
| 292 | + |
| 293 | + /// @brief Compound subtraction assignment operator (-=) |
| 294 | + template <typename U> |
| 295 | + requires(IsVarExpr<Expr> && !ConstType<Type> && SubtractAssignable<Type, U>) |
| 296 | + React &operator-=(const U &rhs) { |
| 297 | + atomicSubtractAssign(*getPtr(), rhs); |
| 298 | + return *this; |
| 299 | + } |
| 300 | + |
| 301 | + /// @brief Compound multiplication assignment operator (*=) |
| 302 | + template <typename U> |
| 303 | + requires(IsVarExpr<Expr> && !ConstType<Type> && MultiplyAssignable<Type, U>) |
| 304 | + React &operator*=(const U &rhs) { |
| 305 | + atomicMultiplyAssign(*getPtr(), rhs); |
| 306 | + return *this; |
| 307 | + } |
| 308 | + |
| 309 | + /// @brief Compound division assignment operator (/=) |
| 310 | + template <typename U> |
| 311 | + requires(IsVarExpr<Expr> && !ConstType<Type> && DivideAssignable<Type, U>) |
| 312 | + React &operator/=(const U &rhs) { |
| 313 | + atomicDivideAssign(*getPtr(), rhs); |
| 314 | + return *this; |
| 315 | + } |
| 316 | + |
| 317 | + /// @brief Compound modulo assignment operator (%=) |
| 318 | + template <typename U> |
| 319 | + requires(IsVarExpr<Expr> && !ConstType<Type> && ModuloAssignable<Type, U>) |
| 320 | + React &operator%=(const U &rhs) { |
| 321 | + atomicModuloAssign(*getPtr(), rhs); |
| 322 | + return *this; |
| 323 | + } |
| 324 | + |
| 325 | + /// @brief Compound bitwise AND assignment operator (&=) |
| 326 | + template <typename U> |
| 327 | + requires(IsVarExpr<Expr> && !ConstType<Type> && BitwiseAndAssignable<Type, U>) |
| 328 | + React &operator&=(const U &rhs) { |
| 329 | + atomicBitwiseAndAssign(*getPtr(), rhs); |
| 330 | + return *this; |
| 331 | + } |
| 332 | + |
| 333 | + /// @brief Compound bitwise OR assignment operator (|=) |
| 334 | + template <typename U> |
| 335 | + requires(IsVarExpr<Expr> && !ConstType<Type> && BitwiseOrAssignable<Type, U>) |
| 336 | + React &operator|=(const U &rhs) { |
| 337 | + atomicBitwiseOrAssign(*getPtr(), rhs); |
| 338 | + return *this; |
| 339 | + } |
| 340 | + |
| 341 | + /// @brief Compound bitwise XOR assignment operator (^=) |
| 342 | + template <typename U> |
| 343 | + requires(IsVarExpr<Expr> && !ConstType<Type> && BitwiseXorAssignable<Type, U>) |
| 344 | + React &operator^=(const U &rhs) { |
| 345 | + atomicBitwiseXorAssign(*getPtr(), rhs); |
| 346 | + return *this; |
| 347 | + } |
| 348 | + |
| 349 | + /// @brief Compound left shift assignment operator (<<=) |
| 350 | + template <typename U> |
| 351 | + requires(IsVarExpr<Expr> && !ConstType<Type> && LeftShiftAssignable<Type, U>) |
| 352 | + React &operator<<=(const U &rhs) { |
| 353 | + atomicLeftShiftAssign(*getPtr(), rhs); |
| 354 | + return *this; |
| 355 | + } |
| 356 | + |
| 357 | + /// @brief Compound right shift assignment operator (>>=) |
| 358 | + template <typename U> |
| 359 | + requires(IsVarExpr<Expr> && !ConstType<Type> && RightShiftAssignable<Type, U>) |
| 360 | + React &operator>>=(const U &rhs) { |
| 361 | + atomicRightShiftAssign(*getPtr(), rhs); |
| 362 | + return *this; |
| 363 | + } |
| 364 | + |
| 365 | + // ==================== Increment/Decrement Operators ==================== |
| 366 | + |
| 367 | + /// @brief Pre-increment operator (++var) |
| 368 | + template <typename T = Type> |
| 369 | + requires(IsVarExpr<Expr> && !ConstType<Type> && PreIncrementable<T>) |
| 370 | + React &operator++() { |
| 371 | + atomicIncrement(*getPtr()); |
| 372 | + return *this; |
| 373 | + } |
| 374 | + |
| 375 | + /// @brief Post-increment operator (var++) |
| 376 | + template <typename T = Type> |
| 377 | + requires(IsVarExpr<Expr> && !ConstType<Type> && PostIncrementable<T>) |
| 378 | + Type operator++(int) { |
| 379 | + return atomicPostIncrement(*getPtr()); |
| 380 | + } |
| 381 | + |
| 382 | + /// @brief Pre-decrement operator (--var) |
| 383 | + template <typename T = Type> |
| 384 | + requires(IsVarExpr<Expr> && !ConstType<Type> && PreDecrementable<T>) |
| 385 | + React &operator--() { |
| 386 | + atomicDecrement(*getPtr()); |
| 387 | + return *this; |
| 388 | + } |
| 389 | + |
| 390 | + /// @brief Post-decrement operator (var--) |
| 391 | + template <typename T = Type> |
| 392 | + requires(IsVarExpr<Expr> && !ConstType<Type> && PostDecrementable<T>) |
| 393 | + Type operator--(int) { |
| 394 | + return atomicPostDecrement(*getPtr()); |
| 395 | + } |
| 396 | + |
257 | 397 | /// @brief Get the internal shared pointer for advanced operations. |
258 | 398 | [[nodiscard]] std::shared_ptr<react_type> getPtr() const { |
259 | 399 | // Thread-safe access to weak_ptr using conditional mutex |
|
0 commit comments