13#include "CoreMinimal.h"
31 template <CDefaultInitializable = T>
34 template <CMoveConstructible = T>
37 template <CCopyConstructible = T>
40 template <CMoveConstructible = T>
43 template <
typename Arg>
44 requires (!CSameAs<Arg, TChangeData> && !CSameAs<Arg, T>)
47 template <
typename... Args>
48 requires (
sizeof...(Args) > 1)
71 virtual T
const&
Get()
const = 0;
81 virtual void Set(T
const& value) = 0;
93 virtual void Modify(TUniqueFunction<
void(T&)>&& modifier,
bool alwaysNotify =
true) = 0;
96 template <CChangeListener<T> Function>
102 onChange(change.Next);
104 onChange(change.Next, change.Previous);
125 template <CChangeListener<T> Function>
139 template <
typename Object, CChangeListener<T> Function>
156 template <CConvertibleToDecayed<T> Other,
typename Guard>
161 [
this](Other
const& next) {
Set(next); },
177 template <
typename Other,
typename Guard>
178 requires CConvertibleToDecayed<Other, T>
183 [&otherState](T
const& next) { otherState.
Set(next); },
203 virtual bool Remove(FDelegateHandle
const& handle) = 0;
226 virtual TTuple<T const&, TUniquePtr<ReadLockVariant>>
GetOnAnyThread()
const = 0;
235 virtual TUniquePtr<ReadLockVariant>
ReadLock()
const = 0;
278 template <CBooleanTestable = T>
285 return static_cast<bool>(
Get()) && !previous;
293 template <CBooleanTestable = T>
301 template <CBooleanTestable = T>
308 return !
static_cast<bool>(
Get()) && previous;
316 template <CBooleanTestable = T>
320 template <CCoreEqualityComparable = T>
327 template <CCoreEqualityComparable = T>
333 template <
typename Self>
334 operator T
const& (
this Self&& self)
339 template <
typename Self>
342 if constexpr (CPointer<T>)
345 else if constexpr (CMemberAccessible<T>)
346 return self.Get().operator->();
348 else return &self.Get();
372 template <
typename T, FStatePolicy DefaultPolicy>
375 template <
typename ThreadSafeType,
typename NaiveType>
376 using ThreadSafeSwitch = std::conditional_t<DefaultPolicy.ThreadSafe, ThreadSafeType, NaiveType>;
389 template <CDefaultInitializable = T>
393 template <CCopyConstructible = T>
394 explicit TState(T
const& value) : Value(value) {}
397 template <CMoveConstructible = T>
398 explicit TState(T&& value) : Value(MoveTemp(value)) {}
401 template <CCopyConstructible = T>
405 template <CMoveConstructible = T>
409 template <
typename Arg>
410 requires (!CConvertibleTo<Arg, TState> && !CSameAs<Arg, T>)
414 template <
typename... Args>
415 requires (
sizeof...(Args) > 1)
418 virtual T
const&
Get()
const override {
return Value.Next; }
420 virtual TTuple<T const&, TUniquePtr<ReadLockVariant>>
GetOnAnyThread()
const override
425 virtual void Set(T
const& value)
override
428 ->WithMessage(
TEXT_"Attempting to set this state while this state is already being set from somewhere else.")
430 TGuardValue modifyingGuard(Modifying,
true);
434 if constexpr (CCoreEqualityComparable<T>)
437 if constexpr (CCopyable<T>)
439 Value.Previous = Value.Next;
444 OnChangeEvent.Broadcast(Value);
448 virtual void Modify(TUniqueFunction<
void(T&)>&& modifier,
bool alwaysNotify =
true)
override
451 ->WithMessage(
TEXT_"Attempting to set this state while this state is already being set from somewhere else.")
453 TGuardValue modifyingGuard(Modifying,
true);
456 TOptional<T> previous;
458 if constexpr (CCopyable<T>)
460 previous = Value.Next;
462 modifier(Value.Next);
464 if constexpr (CCopyable<T> && CCoreEqualityComparable<T>)
467 || !Value.Previous.IsSet()
468 || previous.GetValue() != Value.Next;
470 if constexpr (CCopyable<T>)
472 Value.Previous = previous;
475 OnChangeEvent.Broadcast(Value);
482 return OnChangeEvent.Add(onChange, eventPolicy);
486 virtual bool Remove(FDelegateHandle
const& handle)
override
489 return OnChangeEvent.Remove(handle);
495 return OnChangeEvent.RemoveAll(
object);
500 if constexpr (CCoreEqualityComparable<T>)
502 bool hasChanged = Value.Next != nextValue;
515 return OnChangeEvent.IsBroadcasted();
518 virtual TUniquePtr<ReadLockVariant>
ReadLock()
const override
520 return MakeUnique<ReadLockVariant>(TInPlaceType<ReadLockType>(), Mutex.
Get());
523 virtual TUniquePtr<WriteLockVariant>
WriteLock()
override
525 return MakeUnique<WriteLockVariant>(TInPlaceType<WriteLockType>(), Mutex.
Get());
530 return Value.Previous;
535 return Value.Previous.Get(fallback);
540 return Value.Previous.IsSet() ? Value.Previous.GetValue() : Value.Next;
547 ->WithMessage(
TEXT_"Attempting to set this state while this state is already being set from somewhere else.")
549 TGuardValue modifyingGuard(Modifying,
true);
551 Value.Previous = Value.Next;
554 template <CConvertibleTo<T> Other>
558 if constexpr (CCopyable<Other>)
560 else if constexpr (CMovable<Other>)
561 Set(MoveTemp(value));
570 bool Modifying =
false;
574 template <
typename LeftValue, CWeaklyEqualityComparableWith<LeftValue> RightValue>
577 return left.
Get() == right.
Get();
580 template <
typename LeftValue, CPartiallyOrderedWith<LeftValue> RightValue>
583 return left.
Get() <=> right.
Get();
#define ASSERT_QUIT(condition, returnOnFailure,...)
Use this instead of check macro if the checked expression shouldn't be ignored in shipping builds....
#define FWD(...)
Shorten forwarding expression with this macro so one may not need to specify explicit type.
#define TEXT_
A convenience alternative to Unreal's own TEXT macro but this one doesn't require parenthesis around ...
"Extension" of a common TMulticastDelegate. It allows to define optional "flags" when adding a bindin...
Concept describing a function which can listen to changes to the current value of a TState only.
Concept describing a function which can listen to changes to the current and the previous values of a...
Concept constraining given type to a state.
TInferredDelegate< Function, Captures... > From(Function func, Captures &&... captures)
Instead of specifying manually a delegate type, infer it from the input function and the extra captur...
bool operator==(IState< LeftValue > const &left, IState< RightValue > const &right)
bool operator<=>(IState< LeftValue > const &left, IState< RightValue > const &right)
Settings for the TEventDelegate class, which defines optional behavior when adding a binding to it.
A type wrapper around a default initializeable object which may not be copyable but which needs to be...
Flags expressing how TState should handle object comparison and lifespan.
bool StorePrevious
Store previous value as well. If the value is equality comparable store only when it's changed.
bool AlwaysStorePrevious
If the state value is equality comparable, store the previous value even when that's equal to the new...
bool AlwaysNotify
Always emit change notification when a value is set on TState and don't attempt to compare them.
Public API and base class for TState which shouldn't concern with policy flags or thread safety.
virtual T const & GetPreviousOrCurrent() const =0
Get the previous value if StorePrevious is enabled and there was at least one change or the current v...
bool HasChanged(T const &fallback) const
Returns true when current value is not equal to previous one.
virtual void NormalizePrevious()=0
Set the previous value to the current one. Useful in Ticks.
virtual int32 RemoveAll(const void *object)=0
Equivalent to TMulticastDelegate::RemoveAll
FDelegateHandle OnChange(TDelegate< void(TChangeData< T > const &)> onChange, FEventPolicy const &eventPolicy={})
Add a delegate which gets a TChangeData<T> const& if this state has been set.
virtual void Set(T const &value)=0
Set the wrapped value if for some reason the assignment operator is not enough or deleted....
virtual bool HasEverChanged() const =0
Returns true if this state has ever been changed from its initial value given at construction.
bool OnDown(bool fallback=false) const
Returns true when this state is currently true, but previously it wasn't.
bool BecameTrue(bool fallback=false) const
Returns true when this state is currently true, but previously it wasn't.
virtual void Modify(TUniqueFunction< void(T &)> &&modifier, bool alwaysNotify=true)=0
Modify this state via an l-value ref in a functor.
TVariant< FWriteScopeLock, FVoid > WriteLockVariant
virtual TOptional< T > const & GetPrevious() const =0
Get the previous value if StorePrevious is enabled and there was at least one change.
bool BecameFalse(bool fallback=false) const
Returns true when this state is currently false, but previously it wasn't.
virtual bool Remove(FDelegateHandle const &handle)=0
Equivalent to TMulticastDelegate::Remove
virtual T const & GetPrevious(T const &fallback) const =0
Get the previous value if StorePrevious is enabled and there was at least one change....
virtual bool HasChangedFrom(const T &nextValue)=0
Given value will be stored in the state only if T is equality comparable and it differs from the curr...
virtual T const & Get() const =0
Get the wrapped value if for some reason the conversion operator is not enough or deleted....
bool OnUp(bool fallback=false) const
Returns true when this state is currently false, but previously it wasn't.
virtual FDelegateHandle OnChangeImpl(TDelegate< void(TChangeData< T > const &)> &&onChange, FEventPolicy const &eventPolicy={})=0
void SyncPull(Guard &&object, IState< Other > &otherState)
Pull changes from another state, syncing the value between the two. Values will be copied.
FDelegateHandle OnChange(Function const &onChange, FEventPolicy const &eventPolicy={})
Add a function without object binding which either has one or two arguments with the following signat...
FDelegateHandle OnChange(Object &&object, Function const &onChange, FEventPolicy const &eventPolicy={})
Add a function with an object binding which either has one or two arguments with the following signat...
void SyncPush(Guard &&object, IState< Other > &otherState)
Push changes from another state, syncing the value between the two. Values will be copied.
virtual TUniquePtr< ReadLockVariant > ReadLock() const =0
Lock this state for reading for the current scope.
bool HasChanged() const
Returns true when current value is not equal to previous one.
TVariant< FReadScopeLock, FVoid > ReadLockVariant
virtual TTuple< T const &, TUniquePtr< ReadLockVariant > > GetOnAnyThread() const =0
If thread safety is enabled in DefaultPolicy, get the value with a bundled read-scope-lock....
static auto DelegateValueArgument(Function const &onChange)
virtual TUniquePtr< WriteLockVariant > WriteLock()=0
Lock this state for writing for the current scope.
virtual ~IState()=default
auto && operator->(this Self &&self)
This struct holds the circumstances of the data change. It cannot be moved or copied and its lifespan...
TChangeData(Args &&... args)
TChangeData(const TChangeData &from)
TChangeData(TChangeData &&from) noexcept
Storage wrapper for any value which state needs to be tracked or their change needs to be observed....
virtual TUniquePtr< WriteLockVariant > WriteLock() override
Lock this state for writing for the current scope.
TState(T &&value)
Enable move constructor for T only when T is move constructable.
virtual int32 RemoveAll(const void *object) override
Equivalent to TMulticastDelegate::RemoveAll
virtual void Set(T const &value) override
Set the wrapped value if for some reason the assignment operator is not enough or deleted....
std::conditional_t< DefaultPolicy.ThreadSafe, ThreadSafeType, NaiveType > ThreadSafeSwitch
virtual FDelegateHandle OnChangeImpl(TDelegate< void(TChangeData< T > const &)> &&onChange, FEventPolicy const &eventPolicy={}) override
virtual bool Remove(FDelegateHandle const &handle) override
Equivalent to TMulticastDelegate::Remove
TState(TState const &other)
Enable copy constructor for the state only when T is copy constructable.
virtual void Modify(TUniqueFunction< void(T &)> &&modifier, bool alwaysNotify=true) override
Modify this state via an l-value ref in a functor.
virtual T const & GetPreviousOrCurrent() const override
Get the previous value if StorePrevious is enabled and there was at least one change or the current v...
static constexpr FStatePolicy DefaultPolicyFlags
virtual TUniquePtr< ReadLockVariant > ReadLock() const override
Lock this state for reading for the current scope.
virtual T const & GetPrevious(T const &fallback) const override
Get the previous value if StorePrevious is enabled and there was at least one change....
TState(Arg &&arg)
Construct value in-place with non-semantic single argument constructor.
TState()
Enable default constructor only when T is default initializable.
virtual TTuple< T const &, TUniquePtr< ReadLockVariant > > GetOnAnyThread() const override
If thread safety is enabled in DefaultPolicy, get the value with a bundled read-scope-lock....
virtual bool HasChangedFrom(const T &nextValue) override
Given value will be stored in the state only if T is equality comparable and it differs from the curr...
ThreadSafeSwitch< FReadScopeLock, FVoid > ReadLockType
virtual TOptional< T > const & GetPrevious() const override
Get the previous value if StorePrevious is enabled and there was at least one change.
ThreadSafeSwitch< FWriteScopeLock, FVoid > WriteLockType
virtual void NormalizePrevious() override
Set the previous value to the current one. Useful in Ticks.
TState(Args &&... args)
Construct value in-place with multiple argument constructor.
TState(TState &&other)
Enable move constructor for the state only when T is move constructable.
virtual T const & Get() const override
Get the wrapped value if for some reason the conversion operator is not enough or deleted....
TState(T const &value)
Enable copy constructor for T only when T is copy constructable.
virtual bool HasEverChanged() const override
Returns true if this state has ever been changed from its initial value given at construction.