// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Containers/ArrayView.h" #include "Containers/ContainersFwd.h" #include "Containers/StringFwd.h" #include "CoreTypes.h" #include "DerivedDataValueId.h" #include "Misc/EnumClassFlags.h" #include "Templates/RefCounting.h" #include "Templates/UnrealTemplate.h" #define UE_API DERIVEDDATACACHE_API class FCbFieldView; class FCbObjectView; class FCbWriter; template class TFunctionRef; namespace UE::DerivedData::Private { class ICacheRecordPolicyShared; } namespace UE::DerivedData { class FOptionalCacheRecordPolicy; } namespace UE::DerivedData { /** * Flags to control the behavior of cache requests. * * Flags can be combined to cover a variety of requirements. Examples: * * Get(Default): Fetch from any cache. Store the response to any caches if missing. * Get(Local): Fetch from any local cache. Store the response to any local caches if missing. * Get(Query | StoreLocal): Fetch from any cache. Store response to any local caches if missing. * Get(Query | SkipData): Check for existence in any cache. Do not store to any caches if missing. * Get(Default | SkipData): Check for existence in any cache. Store the response to any caches if missing. * Get(Default | PartialRecord): Fetch from any cache, and return a partial record if values are missing data. * * Put(Default): Store to every cache, and do not overwrite existing valid records or values. * Put(Store): Store to every cache, and overwrite existing records or values. * Put(Local): Store to every local cache, skipping remote caches. * Put(Default | PartialRecord): Store to every cache, even if the record has missing data for its values. */ enum class ECachePolicy : uint32 { /** A value with no flags. Disables access to the cache unless combined with other flags. */ None = 0, /** Allow a cache request to query local caches. */ QueryLocal = 1 << 0, /** Allow a cache request to query remote caches. */ QueryRemote = 1 << 1, /** Allow a cache request to query any caches. */ Query = QueryLocal | QueryRemote, /** Allow cache records and values to be stored in local caches. */ StoreLocal = 1 << 2, /** Allow cache records and values to be stored in remote caches. */ StoreRemote = 1 << 3, /** Allow cache records and values to be stored in any caches. */ Store = StoreLocal | StoreRemote, /** Allow cache requests to query and store records and values in local caches. */ Local = QueryLocal | StoreLocal, /** Allow cache requests to query and store records and values in remote caches. */ Remote = QueryRemote | StoreRemote, /** Allow cache requests to query and store records and values in any caches. */ Default = Query | Store, /** Skip fetching the data for values. */ SkipData = 1 << 4, /** Skip fetching the metadata for record requests. */ SkipMeta = 1 << 5, /** * Partial output will be provided with the error status when a required value is missing. * * This is meant for cases when the missing values can be individually recovered, or rebuilt, * without rebuilding the whole record. The cache automatically adds this flag when there are * other cache stores that it may be able to recover missing values from. * * Missing values will be returned in the records, but with only the hash and size. * * Applying this flag for a put of a record allows a partial record to be stored. */ PartialRecord = 1 << 6, /** * Keep records and values in the cache for at least the duration of the session. * * This flag hints that the records and values that it is applied to may be accessed again in * this session. The cache will make an effort to prevent eviction of the records and values, * though an absolute guarantee is impossible. * * This flag is meant to be used when subsequent accesses will not tolerate a cache miss. */ KeepAlive = 1 << 7, }; ENUM_CLASS_FLAGS(ECachePolicy); /** * Returns a cache policy that encompasses the operations requested by the both arguments. * * Examples: * - (Local, Remote | SkipData) -> Default * - (Default, Local | SkipMeta) -> Default * - (Query, StoreRemote) -> Query | StoreRemote */ UE_API ECachePolicy CombineCachePolicy(ECachePolicy A, ECachePolicy B); /** Append a non-empty text version of the policy to the builder. */ UE_API FAnsiStringBuilderBase& operator<<(FAnsiStringBuilderBase& Builder, ECachePolicy Policy); UE_API FWideStringBuilderBase& operator<<(FWideStringBuilderBase& Builder, ECachePolicy Policy); UE_API FUtf8StringBuilderBase& operator<<(FUtf8StringBuilderBase& Builder, ECachePolicy Policy); /** Try to parse a policy from text written by operator<<. */ UE_API bool TryLexFromString(ECachePolicy& OutPolicy, FUtf8StringView String); UE_API bool TryLexFromString(ECachePolicy& OutPolicy, FWideStringView String); UE_API FCbWriter& operator<<(FCbWriter& Writer, ECachePolicy Policy); UE_API bool LoadFromCompactBinary(FCbFieldView Field, ECachePolicy& OutPolicy, ECachePolicy Default = ECachePolicy::Default); /** A value ID and the cache policy to use for that value. */ struct FCacheValuePolicy { FValueId Id; ECachePolicy Policy = ECachePolicy::Default; /** Flags that are valid on a value policy. */ static constexpr ECachePolicy PolicyMask = ECachePolicy::Default | ECachePolicy::SkipData; }; UE_API FCbWriter& operator<<(FCbWriter& Writer, const FCacheValuePolicy& Policy); UE_API bool LoadFromCompactBinary(FCbFieldView Field, FCacheValuePolicy& OutPolicy); /** Interface for the private implementation of the cache record policy. */ class Private::ICacheRecordPolicyShared { public: virtual ~ICacheRecordPolicyShared() = default; virtual void AddRef() const = 0; virtual void Release() const = 0; virtual void AddValuePolicy(const FCacheValuePolicy& Policy) = 0; virtual TConstArrayView GetValuePolicies() const = 0; }; /** * Flags to control the behavior of cache record requests, with optional overrides by value. * * Examples: * - A base policy of None with value policy overrides of Default will fetch those values if they * exist in the record, and skip data for any other values. * - A base policy of Default, with value policy overrides of (Query | SkipData), will skip those * values, but still check if they exist, and will load any other values. */ class FCacheRecordPolicy { public: /** Construct a cache record policy that uses the default policy. */ FCacheRecordPolicy() = default; /** Construct a cache record policy with a uniform policy for the record and every value. */ inline FCacheRecordPolicy(ECachePolicy BasePolicy) : RecordPolicy(BasePolicy) , DefaultValuePolicy(BasePolicy & FCacheValuePolicy::PolicyMask) { } /** Returns true if this is the default cache policy with no overrides for values. */ inline bool IsDefault() const { return !Shared && RecordPolicy == ECachePolicy::Default; } /** Returns true if the record and every value use the same cache policy. */ inline bool IsUniform() const { return !Shared; } /** Returns the cache policy to use for the record. */ inline ECachePolicy GetRecordPolicy() const { return RecordPolicy; } /** Returns the base cache policy that this was constructed from. */ inline ECachePolicy GetBasePolicy() const { return DefaultValuePolicy | (RecordPolicy & ~FCacheValuePolicy::PolicyMask); } /** Returns the cache policy to use for the value. */ UE_API ECachePolicy GetValuePolicy(const FValueId& Id) const; /** Returns the array of cache policy overrides for values, sorted by ID. */ inline TConstArrayView GetValuePolicies() const { return Shared ? Shared->GetValuePolicies() : TConstArrayView(); } /** Returns a copy of this policy transformed by an operation. */ UE_API FCacheRecordPolicy Transform(TFunctionRef Op) const; private: friend class FCacheRecordPolicyBuilder; friend class FOptionalCacheRecordPolicy; ECachePolicy RecordPolicy = ECachePolicy::Default; ECachePolicy DefaultValuePolicy = ECachePolicy::Default; TRefCountPtr Shared; }; /** A cache record policy builder is used to construct a cache record policy. */ class FCacheRecordPolicyBuilder { public: /** Construct a policy builder that uses the default policy as its base policy. */ FCacheRecordPolicyBuilder() = default; /** Construct a policy builder that uses the provided policy for the record and values with no override. */ inline explicit FCacheRecordPolicyBuilder(ECachePolicy Policy) : BasePolicy(Policy) { } /** Adds a cache policy override for a value. Must contain only flags in FCacheRecordValue::PolicyMask. */ UE_API void AddValuePolicy(const FCacheValuePolicy& Value); inline void AddValuePolicy(const FValueId& Id, ECachePolicy Policy) { AddValuePolicy({Id, Policy}); } /** Build a cache record policy, which makes this builder subsequently unusable. */ UE_API FCacheRecordPolicy Build(); private: ECachePolicy BasePolicy = ECachePolicy::Default; TRefCountPtr Shared; }; /** * A cache record policy that can be null. * * @see FCacheRecordPolicy */ class FOptionalCacheRecordPolicy : private FCacheRecordPolicy { public: inline FOptionalCacheRecordPolicy() : FCacheRecordPolicy(~ECachePolicy::None) {} inline FOptionalCacheRecordPolicy(FCacheRecordPolicy&& InOutput) : FCacheRecordPolicy(MoveTemp(InOutput)) {} inline FOptionalCacheRecordPolicy(const FCacheRecordPolicy& InOutput) : FCacheRecordPolicy(InOutput) {} inline FOptionalCacheRecordPolicy& operator=(FCacheRecordPolicy&& InOutput) { FCacheRecordPolicy::operator=(MoveTemp(InOutput)); return *this; } inline FOptionalCacheRecordPolicy& operator=(const FCacheRecordPolicy& InOutput) { FCacheRecordPolicy::operator=(InOutput); return *this; } /** Returns the cache record policy. The caller must check for null before using this accessor. */ inline const FCacheRecordPolicy& Get() const & { return *this; } inline FCacheRecordPolicy Get() && { return MoveTemp(*this); } inline bool IsNull() const { return RecordPolicy == ~ECachePolicy::None; } inline bool IsValid() const { return !IsNull(); } inline explicit operator bool() const { return !IsNull(); } inline void Reset() { *this = FOptionalCacheRecordPolicy(); } }; UE_API FCbWriter& operator<<(FCbWriter& Writer, const FCacheRecordPolicy& Policy); UE_API bool LoadFromCompactBinary(FCbFieldView Field, FCacheRecordPolicy& OutPolicy); } // UE::DerivedData #undef UE_API