diff options
| author | Per Larsson <[email protected]> | 2021-09-27 11:02:38 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-09-27 11:02:38 +0200 |
| commit | b34490abe0f19f22499fb9dafb9b7431ca5ecc95 (patch) | |
| tree | bc16bece4710c612324318551dfd92fdbeb29232 | |
| parent | stats: Completed Meter implementation (diff) | |
| download | zen-b34490abe0f19f22499fb9dafb9b7431ca5ecc95.tar.xz zen-b34490abe0f19f22499fb9dafb9b7431ca5ecc95.zip | |
Ported CbValue from Unreal to Zen (#10)
CompactBinary: Ported CbValue changes from UE5
| -rw-r--r-- | zencore/compactbinary.cpp | 172 | ||||
| -rw-r--r-- | zencore/include/zencore/compactbinary.h | 80 | ||||
| -rw-r--r-- | zencore/include/zencore/compactbinaryvalue.h | 290 | ||||
| -rw-r--r-- | zencore/include/zencore/memory.h | 6 |
4 files changed, 439 insertions, 109 deletions
diff --git a/zencore/compactbinary.cpp b/zencore/compactbinary.cpp index f4908aa9a..a68096c36 100644 --- a/zencore/compactbinary.cpp +++ b/zencore/compactbinary.cpp @@ -3,6 +3,7 @@ #include "zencore/compactbinary.h" #include <zencore/compactbinaryvalidation.h> +#include <zencore/compactbinaryvalue.h> #include <zencore/compress.h> #include <zencore/endian.h> #include <zencore/stream.h> @@ -66,21 +67,8 @@ TimeSpan::Set(int Days, int Hours, int Minutes, int Seconds, int FractionNano) ////////////////////////////////////////////////////////////////////////// namespace CompactBinaryPrivate { - static constexpr const uint8_t GEmptyObjectPayload[] = {uint8_t(CbFieldType::Object), 0x00}; static constexpr const uint8_t GEmptyArrayPayload[] = {uint8_t(CbFieldType::Array), 0x01, 0x00}; - - template<typename T> - static constexpr inline T ReadUnaligned(const void* const Memory) - { -#if PLATFORM_SUPPORTS_UNALIGNED_LOADS - return *static_cast<const T*>(Memory); -#else - T Value; - memcpy(&Value, Memory, sizeof(Value)); - return Value; -#endif - } } // namespace CompactBinaryPrivate ////////////////////////////////////////////////////////////////////////// @@ -151,14 +139,10 @@ CbFieldView::AsArrayView() MemoryView CbFieldView::AsBinaryView(const MemoryView Default) { - if (CbFieldTypeOps::IsBinary(Type)) + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsBinary(Accessor.GetType())) { - const uint8_t* const PayloadBytes = static_cast<const uint8_t*>(Payload); - uint32_t ValueSizeByteCount; - const uint64_t ValueSize = ReadVarUInt(PayloadBytes, ValueSizeByteCount); - Error = CbFieldError::None; - return MemoryView(PayloadBytes + ValueSizeByteCount, ValueSize); + return Accessor.AsBinary(); } else { @@ -170,20 +154,25 @@ CbFieldView::AsBinaryView(const MemoryView Default) std::string_view CbFieldView::AsString(const std::string_view Default) { - if (CbFieldTypeOps::IsString(Type)) + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsString(Accessor.GetType())) { - const char* const PayloadChars = static_cast<const char*>(Payload); - uint32_t ValueSizeByteCount; - const uint64_t ValueSize = ReadVarUInt(PayloadChars, ValueSizeByteCount); - - if (ValueSize >= (uint64_t(1) << 31)) - { - Error = CbFieldError::RangeError; - return Default; - } + Error = CbFieldError::None; + return Accessor.AsString(); + } + else + { + Error = CbFieldError::TypeError; + return Default; + } +} +std::u8string_view +CbFieldView::AsU8String(const std::u8string_view Default) +{ + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsString(Accessor.GetType())) + { Error = CbFieldError::None; - return std::string_view(PayloadChars + ValueSizeByteCount, ValueSize); + return Accessor.AsU8String(); } else { @@ -193,23 +182,11 @@ CbFieldView::AsString(const std::string_view Default) } uint64_t -CbFieldView::AsInteger(const uint64_t Default, const IntegerParams Params) +CbFieldView::AsInteger(const uint64_t Default, const CompactBinaryPrivate::IntegerParams Params) { - if (CbFieldTypeOps::IsInteger(Type)) + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsInteger(Accessor.GetType())) { - // A shift of a 64-bit value by 64 is undefined so shift by one less because magnitude is never zero. - const uint64_t OutOfRangeMask = uint64_t(-2) << (Params.MagnitudeBits - 1); - const uint64_t IsNegative = uint8_t(Type) & 1; - - uint32_t MagnitudeByteCount; - const uint64_t Magnitude = ReadVarUInt(Payload, MagnitudeByteCount); - const uint64_t Value = Magnitude ^ -int64_t(IsNegative); - - const uint64_t IsInRange = (!(Magnitude & OutOfRangeMask)) & ((!IsNegative) | Params.IsSigned); - Error = IsInRange ? CbFieldError::None : CbFieldError::RangeError; - - const uint64_t UseValueMask = -int64_t(IsInRange); - return (Value & UseValueMask) | (Default & ~UseValueMask); + return Accessor.AsInteger(Params, &Error, Default); } else { @@ -221,25 +198,24 @@ CbFieldView::AsInteger(const uint64_t Default, const IntegerParams Params) float CbFieldView::AsFloat(const float Default) { - switch (CbFieldTypeOps::GetType(Type)) + switch (CbValue Accessor = GetValue(); Accessor.GetType()) { case CbFieldType::IntegerPositive: case CbFieldType::IntegerNegative: { - const uint64_t IsNegative = uint8_t(Type) & 1; + const uint64_t IsNegative = uint8_t(Accessor.GetType()) & 1; constexpr uint64_t OutOfRangeMask = ~((uint64_t(1) << /*FLT_MANT_DIG*/ 24) - 1); uint32_t MagnitudeByteCount; - const int64_t Magnitude = ReadVarUInt(Payload, MagnitudeByteCount) + IsNegative; + const int64_t Magnitude = ReadVarUInt(Accessor.GetData(), MagnitudeByteCount) + IsNegative; const uint64_t IsInRange = !(Magnitude & OutOfRangeMask); Error = IsInRange ? CbFieldError::None : CbFieldError::RangeError; return IsInRange ? float(IsNegative ? -Magnitude : Magnitude) : Default; } case CbFieldType::Float32: { - Error = CbFieldError::None; - const uint32_t Value = FromNetworkOrder(CompactBinaryPrivate::ReadUnaligned<uint32_t>(Payload)); - return reinterpret_cast<const float&>(Value); + Error = CbFieldError::None; + return Accessor.AsFloat32(); } case CbFieldType::Float64: Error = CbFieldError::RangeError; @@ -253,31 +229,29 @@ CbFieldView::AsFloat(const float Default) double CbFieldView::AsDouble(const double Default) { - switch (CbFieldTypeOps::GetType(Type)) + switch (CbValue Accessor = GetValue(); Accessor.GetType()) { case CbFieldType::IntegerPositive: case CbFieldType::IntegerNegative: { - const uint64_t IsNegative = uint8_t(Type) & 1; + const uint64_t IsNegative = uint8_t(Accessor.GetType()) & 1; constexpr uint64_t OutOfRangeMask = ~((uint64_t(1) << /*DBL_MANT_DIG*/ 53) - 1); uint32_t MagnitudeByteCount; - const int64_t Magnitude = ReadVarUInt(Payload, MagnitudeByteCount) + IsNegative; + const int64_t Magnitude = ReadVarUInt(Accessor.GetData(), MagnitudeByteCount) + IsNegative; const uint64_t IsInRange = !(Magnitude & OutOfRangeMask); Error = IsInRange ? CbFieldError::None : CbFieldError::RangeError; return IsInRange ? double(IsNegative ? -Magnitude : Magnitude) : Default; } case CbFieldType::Float32: { - Error = CbFieldError::None; - const uint32_t Value = FromNetworkOrder(CompactBinaryPrivate::ReadUnaligned<uint32_t>(Payload)); - return reinterpret_cast<const float&>(Value); + Error = CbFieldError::None; + return Accessor.AsFloat32(); } case CbFieldType::Float64: { - Error = CbFieldError::None; - const uint64_t Value = FromNetworkOrder(CompactBinaryPrivate::ReadUnaligned<uint64_t>(Payload)); - return reinterpret_cast<const double&>(Value); + Error = CbFieldError::None; + return Accessor.AsFloat64(); } default: Error = CbFieldError::TypeError; @@ -288,19 +262,19 @@ CbFieldView::AsDouble(const double Default) bool CbFieldView::AsBool(const bool bDefault) { - const CbFieldType LocalType = Type; - const bool bIsBool = CbFieldTypeOps::IsBool(LocalType); - Error = bIsBool ? CbFieldError::None : CbFieldError::TypeError; - return (uint8_t(bIsBool) & uint8_t(LocalType) & 1) | ((!bIsBool) & bDefault); + CbValue Accessor = GetValue(); + const bool IsBool = CbFieldTypeOps::IsBool(Accessor.GetType()); + Error = IsBool ? CbFieldError::None : CbFieldError::TypeError; + return (uint8_t(IsBool) & Accessor.AsBool()) | ((!IsBool) & bDefault); } IoHash CbFieldView::AsObjectAttachment(const IoHash& Default) { - if (CbFieldTypeOps::IsObjectAttachment(Type)) + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsObjectAttachment(Accessor.GetType())) { Error = CbFieldError::None; - return IoHash::MakeFrom(Payload); + return Accessor.AsObjectAttachment(); } else { @@ -312,10 +286,10 @@ CbFieldView::AsObjectAttachment(const IoHash& Default) IoHash CbFieldView::AsBinaryAttachment(const IoHash& Default) { - if (CbFieldTypeOps::IsBinaryAttachment(Type)) + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsBinaryAttachment(Accessor.GetType())) { Error = CbFieldError::None; - return IoHash::MakeFrom(Payload); + return Accessor.AsBinaryAttachment(); } else { @@ -327,10 +301,10 @@ CbFieldView::AsBinaryAttachment(const IoHash& Default) IoHash CbFieldView::AsAttachment(const IoHash& Default) { - if (CbFieldTypeOps::IsAttachment(Type)) + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsAttachment(Accessor.GetType())) { Error = CbFieldError::None; - return IoHash::MakeFrom(Payload); + return Accessor.AsAttachment(); } else { @@ -342,10 +316,10 @@ CbFieldView::AsAttachment(const IoHash& Default) IoHash CbFieldView::AsHash(const IoHash& Default) { - if (CbFieldTypeOps::IsHash(Type)) + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsHash(Accessor.GetType())) { Error = CbFieldError::None; - return IoHash::MakeFrom(Payload); + return Accessor.AsHash(); } else { @@ -363,16 +337,10 @@ CbFieldView::AsUuid() Guid CbFieldView::AsUuid(const Guid& Default) { - if (CbFieldTypeOps::IsUuid(Type)) + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsUuid(Accessor.GetType())) { Error = CbFieldError::None; - Guid Value; - memcpy(&Value, Payload, sizeof(Guid)); - Value.A = FromNetworkOrder(Value.A); - Value.B = FromNetworkOrder(Value.B); - Value.C = FromNetworkOrder(Value.C); - Value.D = FromNetworkOrder(Value.D); - return Value; + return Accessor.AsUuid(); } else { @@ -390,12 +358,40 @@ CbFieldView::AsObjectId() Oid CbFieldView::AsObjectId(const Oid& Default) { - if (CbFieldTypeOps::IsObjectId(Type)) + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsObjectId(Accessor.GetType())) + { + Error = CbFieldError::None; + return Accessor.AsObjectId(); + } + else + { + Error = CbFieldError::TypeError; + return Default; + } +} + +CbCustomById +CbFieldView::AsCustomById(CbCustomById Default) +{ + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsCustomById(Accessor.GetType())) + { + Error = CbFieldError::None; + return Accessor.AsCustomById(); + } + else + { + Error = CbFieldError::TypeError; + return Default; + } +} + +CbCustomByName +CbFieldView::AsCustomByName(CbCustomByName Default) +{ + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsCustomByName(Accessor.GetType())) { Error = CbFieldError::None; - Oid Value; - memcpy(&Value, Payload, sizeof(Oid)); - return Value; + return Accessor.AsCustomByName(); } else { @@ -407,10 +403,10 @@ CbFieldView::AsObjectId(const Oid& Default) int64_t CbFieldView::AsDateTimeTicks(const int64_t Default) { - if (CbFieldTypeOps::IsDateTime(Type)) + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsDateTime(Accessor.GetType())) { Error = CbFieldError::None; - return FromNetworkOrder(CompactBinaryPrivate::ReadUnaligned<int64_t>(Payload)); + return Accessor.AsDateTimeTicks(); } else { @@ -434,10 +430,10 @@ CbFieldView::AsDateTime(DateTime Default) int64_t CbFieldView::AsTimeSpanTicks(const int64_t Default) { - if (CbFieldTypeOps::IsTimeSpan(Type)) + if (CbValue Accessor = GetValue(); CbFieldTypeOps::IsTimeSpan(Accessor.GetType())) { Error = CbFieldError::None; - return FromNetworkOrder(CompactBinaryPrivate::ReadUnaligned<int64_t>(Payload)); + return Accessor.AsTimeSpanTicks(); } else { diff --git a/zencore/include/zencore/compactbinary.h b/zencore/include/zencore/compactbinary.h index 4fce129ea..60e9ec7aa 100644 --- a/zencore/include/zencore/compactbinary.h +++ b/zencore/include/zencore/compactbinary.h @@ -30,6 +30,7 @@ class CbArrayView; class BinaryReader; class BinaryWriter; class CompressedBuffer; +class CbValue; class DateTime { @@ -318,6 +319,9 @@ public: static constexpr inline bool IsUuid(CbFieldType Type) { return GetType(Type) == CbFieldType::Uuid; } static constexpr inline bool IsObjectId(CbFieldType Type) { return GetType(Type) == CbFieldType::ObjectId; } + static constexpr inline bool IsCustomById(CbFieldType Type) { return GetType(Type) == CbFieldType::CustomById; } + static constexpr inline bool IsCustomByName(CbFieldType Type) { return GetType(Type) == CbFieldType::CustomByName; } + static constexpr inline bool IsDateTime(CbFieldType Type) { return GetType(Type) == CbFieldType::DateTime; } static constexpr inline bool IsTimeSpan(CbFieldType Type) { return GetType(Type) == CbFieldType::TimeSpan; } @@ -365,6 +369,46 @@ public: virtual void VisitTimeSpan(TimeSpan Value) = 0; }; +/** A custom compact binary field type with an integer identifier. */ +struct CbCustomById +{ + /** An identifier for the sub-type of the field. */ + uint64_t Id = 0; + /** A view of the value. Lifetime is tied to the field that the value is associated with. */ + MemoryView Data; +}; + +/** A custom compact binary field type with a string identifier. */ +struct CbCustomByName +{ + /** An identifier for the sub-type of the field. Lifetime is tied to the field that the name is associated with. */ + std::u8string_view Name; + /** A view of the value. Lifetime is tied to the field that the value is associated with. */ + MemoryView Data; +}; + +namespace CompactBinaryPrivate { + /** Parameters for converting to an integer. */ + struct IntegerParams + { + /** Whether the output type has a sign bit. */ + uint32_t IsSigned : 1; + /** Bits of magnitude. (7 for int8) */ + uint32_t MagnitudeBits : 31; + }; + + /** Make integer params for the given integer type. */ + template<typename IntType> + static constexpr inline IntegerParams MakeIntegerParams() + { + IntegerParams Params; + Params.IsSigned = IntType(-1) < IntType(0); + Params.MagnitudeBits = 8 * sizeof(IntType) - Params.IsSigned; + return Params; + } + +} // namespace CompactBinaryPrivate + /** * An atom of data in the compact binary format. * @@ -393,13 +437,20 @@ public: ZENCORE_API CbFieldView(const void* DataPointer, CbFieldType FieldType = CbFieldType::HasFieldType); + /** Construct a field from a value, without access to the name. */ + inline explicit CbFieldView(const CbValue& Value); + /** Returns the name of the field if it has a name, otherwise an empty view. */ constexpr inline std::string_view GetName() const { return std::string_view(static_cast<const char*>(Payload) - NameLen, NameLen); } + /** Returns the value for unchecked access. Prefer the typed accessors below. */ + inline CbValue GetValue() const; + ZENCORE_API MemoryView AsBinaryView(MemoryView Default = MemoryView()); ZENCORE_API CbObjectView AsObjectView(); ZENCORE_API CbArrayView AsArrayView(); ZENCORE_API std::string_view AsString(std::string_view Default = std::string_view()); + ZENCORE_API std::u8string_view AsU8String(std::u8string_view Default = std::u8string_view()); ZENCORE_API void IterateAttachments(std::function<void(CbFieldView)> Visitor) const; @@ -448,6 +499,11 @@ public: /** Access the field as a OID. Returns the provided default on error. */ ZENCORE_API Oid AsObjectId(const Oid& Default); + /** Access the field as a custom sub-type with an integer identifier. Returns the provided default on error. */ + ZENCORE_API CbCustomById AsCustomById(CbCustomById Default); + /** Access the field as a custom sub-type with a string identifier. Returns the provided default on error. */ + ZENCORE_API CbCustomByName AsCustomByName(CbCustomByName Default); + /** Access the field as a date/time tick count. Returns the provided default on error. */ ZENCORE_API int64_t AsDateTimeTicks(int64_t Default = 0); @@ -590,25 +646,6 @@ protected: } private: - /** Parameters for converting to an integer. */ - struct IntegerParams - { - /** Whether the output type has a sign bit. */ - uint32_t IsSigned : 1; - /** Bits of magnitude. (7 for int8) */ - uint32_t MagnitudeBits : 31; - }; - - /** Make integer params for the given integer type. */ - template<typename IntType> - static constexpr inline IntegerParams MakeIntegerParams() - { - IntegerParams Params; - Params.IsSigned = IntType(-1) < IntType(0); - Params.MagnitudeBits = 8 * sizeof(IntType) - Params.IsSigned; - return Params; - } - /** * Access the field as the given integer type. * @@ -617,11 +654,12 @@ private: template<typename IntType> inline IntType AsInteger(IntType Default) { - return IntType(AsInteger(uint64_t(Default), MakeIntegerParams<IntType>())); + return IntType(AsInteger(uint64_t(Default), CompactBinaryPrivate::MakeIntegerParams<IntType>())); } - ZENCORE_API uint64_t AsInteger(uint64_t Default, IntegerParams Params); + ZENCORE_API uint64_t AsInteger(uint64_t Default, CompactBinaryPrivate::IntegerParams Params); +private: /** The field type, with the transient HasFieldType flag if the field contains its type. */ CbFieldType Type = CbFieldType::None; /** The error (if any) that occurred on the last field access. */ diff --git a/zencore/include/zencore/compactbinaryvalue.h b/zencore/include/zencore/compactbinaryvalue.h new file mode 100644 index 000000000..5795ef957 --- /dev/null +++ b/zencore/include/zencore/compactbinaryvalue.h @@ -0,0 +1,290 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include <zencore/compactbinary.h> +#include <zencore/endian.h> +#include <zencore/iobuffer.h> +#include <zencore/iohash.h> +#include <zencore/memory.h> + +namespace zen { + +namespace CompactBinaryPrivate { + + template<typename T> + static constexpr inline T ReadUnaligned(const void* const Memory) + { +#if PLATFORM_SUPPORTS_UNALIGNED_LOADS + return *static_cast<const T*>(Memory); +#else + T Value; + memcpy(&Value, Memory, sizeof(Value)); + return Value; +#endif + } +} // namespace CompactBinaryPrivate +/** + * A type that provides unchecked access to compact binary values. + * + * The main purpose of the type is to efficiently switch on field type. For every other use case, + * prefer to use the field, array, and object types directly. The accessors here do not check the + * type before reading the value, which means they can read out of bounds even on a valid compact + * binary value if the wrong accessor is used. + */ +class CbValue +{ +public: + CbValue(CbFieldType Type, const void* Value); + + CbObjectView AsObjectView() const; + CbArrayView AsArrayView() const; + + MemoryView AsBinary() const; + + /** Access as a string. Checks for range errors and uses the default if OutError is not null. */ + std::string_view AsString(CbFieldError* OutError = nullptr, std::string_view Default = std::string_view()) const; + + /** Access as a string as UTF8. Checks for range errors and uses the default if OutError is not null. */ + std::u8string_view AsU8String(CbFieldError* OutError = nullptr, std::u8string_view Default = std::u8string_view()) const; + + /** + * Access as an integer, with both positive and negative values returned as unsigned. + * + * Checks for range errors and uses the default if OutError is not null. + */ + uint64_t AsInteger(CompactBinaryPrivate::IntegerParams Params, CbFieldError* OutError = nullptr, uint64_t Default = 0) const; + + uint64_t AsIntegerPositive() const; + int64_t AsIntegerNegative() const; + + float AsFloat32() const; + double AsFloat64() const; + + bool AsBool() const; + + inline IoHash AsObjectAttachment() const { return AsHash(); } + inline IoHash AsBinaryAttachment() const { return AsHash(); } + inline IoHash AsAttachment() const { return AsHash(); } + + IoHash AsHash() const; + Guid AsUuid() const; + + int64_t AsDateTimeTicks() const; + int64_t AsTimeSpanTicks() const; + + Oid AsObjectId() const; + + CbCustomById AsCustomById() const; + CbCustomByName AsCustomByName() const; + + inline CbFieldType GetType() const { return Type; } + inline const void* GetData() const { return Data; } + +private: + const void* Data; + CbFieldType Type; +}; + +inline CbFieldView::CbFieldView(const CbValue& InValue) : Type(InValue.GetType()), Payload(InValue.GetData()) +{ +} + +inline CbValue +CbFieldView::GetValue() const +{ + return CbValue(CbFieldTypeOps::GetType(Type), Payload); +} + +inline CbValue::CbValue(CbFieldType InType, const void* InValue) : Data(InValue), Type(InType) +{ +} + +inline CbObjectView +CbValue::AsObjectView() const +{ + return CbObjectView(*this); +} + +inline CbArrayView +CbValue::AsArrayView() const +{ + return CbArrayView(*this); +} + +inline MemoryView +CbValue::AsBinary() const +{ + const uint8_t* const Bytes = static_cast<const uint8_t*>(Data); + uint32_t ValueSizeByteCount; + const uint64_t ValueSize = ReadVarUInt(Bytes, ValueSizeByteCount); + return MakeMemoryView(Bytes + ValueSizeByteCount, ValueSize); +} + +inline std::string_view +CbValue::AsString(CbFieldError* OutError, std::string_view Default) const +{ + const char* const Chars = static_cast<const char*>(Data); + uint32_t ValueSizeByteCount; + const uint64_t ValueSize = ReadVarUInt(Chars, ValueSizeByteCount); + + if (OutError) + { + if (ValueSize >= (uint64_t(1) << 31)) + { + *OutError = CbFieldError::RangeError; + return Default; + } + *OutError = CbFieldError::None; + } + + return std::string_view(Chars + ValueSizeByteCount, int32_t(ValueSize)); +} + +inline std::u8string_view +CbValue::AsU8String(CbFieldError* OutError, std::u8string_view Default) const +{ + const char8_t* const Chars = static_cast<const char8_t*>(Data); + uint32_t ValueSizeByteCount; + const uint64_t ValueSize = ReadVarUInt(Chars, ValueSizeByteCount); + + if (OutError) + { + if (ValueSize >= (uint64_t(1) << 31)) + { + *OutError = CbFieldError::RangeError; + return Default; + } + *OutError = CbFieldError::None; + } + + return std::u8string_view(Chars + ValueSizeByteCount, int32_t(ValueSize)); +} + +inline uint64_t +CbValue::AsInteger(CompactBinaryPrivate::IntegerParams Params, CbFieldError* OutError, uint64_t Default) const +{ + // A shift of a 64-bit value by 64 is undefined so shift by one less because magnitude is never zero. + const uint64_t OutOfRangeMask = uint64_t(-2) << (Params.MagnitudeBits - 1); + const uint64_t IsNegative = uint8_t(Type) & 1; + + uint32_t MagnitudeByteCount; + const uint64_t Magnitude = ReadVarUInt(Data, MagnitudeByteCount); + const uint64_t Value = Magnitude ^ -int64_t(IsNegative); + + if (OutError) + { + const uint64_t IsInRange = (!(Magnitude & OutOfRangeMask)) & ((!IsNegative) | Params.IsSigned); + *OutError = IsInRange ? CbFieldError::None : CbFieldError::RangeError; + + const uint64_t UseValueMask = -int64_t(IsInRange); + return (Value & UseValueMask) | (Default & ~UseValueMask); + } + + return Value; +} + +inline uint64_t +CbValue::AsIntegerPositive() const +{ + uint32_t MagnitudeByteCount; + return ReadVarUInt(Data, MagnitudeByteCount); +} + +inline int64_t +CbValue::AsIntegerNegative() const +{ + uint32_t MagnitudeByteCount; + return int64_t(ReadVarUInt(Data, MagnitudeByteCount)) ^ -int64_t(1); +} + +inline float +CbValue::AsFloat32() const +{ + const uint32_t Value = FromNetworkOrder(CompactBinaryPrivate::ReadUnaligned<uint32_t>(Data)); + return reinterpret_cast<const float&>(Value); +} + +inline double +CbValue::AsFloat64() const +{ + const uint64_t Value = FromNetworkOrder(CompactBinaryPrivate::ReadUnaligned<uint64_t>(Data)); + return reinterpret_cast<const double&>(Value); +} + +inline bool +CbValue::AsBool() const +{ + return uint8_t(Type) & 1; +} + +inline IoHash +CbValue::AsHash() const +{ + return IoHash::MakeFrom(Data); +} + +inline Guid +CbValue::AsUuid() const +{ + Guid Value; + memcpy(&Value, Data, sizeof(Guid)); + Value.A = FromNetworkOrder(Value.A); + Value.B = FromNetworkOrder(Value.B); + Value.C = FromNetworkOrder(Value.C); + Value.D = FromNetworkOrder(Value.D); + return Value; +} + +inline int64_t +CbValue::AsDateTimeTicks() const +{ + return FromNetworkOrder(CompactBinaryPrivate::ReadUnaligned<int64_t>(Data)); +} + +inline int64_t +CbValue::AsTimeSpanTicks() const +{ + return FromNetworkOrder(CompactBinaryPrivate::ReadUnaligned<int64_t>(Data)); +} + +inline Oid +CbValue::AsObjectId() const +{ + return Oid::FromMemory(Data); +} + +inline CbCustomById +CbValue::AsCustomById() const +{ + const uint8_t* Bytes = static_cast<const uint8_t*>(Data); + uint32_t DataSizeByteCount; + const uint64_t DataSize = ReadVarUInt(Bytes, DataSizeByteCount); + Bytes += DataSizeByteCount; + + CbCustomById Value; + uint32_t TypeIdByteCount; + Value.Id = ReadVarUInt(Bytes, TypeIdByteCount); + Value.Data = MakeMemoryView(Bytes + TypeIdByteCount, DataSize - TypeIdByteCount); + return Value; +} + +inline CbCustomByName +CbValue::AsCustomByName() const +{ + const uint8_t* Bytes = static_cast<const uint8_t*>(Data); + uint32_t DataSizeByteCount; + const uint64_t DataSize = ReadVarUInt(Bytes, DataSizeByteCount); + Bytes += DataSizeByteCount; + + uint32_t TypeNameLenByteCount; + const uint64_t TypeNameLen = ReadVarUInt(Bytes, TypeNameLenByteCount); + Bytes += TypeNameLenByteCount; + + CbCustomByName Value; + Value.Name = std::u8string_view(reinterpret_cast<const char8_t*>(Bytes), static_cast<std::u8string_view::size_type>(TypeNameLen)); + Value.Data = MakeMemoryView(Bytes + TypeNameLen, DataSize - TypeNameLen - TypeNameLenByteCount); + return Value; +} + +} // namespace zen diff --git a/zencore/include/zencore/memory.h b/zencore/include/zencore/memory.h index 3d4db1081..aba391c85 100644 --- a/zencore/include/zencore/memory.h +++ b/zencore/include/zencore/memory.h @@ -354,6 +354,12 @@ MakeMemoryView(const void* Data, const void* DataEnd) return MemoryView(Data, DataEnd); } +[[nodiscard]] inline MemoryView +MakeMemoryView(const void* Data, uint64_t Size) +{ + return MemoryView(Data, reinterpret_cast<const uint8_t*>(Data) + Size); +} + /** * Make a non-owning mutable view of the memory of the initializer list. * |