Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
CompactBinary.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Containers/StringFwd.h"
6#include "Containers/StringView.h"
7#include "CoreTypes.h"
8#include "HAL/UnrealMemory.h"
9#include "IO/IoHash.h"
10#include "Memory/CompositeBuffer.h"
11#include "Memory/MemoryFwd.h"
12#include "Memory/MemoryView.h"
13#include "Memory/SharedBuffer.h"
14#include "Misc/AssertionMacros.h"
15#include "Misc/EnumClassFlags.h"
16#include "String/BytesToHex.h"
17#include "Templates/Function.h"
18#include "Templates/IsTriviallyDestructible.h"
19#include "Templates/RemoveReference.h"
20#include "Templates/UnrealTemplate.h"
21
22template <typename CharType> class TStringBuilderBase;
23
24/**
25 * This file declares a compact binary data format that is compatible with JSON and only slightly
26 * more expressive. The format is designed to achieve fairly small encoded sizes while also being
27 * efficient to read both sequentially and through random access. An atom of data in this compact
28 * binary format is called a field, which can be: an object, an array, a byte string, a character
29 * string, or one of several scalar types including integer, floating point, boolean, null, hash,
30 * uuid, date/time, time span, object identifier, or attachment reference.
31 *
32 * An object is a collection of name-field pairs, and an array is a collection of fields. Encoded
33 * objects and arrays are both written such that they may be interpreted as a field that can then
34 * be cast to an object or array. This attribute means that a blob containing compact binary data
35 * is always safe to interpret as a field, which allows for easy validation as described later.
36 *
37 * A field can be constructed as a view of the underlying memory with FCbFieldView, or a FCbField
38 * can used when ownership of the underlying memory is required. An object provides this behavior
39 * with FCbObjectView or FCbObject, and an array uses FCbArrayView or FCbArray.
40 *
41 * It is optimal use the view types when possible, and reference types only when they are needed,
42 * to avoid the overhead of the atomic reference counting of the shared buffer.
43 *
44 * A suite of validation functionality is provided by ValidateCompactBinary and its siblings. The
45 * Default mode provides a guarantee that the data can be consumed without a crash. Documentation
46 * of the other modes is available on ECbValidateMode.
47 *
48 * Example:
49 *
50 * void BeginBuild(FCbObject Params)
51 * {
52 * if (FSharedBuffer Data = Storage().Load(Params["Data"].AsBinaryAttachment()))
53 * {
54 * SetData(Data);
55 * }
56 *
57 * if (Params["Resize"].AsBool())
58 * {
59 * FCbFieldView MaxWidthField = Params["MaxWidth"]
60 * FCbFieldView MaxHeightField = Params["MaxHeight"];
61 * if (MaxWidthField && MaxHeightField)
62 * {
63 * Resize(MaxWidthField.AsInt32(), MaxHeightField.AsInt32());
64 * }
65 * }
66 *
67 * for (FCbFieldView Format : Params.FindView(ANSITEXTVIEW("Formats")))
68 * {
69 * BeginCompress(FName(Format.AsString()));
70 * }
71 * }
72 */
73
74class FArchive;
75class FCbArrayView;
76class FCbField;
78class FCbFieldView;
80class FCbObjectId;
81class FCbObjectView;
82class FCbValue;
83class FIoHashBuilder;
84struct FDateTime;
85struct FGuid;
86struct FTimespan;
87template <typename FuncType> class TFunctionRef;
88
89/** A reference to a function that is used to allocate buffers for compact binary data. */
90using FCbBufferAllocator = TFunctionRef<FUniqueBuffer (uint64 Size)>;
91
92///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
93
94/**
95 * Field types and flags for FCbField[View].
96 *
97 * DO NOT CHANGE THE VALUE OF ANY MEMBERS OF THIS ENUM!
98 * BACKWARD COMPATIBILITY REQUIRES THAT THESE VALUES BE FIXED!
99 * SERIALIZATION USES HARD-CODED CONSTANTS BASED ON THESE VALUES!
100 */
101enum class ECbFieldType : uint8
102{
103 /** A field type that does not occur in a valid object. */
104 None = 0x00,
105
106 /** Null. Value is empty. */
107 Null = 0x01,
108
109 /**
110 * Object is an array of fields with unique non-empty names.
111 *
112 * Value is a VarUInt byte count for the encoded fields, followed by the fields.
113 */
114 Object = 0x02,
115 /**
116 * UniformObject is an array of fields with the same field types and unique non-empty names.
117 *
118 * Value is a VarUInt byte count for the encoded fields, followed by the field type, followed
119 * by the fields encoded with no type.
120 */
121 UniformObject = 0x03,
122
123 /**
124 * Array is an array of fields with no name that may be of different types.
125 *
126 * Value is a VarUInt byte count, followed by a VarUInt field count, followed by the fields.
127 */
128 Array = 0x04,
129 /**
130 * UniformArray is an array of fields with no name and with the same field type.
131 *
132 * Value is a VarUInt byte count, followed by a VarUInt field count, followed by the field type,
133 * followed by the fields encoded with no type.
134 */
135 UniformArray = 0x05,
136
137 /** Binary. Value is a VarUInt byte count followed by the data. */
138 Binary = 0x06,
139
140 /** String in UTF-8. Value is a VarUInt byte count then an unterminated UTF-8 string. */
141 String = 0x07,
142
143 /**
144 * Non-negative integer with the range of a 64-bit unsigned integer.
145 *
146 * Value is the value encoded as a VarUInt.
147 */
148 IntegerPositive = 0x08,
149 /**
150 * Negative integer with the range of a 64-bit signed integer.
151 *
152 * Value is the ones' complement of the value encoded as a VarUInt.
153 */
154 IntegerNegative = 0x09,
155
156 /** Single precision float. Value is one big endian IEEE 754 binary32 float. */
157 Float32 = 0x0a,
158 /** Double precision float. Value is one big endian IEEE 754 binary64 float. */
159 Float64 = 0x0b,
160
161 /** Boolean false value. Value is empty. */
162 BoolFalse = 0x0c,
163 /** Boolean true value. Value is empty. */
164 BoolTrue = 0x0d,
165
166 /**
167 * ObjectAttachment is a reference to a compact binary object attachment stored externally.
168 *
169 * Value is a 160-bit hash digest of the referenced compact binary object data.
170 */
171 ObjectAttachment = 0x0e,
172 /**
173 * BinaryAttachment is a reference to a binary attachment stored externally.
174 *
175 * Value is a 160-bit hash digest of the referenced binary data.
176 */
177 BinaryAttachment = 0x0f,
178
179 /** Hash. Value is a 160-bit hash digest. */
180 Hash = 0x10,
181 /** UUID/GUID. Value is a 128-bit UUID as defined by RFC 4122. */
182 Uuid = 0x11,
183
184 /**
185 * Date and time between 0001-01-01 00:00:00.0000000 and 9999-12-31 23:59:59.9999999.
186 *
187 * Value is a big endian int64 count of 100ns ticks since 0001-01-01 00:00:00.0000000.
188 */
189 DateTime = 0x12,
190 /**
191 * Difference between two date/time values.
192 *
193 * Value is a big endian int64 count of 100ns ticks in the span, and may be negative.
194 */
195 TimeSpan = 0x13,
196
197 /**
198 * ObjectId is an opaque object identifier. See FCbObjectId.
199 *
200 * Value is a 12-byte object identifier.
201 */
202 ObjectId = 0x14,
203
204 /**
205 * CustomById identifies the sub-type of its value by an integer identifier.
206 *
207 * Value is a VarUInt byte count, followed by a VarUInt encoding of the sub-type identifier,
208 * followed by the value of the sub-type.
209 */
210 CustomById = 0x1e,
211 /**
212 * CustomByType identifies the sub-type of its value by a string identifier.
213 *
214 * Value is a VarUInt byte count, followed by a String encoding of the sub-type identifier,
215 * followed by the value of the sub-type.
216 */
217 CustomByName = 0x1f,
218
219 /** Reserved for future use as a flag. Do not add types in this range. */
220 Reserved = 0x20,
221
222 /**
223 * A transient flag which indicates that the object or array containing this field has stored
224 * the field type before the value and name. Non-uniform objects and fields will set this.
225 *
226 * Note: Since the flag must never be serialized, this bit may be re-purposed in the future.
227 */
228 HasFieldType = 0x40,
229
230 /** A persisted flag which indicates that the field has a name stored before the value. */
231 HasFieldName = 0x80,
232};
233
235
236///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
237
238/** Functions that operate on ECbFieldType. */
240{
241 static constexpr ECbFieldType SerializedTypeMask = ECbFieldType(0b1001'1111);
242 static constexpr ECbFieldType TypeMask = ECbFieldType(0b0001'1111);
243
244 static constexpr ECbFieldType ObjectMask = ECbFieldType(0b0001'1110);
245 static constexpr ECbFieldType ObjectBase = ECbFieldType(0b0000'0010);
246
247 static constexpr ECbFieldType ArrayMask = ECbFieldType(0b0001'1110);
248 static constexpr ECbFieldType ArrayBase = ECbFieldType(0b0000'0100);
249
250 static constexpr ECbFieldType IntegerMask = ECbFieldType(0b0001'1110);
251 static constexpr ECbFieldType IntegerBase = ECbFieldType(0b0000'1000);
252
253 static constexpr ECbFieldType FloatMask = ECbFieldType(0b0001'1100);
254 static constexpr ECbFieldType FloatBase = ECbFieldType(0b0000'1000);
255
256 static constexpr ECbFieldType BoolMask = ECbFieldType(0b0001'1110);
257 static constexpr ECbFieldType BoolBase = ECbFieldType(0b0000'1100);
258
259 static constexpr ECbFieldType AttachmentMask = ECbFieldType(0b0001'1110);
260 static constexpr ECbFieldType AttachmentBase = ECbFieldType(0b0000'1110);
261
263
264public:
265 /** The type with flags removed. */
266 static constexpr inline ECbFieldType GetType(ECbFieldType Type) { return Type & TypeMask; }
267 /** The type with transient flags removed. */
268 static constexpr inline ECbFieldType GetSerializedType(ECbFieldType Type) { return Type & SerializedTypeMask; }
269
270 static constexpr inline bool HasFieldType(ECbFieldType Type) { return EnumHasAnyFlags(Type, ECbFieldType::HasFieldType); }
271 static constexpr inline bool HasFieldName(ECbFieldType Type) { return EnumHasAnyFlags(Type, ECbFieldType::HasFieldName); }
272
273 static constexpr inline bool IsNone(ECbFieldType Type) { return GetType(Type) == ECbFieldType::None; }
274 static constexpr inline bool IsNull(ECbFieldType Type) { return GetType(Type) == ECbFieldType::Null; }
275
276 static constexpr inline bool IsObject(ECbFieldType Type) { return (Type & ObjectMask) == ObjectBase; }
277 static constexpr inline bool IsArray(ECbFieldType Type) { return (Type & ArrayMask) == ArrayBase; }
278
279 static constexpr inline bool IsBinary(ECbFieldType Type) { return GetType(Type) == ECbFieldType::Binary; }
280 static constexpr inline bool IsString(ECbFieldType Type) { return GetType(Type) == ECbFieldType::String; }
281
282 static constexpr inline bool IsInteger(ECbFieldType Type) { return (Type & IntegerMask) == IntegerBase; }
283 /** Whether the field is a float, or integer due to implicit conversion. */
284 static constexpr inline bool IsFloat(ECbFieldType Type) { return (Type & FloatMask) == FloatBase; }
285 static constexpr inline bool IsBool(ECbFieldType Type) { return (Type & BoolMask) == BoolBase; }
286
287 static constexpr inline bool IsObjectAttachment(ECbFieldType Type) { return GetType(Type) == ECbFieldType::ObjectAttachment; }
288 static constexpr inline bool IsBinaryAttachment(ECbFieldType Type) { return GetType(Type) == ECbFieldType::BinaryAttachment; }
289 static constexpr inline bool IsAttachment(ECbFieldType Type) { return (Type & AttachmentMask) == AttachmentBase; }
290
291 static constexpr inline bool IsHash(ECbFieldType Type) { return GetType(Type) == ECbFieldType::Hash || IsAttachment(Type); }
292 static constexpr inline bool IsUuid(ECbFieldType Type) { return GetType(Type) == ECbFieldType::Uuid; }
293
294 static constexpr inline bool IsDateTime(ECbFieldType Type) { return GetType(Type) == ECbFieldType::DateTime; }
295 static constexpr inline bool IsTimeSpan(ECbFieldType Type) { return GetType(Type) == ECbFieldType::TimeSpan; }
296
297 static constexpr inline bool IsObjectId(ECbFieldType Type) { return GetType(Type) == ECbFieldType::ObjectId; }
298
299 static constexpr inline bool IsCustomById(ECbFieldType Type) { return GetType(Type) == ECbFieldType::CustomById; }
300 static constexpr inline bool IsCustomByName(ECbFieldType Type) { return GetType(Type) == ECbFieldType::CustomByName; }
301
302 static constexpr inline bool HasFields(ECbFieldType Type)
303 {
305 }
306
307 static constexpr inline bool HasUniformFields(ECbFieldType Type)
308 {
310 }
311
312 /** Whether the type is or may contain fields of any attachment type. */
313 static constexpr inline bool MayContainAttachments(ECbFieldType Type)
314 {
315 // The use of !! will suppress V792 from static analysis. Using //-V792 did not work.
316 return !!IsObject(Type) | !!IsArray(Type) | !!IsAttachment(Type);
317 }
318};
319
320///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
321
322/** A reference to a function that is used to visit fields. */
323using FCbFieldVisitor = TFunctionRef<void (FCbFieldView)>;
324
325///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
326
327/** Iterator that can be used as a sentinel for the end of a range. */
329{
330};
331
332/**
333 * Iterator for FCbField[View] that can operate on any contiguous range of fields.
334 *
335 * The iterator *is* the current field that the iterator points to and exposes the full interface
336 * of FCbField[View]. An iterator that is at the end is equivalent to a field with no value.
337 *
338 * The iterator represents a range of fields from the current field to the last field.
339 */
340template <typename FieldType>
341class TCbFieldIterator : public FieldType
342{
343public:
344 /** Construct an empty field range. */
345 constexpr TCbFieldIterator() = default;
346
348
350 {
351 TCbFieldIterator It(*this);
352 ++*this;
353 return It;
354 }
355
356 constexpr inline FieldType& operator*() { return *this; }
357 constexpr inline FieldType* operator->() { return this; }
358
359 /** Reset this to an empty field range. */
360 inline void Reset() { *this = TCbFieldIterator(); }
361
362 /** Returns the size of the fields in the range in bytes. */
363 uint64 GetRangeSize() const;
364
365 /** Calculate the hash of every field in the range. */
367 /** Append the hash of every field in the range. */
368 void AppendRangeHash(FIoHashBuilder& Builder) const;
369
370 using FieldType::Equals;
371
372 template <typename OtherFieldType>
373 constexpr inline bool Equals(const TCbFieldIterator<OtherFieldType>& Other) const
374 {
375 return FieldType::GetValueData() == Other.OtherFieldType::GetValueData() && FieldsEnd == Other.FieldsEnd;
376 }
377
378 template <typename OtherFieldType>
379 constexpr inline bool operator==(const TCbFieldIterator<OtherFieldType>& Other) const
380 {
381 return Equals(Other);
382 }
383
384 template <typename OtherFieldType>
385 constexpr inline bool operator!=(const TCbFieldIterator<OtherFieldType>& Other) const
386 {
387 return !Equals(Other);
388 }
389
390 constexpr inline bool operator==(const FCbIteratorSentinel&) const { return !FieldType::HasValue(); }
391 constexpr inline bool operator!=(const FCbIteratorSentinel&) const { return FieldType::HasValue(); }
392
393 /** Copy the field range into a buffer of exactly GetRangeSize() bytes. */
394 void CopyRangeTo(FMutableMemoryView Buffer) const;
395
396 /** Copy the field range into an archive, as if calling CopyTo on every field. */
397 void CopyRangeTo(FArchive& Ar) const;
398
399 /** Invoke the visitor for every attachment in the field range. */
400 void IterateRangeAttachments(FCbFieldVisitor Visitor) const;
401
402 /**
403 * Try to get a view of every field in the range as they would be serialized.
404 *
405 * A view is available if each field contains its type. Access the equivalent for other field
406 * ranges through FCbFieldIterator::CloneRange or CopyRangeTo.
407 */
408 inline bool TryGetRangeView(FMemoryView& OutView) const
409 {
412 {
414 return true;
415 }
416 return false;
417 }
418
419 /** DO NOT USE DIRECTLY. These functions enable range-based for loop support. */
420 constexpr inline TCbFieldIterator begin() const { return *this; }
421 constexpr inline FCbIteratorSentinel end() const { return FCbIteratorSentinel(); }
422
423protected:
424 /** Construct a field range that contains exactly one field. */
425 constexpr inline explicit TCbFieldIterator(FieldType InField)
426 : FieldType(MoveTemp(InField))
427 , FieldsEnd(FieldType::GetValueEnd())
428 {
429 }
430
431 /**
432 * Construct a field range from the first field and a pointer to the end of the last field.
433 *
434 * @param InField The first field, or the default field if there are no fields.
435 * @param InFieldsEnd A pointer to the end of the value of the last field, or null.
436 */
437 constexpr inline TCbFieldIterator(FieldType&& InField, const void* InFieldsEnd)
438 : FieldType(MoveTemp(InField))
439 , FieldsEnd(InFieldsEnd)
440 {
441 }
442
443 /** Returns the end of the last field, or null for an iterator at the end. */
444 template <typename OtherFieldType>
445 static inline const void* GetFieldsEnd(const TCbFieldIterator<OtherFieldType>& It)
446 {
447 return It.FieldsEnd;
448 }
449
450private:
451 template <typename OtherType>
452 friend class TCbFieldIterator;
453
454 /** Pointer to the first byte past the end of the last field. Set to null at the end. */
455 const void* FieldsEnd = nullptr;
456};
457
458///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
459
460/** Errors that can occur when accessing a field. */
462{
463 /** The field is not in an error state. */
464 None,
465 /** The value type does not match the requested type. */
466 TypeError,
467 /** The value is out of range for the requested type. */
469};
470
471///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
472
473/**
474 * An opaque 12-byte object identifier.
475 *
476 * It has no intrinsic meaning, and can only be properly interpreted in the context of its usage.
477 */
479{
480public:
481 using ByteArray = uint8[12];
482
483 /** Construct an ObjectId with every byte initialized to zero. */
484 FCbObjectId() = default;
485
486 /** Construct an ObjectId from an array of 12 bytes. */
487 inline explicit FCbObjectId(const ByteArray& ObjectId);
488
489 /** Construct an ObjectId from a view of 12 bytes. */
490 explicit FCbObjectId(FMemoryView ObjectId);
491
492 /** Returns a reference to the raw byte array for the ObjectId. */
493 inline const ByteArray& GetBytes() const { return Bytes; }
494 inline operator const ByteArray&() const { return Bytes; }
495
496 /** Returns a view of the raw byte array for the ObjectId. */
497 constexpr inline FMemoryView GetView() const { return MakeMemoryView(Bytes); }
498
500
501 inline bool operator==(const FCbObjectId& B) const
502 {
503 return FMemory::Memcmp(this, &B, sizeof(FCbObjectId)) == 0;
504 }
505
506 inline bool operator!=(const FCbObjectId& B) const
507 {
508 return FMemory::Memcmp(this, &B, sizeof(FCbObjectId)) != 0;
509 }
510
511 inline bool operator<(const FCbObjectId& B) const
512 {
513 return FMemory::Memcmp(this, &B, sizeof(FCbObjectId)) <= 0;
514 }
515
516 friend inline uint32 GetTypeHash(const FCbObjectId& Id)
517 {
518 return *reinterpret_cast<const uint32*>(&Id);
519 }
520
521 /** Convert the ObjectId to a 24-character hex string. */
522 template <typename CharType>
523 friend inline TStringBuilderBase<CharType>& operator<<(TStringBuilderBase<CharType>& Builder, const FCbObjectId& Id)
524 {
526 return Builder;
527 }
528
529private:
530 alignas(uint32) ByteArray Bytes{};
531};
532
533inline FCbObjectId::FCbObjectId(const ByteArray& ObjectId)
534{
535 FMemory::Memcpy(Bytes, ObjectId, sizeof(ByteArray));
536}
537
538///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
539
540/** A custom compact binary field type with an integer identifier. */
542{
543 /** An identifier for the sub-type of the field. */
544 uint64 Id = 0;
545 /** A view of the value. Lifetime is tied to the field that the value is associated with. */
547};
548
549/** A custom compact binary field type with a string identifier. */
551{
552 /** An identifier for the sub-type of the field. Lifetime is tied to the field that the name is associated with. */
553 FUtf8StringView Name;
554 /** A view of the value. Lifetime is tied to the field that the value is associated with. */
556};
557
558///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
559
560namespace UE::CompactBinary::Private
561{
562
563/** Parameters for converting to an integer. */
565{
566 /** Whether the output type has a sign bit. */
567 uint32 IsSigned : 1;
568 /** Bits of magnitude. (7 for int8) */
569 uint32 MagnitudeBits : 31;
570};
571
572/** Make integer params for the given integer type. */
573template <typename IntType>
574static constexpr inline FIntegerParams MakeIntegerParams()
575{
576 FIntegerParams Params;
577 Params.IsSigned = IntType(-1) < IntType(0);
578 Params.MagnitudeBits = 8 * sizeof(IntType) - Params.IsSigned;
579 return Params;
580}
581
582} // UE::CompactBinary::Private
583
584///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
585
586/**
587 * An atom of data in the compact binary format.
588 *
589 * Accessing the value of a field is always a safe operation, even if accessed as the wrong type.
590 * An invalid access will return a default value for the requested type, and set an error code on
591 * the field that can be checked with GetLastError and HasLastError. A valid access will clear an
592 * error from a previous invalid access.
593 *
594 * A field is encoded in one or more bytes, depending on its type and the type of object or array
595 * that contains it. A field of an object or array which is non-uniform encodes its field type in
596 * the first byte, and includes the HasFieldName flag for a field in an object. The field name is
597 * encoded in a variable-length unsigned integer of its size in bytes, for named fields, followed
598 * by that many bytes of the UTF-8 encoding of the name with no null terminator. The remainder of
599 * the field is the value which is described in the field type enum. Every field must be uniquely
600 * addressable when encoded, which means a zero-byte field is not permitted, and only arises in a
601 * uniform array of fields with no value, where the answer is to encode as a non-uniform array.
602 *
603 * This type only provides a view into memory and does not perform any memory management itself.
604 * Use FCbField to hold a reference to the underlying memory when necessary.
605 */
607{
608public:
609 /** Construct a field with no name and no value. */
610 constexpr FCbFieldView() = default;
611
612 /**
613 * Construct a field from a pointer to its data and an optional externally-provided type.
614 *
615 * @param Data Pointer to the start of the field data.
616 * @param Type HasFieldType means that Data contains the type. Otherwise, use the given type.
617 */
618 explicit FCbFieldView(const void* Data, ECbFieldType Type = ECbFieldType::HasFieldType);
619
620 /** Construct a field from a value, without access to the name. */
621 inline explicit FCbFieldView(const FCbValue& Value);
622
623 /** Returns a copy of the field with the name removed. */
624 constexpr inline FCbFieldView RemoveName() const
625 {
626 FCbFieldView Field;
628 Field.Value = Value;
629 return Field;
630 }
631
632 /** Returns the name of the field if it has a name, otherwise an empty view. */
633 constexpr inline FUtf8StringView GetName() const
634 {
635 return FUtf8StringView(static_cast<const UTF8CHAR*>(Value) - NameLen, NameLen);
636 }
637
638 /** Returns the value for unchecked access. Prefer the typed accessors below. */
639 inline FCbValue GetValue() const;
640
641 /** Access the field as an object. Defaults to an empty object on error. */
643
644 /** Access the field as an array. Defaults to an empty array on error. */
646
647 /** Access the field as binary. Returns the provided default on error. */
649
650 /** Access the field as a string. Returns the provided default on error. */
651 FUtf8StringView AsString(FUtf8StringView Default = FUtf8StringView());
652
653 /** Access the field as an int8. Returns the provided default on error. */
654 inline int8 AsInt8(int8 Default = 0) { return AsInteger<int8>(Default); }
655 /** Access the field as an int16. Returns the provided default on error. */
656 inline int16 AsInt16(int16 Default = 0) { return AsInteger<int16>(Default); }
657 /** Access the field as an int32. Returns the provided default on error. */
658 inline int32 AsInt32(int32 Default = 0) { return AsInteger<int32>(Default); }
659 /** Access the field as an int64. Returns the provided default on error. */
660 inline int64 AsInt64(int64 Default = 0) { return AsInteger<int64>(Default); }
661 /** Access the field as a uint8. Returns the provided default on error. */
662 inline uint8 AsUInt8(uint8 Default = 0) { return AsInteger<uint8>(Default); }
663 /** Access the field as a uint16. Returns the provided default on error. */
664 inline uint16 AsUInt16(uint16 Default = 0) { return AsInteger<uint16>(Default); }
665 /** Access the field as a uint32. Returns the provided default on error. */
666 inline uint32 AsUInt32(uint32 Default = 0) { return AsInteger<uint32>(Default); }
667 /** Access the field as a uint64. Returns the provided default on error. */
668 inline uint64 AsUInt64(uint64 Default = 0) { return AsInteger<uint64>(Default); }
669
670 /** Access the field as a float. Returns the provided default on error. */
671 float AsFloat(float Default = 0.0f);
672 /** Access the field as a double. Returns the provided default on error. */
673 double AsDouble(double Default = 0.0);
674
675 /** Access the field as a bool. Returns the provided default on error. */
676 bool AsBool(bool bDefault = false);
677
678 /** Access the field as a hash referencing an object attachment. Returns the provided default on error. */
680 /** Access the field as a hash referencing a binary attachment. Returns the provided default on error. */
682 /** Access the field as a hash referencing an attachment. Returns the provided default on error. */
684
685 /** Access the field as a hash. Returns the provided default on error. */
687
688 /** Access the field as a UUID. Returns a nil UUID on error. */
690 /** Access the field as a UUID. Returns the provided default on error. */
691 FGuid AsUuid(const FGuid& Default);
692
693 /** Access the field as a date/time tick count. Returns the provided default on error. */
694 int64 AsDateTimeTicks(int64 Default = 0);
695
696 /** Access the field as a date/time. Returns a date/time at the epoch on error. */
698 /** Access the field as a date/time. Returns the provided default on error. */
700
701 /** Access the field as a timespan tick count. Returns the provided default on error. */
702 int64 AsTimeSpanTicks(int64 Default = 0);
703
704 /** Access the field as a timespan. Returns an empty timespan on error. */
706 /** Access the field as a timespan. Returns the provided default on error. */
708
709 /** Access the field as an object identifier. Returns the provided default on error. */
711
712 /** Access the field as a custom sub-type with an integer identifier. Returns the provided default on error. */
714 /** Access the field as a custom sub-type with a string identifier. Returns the provided default on error. */
716
717 /** Access the field as a custom sub-type with an integer identifier. Returns the provided default on error. */
719 /** Access the field as a custom sub-type with a string identifier. Returns the provided default on error. */
721
722 /** True if the field has a name. */
723 constexpr inline bool HasName() const { return FCbFieldType::HasFieldName(TypeWithFlags); }
724
725 constexpr inline bool IsNull() const { return FCbFieldType::IsNull(TypeWithFlags); }
726
727 constexpr inline bool IsObject() const { return FCbFieldType::IsObject(TypeWithFlags); }
728 constexpr inline bool IsArray() const { return FCbFieldType::IsArray(TypeWithFlags); }
729
730 constexpr inline bool IsBinary() const { return FCbFieldType::IsBinary(TypeWithFlags); }
731 constexpr inline bool IsString() const { return FCbFieldType::IsString(TypeWithFlags); }
732
733 /** Whether the field is an integer of unspecified range and sign. */
734 constexpr inline bool IsInteger() const { return FCbFieldType::IsInteger(TypeWithFlags); }
735 /** Whether the field is a float, or integer that supports implicit conversion. */
736 constexpr inline bool IsFloat() const { return FCbFieldType::IsFloat(TypeWithFlags); }
737 constexpr inline bool IsBool() const { return FCbFieldType::IsBool(TypeWithFlags); }
738
741 constexpr inline bool IsAttachment() const { return FCbFieldType::IsAttachment(TypeWithFlags); }
742
743 constexpr inline bool IsHash() const { return FCbFieldType::IsHash(TypeWithFlags); }
744 constexpr inline bool IsUuid() const { return FCbFieldType::IsUuid(TypeWithFlags); }
745
746 constexpr inline bool IsDateTime() const { return FCbFieldType::IsDateTime(TypeWithFlags); }
747 constexpr inline bool IsTimeSpan() const { return FCbFieldType::IsTimeSpan(TypeWithFlags); }
748
749 constexpr inline bool IsObjectId() const { return FCbFieldType::IsObjectId(TypeWithFlags); }
750
751 constexpr inline bool IsCustomById() const { return FCbFieldType::IsCustomById(TypeWithFlags); }
752 constexpr inline bool IsCustomByName() const { return FCbFieldType::IsCustomByName(TypeWithFlags); }
753
754 /** Whether the field has a value. */
755 constexpr inline explicit operator bool() const { return HasValue(); }
756
757 /**
758 * Whether the field has a value.
759 *
760 * All fields in a valid object or array have a value. A field with no value is returned when
761 * finding a field by name fails or when accessing an iterator past the end.
762 */
763 constexpr inline bool HasValue() const { return !FCbFieldType::IsNone(TypeWithFlags); };
764
765 /** Whether the last field access encountered an error. */
766 constexpr inline bool HasError() const { return Error != ECbFieldError::None; }
767
768 /** The type of error that occurred on the last field access, or None. */
769 constexpr inline ECbFieldError GetError() const { return Error; }
770
771 /** Returns the size of the field in bytes, including the type and name. */
772 uint64 GetSize() const;
773
774 /** Calculate the hash of the field, including the type and name. */
776 /** Append the hash of the field, including the type and name. */
777 void AppendHash(FIoHashBuilder& Builder) const;
778
779 /**
780 * Whether this field is identical to the other field.
781 *
782 * Performs a deep comparison of any contained arrays or objects and their fields. Comparison
783 * assumes that both fields are valid and are written in the canonical format. Fields must be
784 * written in the same order in arrays and objects, and name comparison is case sensitive. If
785 * these assumptions do not hold, this may return false for equivalent inputs. Validation can
786 * be performed with ValidateCompactBinary, except for field order and field name case.
787 */
788 bool Equals(const FCbFieldView& Other) const;
789
790 /** Copy the field into a buffer of exactly GetSize() bytes, including the type and name. */
791 void CopyTo(FMutableMemoryView Buffer) const;
792
793 /** Copy the field into an archive, including its type and name. */
794 void CopyTo(FArchive& Ar) const;
795
796 /** Invoke the visitor for every attachment in the field. */
797 void IterateAttachments(FCbFieldVisitor Visitor) const;
798
799 /**
800 * Try to get a view of the field as it would be serialized, such as by CopyTo.
801 *
802 * A view is available if the field contains its type. Access the equivalent for other fields
803 * through FCbField::GetBuffer, FCbField::Clone, or CopyTo.
804 */
805 inline bool TryGetView(FMemoryView& OutView) const
806 {
808 {
809 OutView = GetView();
810 return true;
811 }
812 return false;
813 }
814
815 /** Find a field of an object by case-sensitive name comparison, otherwise a field with no value. */
816 FCbFieldView operator[](FUtf8StringView Name) const;
817
818 /** Create an iterator for the fields of an array or object, otherwise an empty iterator. */
820
821 /** DO NOT USE DIRECTLY. These functions enable range-based for loop support. */
823 constexpr inline FCbIteratorSentinel end() const { return FCbIteratorSentinel(); }
824
825protected:
826 /** Returns a view of the field, including the type and name when present. */
828
829 /** Returns a view of the name and value, which excludes the type. */
831
832 /** Returns a view of the value, which excludes the type and name. */
833 inline FMemoryView GetValueView() const { return MakeMemoryView(Value, GetValueSize()); }
834
835 /** Returns the type of the field excluding flags. */
836 constexpr inline ECbFieldType GetType() const { return FCbFieldType::GetType(TypeWithFlags); }
837
838 /** Returns the type of the field including flags. */
839 constexpr inline ECbFieldType GetTypeWithFlags() const { return TypeWithFlags; }
840
841 /** Returns the start of the value. */
842 constexpr inline const void* GetValueData() const { return Value; }
843
844 /** Returns the end of the value. */
845 inline const void* GetValueEnd() const { return static_cast<const uint8*>(Value) + GetValueSize(); }
846
847 /** Returns the size of the value in bytes, which is the field excluding the type and name. */
848 uint64 GetValueSize() const;
849
850 /** Assign a field from a pointer to its data and an optional externally-provided type. */
851 inline void Assign(const void* InData, const ECbFieldType InType)
852 {
853 static_assert(TIsTriviallyDestructible<FCbFieldView>::Value,
854 "This optimization requires FCbFieldView to be trivially destructible!");
855 new(this) FCbFieldView(InData, InType);
856 }
857
858private:
859 /**
860 * Access the field as the given integer type.
861 *
862 * Returns the provided default if the value cannot be represented in the output type.
863 */
864 template <typename IntType>
865 inline IntType AsInteger(IntType Default)
866 {
868 }
869
870 uint64 AsInteger(uint64 Default, UE::CompactBinary::Private::FIntegerParams Params);
871
872private:
873 /** The field type, with the transient HasFieldType flag if the field contains its type. */
875 /** The error (if any) that occurred on the last field access. */
877 /** The number of bytes for the name stored before the value. */
878 uint32 NameLen = 0;
879 /** The value, which also points to the end of the name. */
880 const void* Value = nullptr;
881};
882
883/**
884 * Iterator for FCbFieldView.
885 *
886 * @see TCbFieldIterator
887 */
889{
890public:
891 /** Construct a field range that contains exactly one field. */
892 static inline FCbFieldViewIterator MakeSingle(const FCbFieldView& Field)
893 {
894 return FCbFieldViewIterator(Field);
895 }
896
897 /**
898 * Construct a field range from a buffer containing zero or more valid fields.
899 *
900 * @param View A buffer containing zero or more valid fields.
901 * @param Type HasFieldType means that View contains the type. Otherwise, use the given type.
902 */
904 {
905 return !View.IsEmpty() ? FCbFieldViewIterator(FCbFieldView(View.GetData(), Type), View.GetDataEnd()) : FCbFieldViewIterator();
906 }
907
908 /** Construct an empty field range. */
909 constexpr FCbFieldViewIterator() = default;
910
911 /** Construct an iterator from another iterator. */
912 template <typename OtherFieldType>
913 inline FCbFieldViewIterator(const TCbFieldIterator<OtherFieldType>& It)
915 {
916 }
917
918private:
920};
921
923{
925}
926
927///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
928
929/**
930 * Array of FCbField[View] that have no names.
931 *
932 * Accessing a field of the array requires iteration. Access by index is not provided because the
933 * cost of accessing an item by index scales linearly with the index.
934 *
935 * This type only provides a view into memory and does not perform any memory management itself.
936 * Use FCbArray to hold a reference to the underlying memory when necessary.
937 */
938class FCbArrayView : protected FCbFieldView
939{
940public:
941 /** @see FCbFieldView::FCbFieldView */
942 using FCbFieldView::FCbFieldView;
943
944 /** Construct an array with no fields. */
946
947 /** Returns the number of items in the array. */
948 uint64 Num() const;
949
950 /** Access the array as an array field. */
951 inline FCbFieldView AsFieldView() const { return RemoveName(); }
952
953 /** Construct an array from an array field. No type check is performed! */
954 static inline FCbArrayView FromFieldNoCheck(const FCbFieldView& Field) { return FCbArrayView(Field); }
955
956 /** Whether the array has any fields. */
957 inline explicit operator bool() const { return Num() > 0; }
958
959 /** Returns the size of the array in bytes if serialized by itself with no name. */
960 uint64 GetSize() const;
961
962 /** Calculate the hash of the array if serialized by itself with no name. */
964 /** Append the hash of the array if serialized by itself with no name. */
965 void AppendHash(FIoHashBuilder& Builder) const;
966
967 /**
968 * Whether this array is identical to the other array.
969 *
970 * Performs a deep comparison of any contained arrays or objects and their fields. Comparison
971 * assumes that both fields are valid and are written in the canonical format. Fields must be
972 * written in the same order in arrays and objects, and name comparison is case sensitive. If
973 * these assumptions do not hold, this may return false for equivalent inputs. Validation can
974 * be done with the All mode to check these assumptions about the format of the inputs.
975 */
976 bool Equals(const FCbArrayView& Other) const;
977
978 /** Copy the array into a buffer of exactly GetSize() bytes, with no name. */
979 void CopyTo(FMutableMemoryView Buffer) const;
980
981 /** Copy the array into an archive. This will write GetSize() bytes, with no name. */
982 void CopyTo(FArchive& Ar) const;
983
984 /** Invoke the visitor for every attachment in the array. */
985 inline void IterateAttachments(FCbFieldVisitor Visitor) const { CreateViewIterator().IterateRangeAttachments(Visitor); }
986
987 /**
988 * Try to get a view of the array as it would be serialized, such as by CopyTo.
989 *
990 * A view is available if the array contains its type and has no name. Access the equivalent
991 * for other arrays through FCbArray::GetBuffer, FCbArray::Clone, or CopyTo.
992 */
993 inline bool TryGetView(FMemoryView& OutView) const
994 {
995 return !FCbFieldView::HasName() && FCbFieldView::TryGetView(OutView);
996 }
997
998 /** @see FCbFieldView::CreateViewIterator */
999 using FCbFieldView::CreateViewIterator;
1000 using FCbFieldView::begin;
1001 using FCbFieldView::end;
1002
1003private:
1004 /** Construct an array from an array field. No type check is performed! Use via FromFieldNoCheck. */
1005 inline explicit FCbArrayView(const FCbFieldView& Field) : FCbFieldView(Field) {}
1006};
1007
1008///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1009
1010/**
1011 * Array of FCbField[View] that have unique names.
1012 *
1013 * Accessing the fields of an object is always a safe operation, even if the requested field does
1014 * not exist. Fields may be accessed by name or through iteration. When a field is requested that
1015 * is not found in the object, the field that it returns has no value (evaluates to false) though
1016 * attempting to access the empty field is also safe, as described by FCbFieldView.
1017 *
1018 * This type only provides a view into memory and does not perform any memory management itself.
1019 * Use FCbObject to hold a reference to the underlying memory when necessary.
1020 */
1022{
1023public:
1024 /** @see FCbFieldView::FCbFieldView */
1025 using FCbFieldView::FCbFieldView;
1026
1027 /** Construct an object with no fields. */
1029
1030 /**
1031 * Find a field by case-sensitive name comparison.
1032 *
1033 * The cost of this operation scales linearly with the number of fields in the object. Prefer to
1034 * iterate over the fields only once when consuming an object.
1035 *
1036 * @param Name The name of the field.
1037 * @return The matching field if found, otherwise a field with no value.
1038 */
1039 FCbFieldView FindView(FUtf8StringView Name) const;
1040
1041 /** Find a field by case-insensitive name comparison. */
1042 FCbFieldView FindViewIgnoreCase(FUtf8StringView Name) const;
1043
1044 /** Find a field by case-sensitive name comparison. */
1045 inline FCbFieldView operator[](FUtf8StringView Name) const { return FindView(Name); }
1046
1047 /** Access the object as an object field. */
1048 inline FCbFieldView AsFieldView() const { return RemoveName(); }
1049
1050 /** Construct an object from an object field. No type check is performed! */
1051 static inline FCbObjectView FromFieldNoCheck(const FCbFieldView& Field) { return FCbObjectView(Field); }
1052
1053 /** Whether the object has any fields. */
1054 explicit operator bool() const;
1055
1056 /** Returns the size of the object in bytes if serialized by itself with no name. */
1057 uint64 GetSize() const;
1058
1059 /** Calculate the hash of the object if serialized by itself with no name. */
1061 /** Append the hash of the object if serialized by itself with no name. */
1062 void AppendHash(FIoHashBuilder& Builder) const;
1063
1064 /**
1065 * Whether this object is identical to the other object.
1066 *
1067 * Performs a deep comparison of any contained arrays or objects and their fields. Comparison
1068 * assumes that both fields are valid and are written in the canonical format. Fields must be
1069 * written in the same order in arrays and objects, and name comparison is case sensitive. If
1070 * these assumptions do not hold, this may return false for equivalent inputs. Validation can
1071 * be done with the All mode to check these assumptions about the format of the inputs.
1072 */
1073 bool Equals(const FCbObjectView& Other) const;
1074
1075 /** Copy the object into a buffer of exactly GetSize() bytes, with no name. */
1076 void CopyTo(FMutableMemoryView Buffer) const;
1077
1078 /** Copy the object into an archive. This will write GetSize() bytes, with no name. */
1079 void CopyTo(FArchive& Ar) const;
1080
1081 /** Invoke the visitor for every attachment in the object. */
1082 inline void IterateAttachments(FCbFieldVisitor Visitor) const { CreateViewIterator().IterateRangeAttachments(Visitor); }
1083
1084 /**
1085 * Try to get a view of the object as it would be serialized, such as by CopyTo.
1086 *
1087 * A view is available if the object contains its type and has no name. Access the equivalent
1088 * for other objects through FCbObject::GetBuffer, FCbObject::Clone, or CopyTo.
1089 */
1090 inline bool TryGetView(FMemoryView& OutView) const
1091 {
1092 return !FCbFieldView::HasName() && FCbFieldView::TryGetView(OutView);
1093 }
1094
1095 /** @see FCbFieldView::CreateViewIterator */
1096 using FCbFieldView::CreateViewIterator;
1097 using FCbFieldView::begin;
1098 using FCbFieldView::end;
1099
1100private:
1101 /** Construct an object from an object field. No type check is performed! Use via FromFieldNoCheck. */
1102 inline explicit FCbObjectView(const FCbFieldView& Field) : FCbFieldView(Field) {}
1103};
1104
1105///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1106
1107/** A wrapper that holds a reference to the buffer that contains its compact binary value. */
1108template <typename ViewType>
1109class TCbBuffer : public ViewType
1110{
1111public:
1112 /** Construct a default value. */
1113 TCbBuffer() = default;
1114
1115 /**
1116 * Construct a value from a pointer to its data and an optional externally-provided type.
1117 *
1118 * @param ValueBuffer A buffer that exactly contains the value.
1119 * @param Type HasFieldType means that ValueBuffer contains the type. Otherwise, use the given type.
1120 */
1121 inline explicit TCbBuffer(FSharedBuffer ValueBuffer, ECbFieldType Type = ECbFieldType::HasFieldType)
1122 {
1123 if (ValueBuffer)
1124 {
1128 }
1129 }
1130
1131 /** Construct a value that holds a reference to the buffer that contains it. */
1132 inline TCbBuffer(const ViewType& Value, FSharedBuffer OuterBuffer)
1133 : ViewType(Value)
1134 {
1135 if (OuterBuffer)
1136 {
1139 }
1140 }
1141
1142 /** Construct a value that holds a reference to the buffer of the outer that contains it. */
1143 template <typename OtherViewType>
1144 inline TCbBuffer(const ViewType& Value, TCbBuffer<OtherViewType> OuterBuffer)
1146 {
1147 }
1148
1149 /** Reset this to a default value and null buffer. */
1150 inline void Reset() { *this = TCbBuffer(); }
1151
1152 /** Whether this reference has ownership of the memory in its buffer. */
1153 inline bool IsOwned() const { return Buffer && Buffer.IsOwned(); }
1154
1155 /** Clone the value, if necessary, to a buffer that this reference has ownership of. */
1156 inline void MakeOwned()
1157 {
1158 if (!IsOwned())
1159 {
1164 }
1165 }
1166
1167 /** Returns the value as a view. */
1168 inline const ViewType& AsView() const { return *this; }
1169
1170 /**
1171 * Returns the outer buffer (if any) that contains this value.
1172 *
1173 * The outer buffer might contain other data before and/or after this value. Use GetBuffer to
1174 * request a buffer that exactly contains this value, or TryGetView for a contiguous view.
1175 */
1176 inline const FSharedBuffer& GetOuterBuffer() const & { return Buffer; }
1178
1179 /** Find a field of an object by case-sensitive name comparison, otherwise a field with no value. */
1180 inline FCbField operator[](FUtf8StringView Name) const;
1181
1182 /** Create an iterator for the fields of an array or object, otherwise an empty iterator. */
1184
1185 /** DO NOT USE DIRECTLY. These functions enable range-based for loop support. */
1186 inline FCbFieldIterator begin() const;
1187 constexpr inline FCbIteratorSentinel end() const { return FCbIteratorSentinel(); }
1188
1189private:
1190 template <typename OtherType>
1191 friend class TCbBuffer;
1192
1194};
1195
1196///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1197
1198/**
1199 * Factory functions for types derived from TCbBuffer.
1200 *
1201 * This uses the curiously recurring template pattern to construct the correct derived type, that
1202 * must inherit from TCbBuffer and this type to expose the factory functions.
1203 */
1204template <typename Type, typename ViewType>
1206{
1207public:
1208 /** Construct a value from an owned clone of its memory. */
1209 static inline Type Clone(const void* const Data)
1210 {
1211 return Clone(ViewType(Data));
1212 }
1213
1214 /** Construct a value from an owned clone of its memory. */
1215 static inline Type Clone(const ViewType& Value)
1216 {
1218 Owned.MakeOwned();
1219 return Owned;
1220 }
1221
1222 /** Construct a value from a read-only view of its memory and its optional outer buffer. */
1223 static inline Type MakeView(const void* const Data, FSharedBuffer OuterBuffer = FSharedBuffer())
1224 {
1226 }
1227
1228 /** Construct a value from a read-only view of its memory and its optional outer buffer. */
1229 static inline Type MakeView(const ViewType& Value, FSharedBuffer OuterBuffer = FSharedBuffer())
1230 {
1231 return Type(Value, MoveTemp(OuterBuffer));
1232 }
1233};
1234
1235///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1236
1237class FCbArray;
1238class FCbObject;
1239
1240///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1241
1242/**
1243 * A field that includes a shared buffer for the memory that contains it.
1244 *
1245 * @see FCbFieldView
1246 * @see TCbBuffer
1247 */
1249{
1250public:
1251 using TCbBuffer::TCbBuffer;
1252
1253 /** Access the field as an object. Defaults to an empty object on error. */
1254 inline FCbObject AsObject() &;
1255 inline FCbObject AsObject() &&;
1256
1257 /** Access the field as an array. Defaults to an empty array on error. */
1258 inline FCbArray AsArray() &;
1259 inline FCbArray AsArray() &&;
1260
1261 /** Access the field as binary. Returns the provided default on error. */
1264
1265 /** Returns a buffer that contains the field as it would be serialized by CopyTo. */
1267};
1268
1269template <typename ViewType>
1270inline FCbField TCbBuffer<ViewType>::operator[](FUtf8StringView Name) const
1271{
1272 if (FCbFieldView Field = ViewType::operator[](Name))
1273 {
1274 return FCbField::MakeView(Field, GetOuterBuffer());
1275 }
1276 return FCbField();
1277}
1278
1279/**
1280 * Iterator for FCbField.
1281 *
1282 * @see TCbFieldIterator
1283 */
1285{
1286public:
1287 /** Construct a field range from an owned clone of a range. */
1289
1290 /** Construct a field range from an owned clone of a range. */
1292 {
1293 return CloneRange(FCbFieldViewIterator(It));
1294 }
1295
1296 /** Construct a field range that contains exactly one field. */
1298 {
1299 return FCbFieldIterator(MoveTemp(Field));
1300 }
1301
1302 /**
1303 * Construct a field range from a buffer containing zero or more valid fields.
1304 *
1305 * @param Buffer A buffer containing zero or more valid fields.
1306 * @param Type HasFieldType means that Buffer contains the type. Otherwise, use the given type.
1307 */
1308 static inline FCbFieldIterator MakeRange(FSharedBuffer Buffer, ECbFieldType Type = ECbFieldType::HasFieldType)
1309 {
1310 if (Buffer.GetSize())
1311 {
1312 const void* const DataEnd = Buffer.GetView().GetDataEnd();
1313 return FCbFieldIterator(FCbField(MoveTemp(Buffer), Type), DataEnd);
1314 }
1315 return FCbFieldIterator();
1316 }
1317
1318 /** Construct a field range from an iterator and its optional outer buffer. */
1319 static inline FCbFieldIterator MakeRangeView(const FCbFieldViewIterator& It, FSharedBuffer OuterBuffer = FSharedBuffer())
1320 {
1321 return FCbFieldIterator(FCbField(It, MoveTemp(OuterBuffer)), GetFieldsEnd(It));
1322 }
1323
1324 /** Construct an empty field range. */
1325 constexpr FCbFieldIterator() = default;
1326
1327 /** Clone the range, if necessary, to a buffer that this has ownership of. */
1328 inline void MakeRangeOwned()
1329 {
1330 if (!IsOwned())
1331 {
1332 *this = CloneRange(*this);
1333 }
1334 }
1335
1336private:
1338};
1339
1340template <typename ViewType>
1342{
1343 if (FCbFieldViewIterator It = ViewType::CreateViewIterator())
1344 {
1345 return FCbFieldIterator::MakeRangeView(It, GetOuterBuffer());
1346 }
1347 return FCbFieldIterator();
1348}
1349
1350template <typename ViewType>
1351inline FCbFieldIterator TCbBuffer<ViewType>::begin() const
1352{
1353 return CreateIterator();
1354}
1355
1356///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1357
1358/**
1359 * An array that includes a shared buffer for the memory that contains it.
1360 *
1361 * @see FCbArrayView
1362 * @see TCbBuffer
1363 */
1365{
1366public:
1367 using TCbBuffer::TCbBuffer;
1368
1369 /** Access the array as an array field. */
1370 inline FCbField AsField() const & { return FCbField(FCbArrayView::AsFieldView(), *this); }
1371 inline FCbField AsField() && { return FCbField(FCbArrayView::AsFieldView(), MoveTemp(*this)); }
1372
1373 /** Returns a buffer that contains the array as it would be serialized by CopyTo. */
1375};
1376
1377///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1378
1379/**
1380 * An object that includes a shared buffer for the memory that contains it.
1381 *
1382 * @see FCbObjectView
1383 * @see TCbBuffer
1384 */
1386{
1387public:
1388 using TCbBuffer::TCbBuffer;
1389
1390 /** Find a field by case-sensitive name comparison. */
1391 inline FCbField Find(FUtf8StringView Name) const
1392 {
1393 if (::FCbFieldView Field = FindView(Name))
1394 {
1395 return FCbField(Field, *this);
1396 }
1397 return FCbField();
1398 }
1399
1400 /** Find a field by case-insensitive name comparison. */
1401 inline FCbField FindIgnoreCase(FUtf8StringView Name) const
1402 {
1403 if (::FCbFieldView Field = FindViewIgnoreCase(Name))
1404 {
1405 return FCbField(Field, *this);
1406 }
1407 return FCbField();
1408 }
1409
1410 /** Find a field by case-sensitive name comparison. */
1411 inline FCbField operator[](FUtf8StringView Name) const { return Find(Name); }
1412
1413 /** Access the object as an object field. */
1414 inline FCbField AsField() const & { return FCbField(FCbObjectView::AsFieldView(), *this); }
1415 inline FCbField AsField() && { return FCbField(FCbObjectView::AsFieldView(), MoveTemp(*this)); }
1416
1417 /** Returns a buffer that contains the object as it would be serialized by CopyTo. */
1419};
1420
1421///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1422
1424{
1425 return IsObject() ? FCbObject(AsObjectView(), *this) : FCbObject();
1426}
1427
1429{
1430 return IsObject() ? FCbObject(AsObjectView(), MoveTemp(*this)) : FCbObject();
1431}
1432
1434{
1435 return IsArray() ? FCbArray(AsArrayView(), *this) : FCbArray();
1436}
1437
1439{
1440 return IsArray() ? FCbArray(AsArrayView(), MoveTemp(*this)) : FCbArray();
1441}
1442
1444{
1445 const FMemoryView View = AsBinaryView();
1446 return !HasError() ? FSharedBuffer::MakeView(View, GetOuterBuffer()) : Default;
1447}
1448
1450{
1451 const FMemoryView View = AsBinaryView();
1452 return !HasError() ? FSharedBuffer::MakeView(View, MoveTemp(*this).GetOuterBuffer()) : Default;
1453}
1454
1455///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define check(expr)
ECbFieldError
ECbFieldType
#define ENUM_CLASS_FLAGS(Enum)
FCbField AsField() &&
FCompositeBuffer GetBuffer() const
FCbField AsField() const &
bool Equals(const FCbArrayView &Other) const
FCbArrayView(const FCbFieldView &Field)
void IterateAttachments(FCbFieldVisitor Visitor) const
FCbFieldView AsFieldView() const
FIoHash GetHash() const
void CopyTo(FMutableMemoryView Buffer) const
uint64 Num() const
void CopyTo(FArchive &Ar) const
static FCbArrayView FromFieldNoCheck(const FCbFieldView &Field)
void AppendHash(FIoHashBuilder &Builder) const
operator bool() const
uint64 GetSize() const
bool TryGetView(FMemoryView &OutView) const
FCbArray AsArray() &
FCompositeBuffer GetBuffer() const
FCbArray AsArray() &&
FCbObject AsObject() &
FSharedBuffer AsBinary(const FSharedBuffer &Default=FSharedBuffer()) &&
FSharedBuffer AsBinary(const FSharedBuffer &Default=FSharedBuffer()) &
FCbObject AsObject() &&
static FCbFieldIterator CloneRange(const FCbFieldViewIterator &It)
static FCbFieldIterator MakeRangeView(const FCbFieldViewIterator &It, FSharedBuffer OuterBuffer=FSharedBuffer())
static FCbFieldIterator MakeRange(FSharedBuffer Buffer, ECbFieldType Type=ECbFieldType::HasFieldType)
static FCbFieldIterator MakeSingle(FCbField Field)
constexpr FCbFieldIterator()=default
static FCbFieldIterator CloneRange(const FCbFieldIterator &It)
static constexpr ECbFieldType GetType(ECbFieldType Type)
static constexpr bool IsTimeSpan(ECbFieldType Type)
static constexpr bool IsArray(ECbFieldType Type)
static constexpr ECbFieldType ArrayMask
static constexpr bool IsObjectId(ECbFieldType Type)
static void StaticAssertTypeConstants()
static constexpr bool IsNone(ECbFieldType Type)
static constexpr bool IsUuid(ECbFieldType Type)
static constexpr ECbFieldType ArrayBase
static constexpr bool IsBool(ECbFieldType Type)
static constexpr ECbFieldType GetSerializedType(ECbFieldType Type)
static constexpr bool IsBinaryAttachment(ECbFieldType Type)
static constexpr bool IsHash(ECbFieldType Type)
static constexpr ECbFieldType IntegerBase
static constexpr ECbFieldType FloatBase
static constexpr ECbFieldType BoolMask
static constexpr bool IsObject(ECbFieldType Type)
static constexpr ECbFieldType TypeMask
static constexpr bool HasFields(ECbFieldType Type)
static constexpr ECbFieldType FloatMask
static constexpr bool IsAttachment(ECbFieldType Type)
static constexpr bool MayContainAttachments(ECbFieldType Type)
static constexpr bool IsObjectAttachment(ECbFieldType Type)
static constexpr bool IsCustomByName(ECbFieldType Type)
static constexpr ECbFieldType ObjectBase
static constexpr ECbFieldType SerializedTypeMask
static constexpr bool IsDateTime(ECbFieldType Type)
static constexpr bool IsFloat(ECbFieldType Type)
static constexpr bool HasFieldName(ECbFieldType Type)
static constexpr ECbFieldType AttachmentBase
static constexpr bool HasFieldType(ECbFieldType Type)
static constexpr ECbFieldType IntegerMask
static constexpr bool HasUniformFields(ECbFieldType Type)
static constexpr ECbFieldType BoolBase
static constexpr ECbFieldType ObjectMask
static constexpr bool IsInteger(ECbFieldType Type)
static constexpr ECbFieldType AttachmentMask
static constexpr bool IsBinary(ECbFieldType Type)
static constexpr bool IsCustomById(ECbFieldType Type)
static constexpr bool IsString(ECbFieldType Type)
static constexpr bool IsNull(ECbFieldType Type)
FCbFieldView(const void *Data, ECbFieldType Type=ECbFieldType::HasFieldType)
FCbFieldView operator[](FUtf8StringView Name) const
constexpr bool IsArray() const
bool Equals(const FCbFieldView &Other) const
constexpr FUtf8StringView GetName() const
uint64 AsUInt64(uint64 Default=0)
ECbFieldError Error
void CopyTo(FArchive &Ar) const
FDateTime AsDateTime()
constexpr bool HasName() const
constexpr operator bool() const
constexpr bool HasError() const
FTimespan AsTimeSpan(FTimespan Default)
int64 AsInt64(int64 Default=0)
FIoHash AsBinaryAttachment(const FIoHash &Default=FIoHash())
uint8 AsUInt8(uint8 Default=0)
ECbFieldType TypeWithFlags
constexpr bool IsInteger() const
uint32 AsUInt32(uint32 Default=0)
FIoHash AsHash(const FIoHash &Default=FIoHash())
constexpr bool IsObjectId() const
void AppendHash(FIoHashBuilder &Builder) const
FMemoryView AsBinaryView(FMemoryView Default=FMemoryView())
int64 AsDateTimeTicks(int64 Default=0)
FUtf8StringView AsString(FUtf8StringView Default=FUtf8StringView())
constexpr bool IsFloat() const
IntType AsInteger(IntType Default)
constexpr FCbIteratorSentinel end() const
FCbObjectView AsObjectView()
int32 AsInt32(int32 Default=0)
uint16 AsUInt16(uint16 Default=0)
int64 AsTimeSpanTicks(int64 Default=0)
FIoHash AsObjectAttachment(const FIoHash &Default=FIoHash())
FCbArrayView AsArrayView()
float AsFloat(float Default=0.0f)
void Assign(const void *InData, const ECbFieldType InType)
void IterateAttachments(FCbFieldVisitor Visitor) const
int16 AsInt16(int16 Default=0)
FMemoryView GetValueView() const
FDateTime AsDateTime(FDateTime Default)
FCbCustomByName AsCustomByName(FCbCustomByName Default=FCbCustomByName())
constexpr bool HasValue() const
FIoHash GetHash() const
constexpr FCbFieldView RemoveName() const
int8 AsInt8(int8 Default=0)
constexpr bool IsUuid() const
constexpr ECbFieldType GetTypeWithFlags() const
double AsDouble(double Default=0.0)
FIoHash AsAttachment(const FIoHash &Default=FIoHash())
constexpr bool IsCustomByName() const
FTimespan AsTimeSpan()
FCbValue GetValue() const
constexpr bool IsHash() const
FMemoryView AsCustom(uint64 Id, FMemoryView Default=FMemoryView())
constexpr bool IsTimeSpan() const
uint64 AsInteger(uint64 Default, UE::CompactBinary::Private::FIntegerParams Params)
FMemoryView GetView() const
const void * Value
constexpr bool IsDateTime() const
bool AsBool(bool bDefault=false)
constexpr bool IsObject() const
void CopyTo(FMutableMemoryView Buffer) const
FMemoryView AsCustom(FUtf8StringView Name, FMemoryView Default=FMemoryView())
constexpr bool IsAttachment() const
FGuid AsUuid(const FGuid &Default)
constexpr bool IsObjectAttachment() const
constexpr bool IsString() const
FCbCustomById AsCustomById(FCbCustomById Default=FCbCustomById())
const void * GetValueEnd() const
FCbFieldViewIterator CreateViewIterator() const
constexpr bool IsNull() const
constexpr bool IsCustomById() const
FCbObjectId AsObjectId(const FCbObjectId &Default=FCbObjectId())
bool TryGetView(FMemoryView &OutView) const
FCbFieldView(const FCbValue &Value)
constexpr ECbFieldError GetError() const
FCbFieldViewIterator begin() const
constexpr bool IsBool() const
FMemoryView GetViewNoType() const
uint64 GetValueSize() const
FGuid AsUuid()
uint64 GetSize() const
constexpr bool IsBinaryAttachment() const
constexpr const void * GetValueData() const
constexpr FCbFieldView()=default
constexpr bool IsBinary() const
constexpr ECbFieldType GetType() const
static FCbFieldViewIterator MakeRange(FMemoryView View, ECbFieldType Type=ECbFieldType::HasFieldType)
constexpr FCbFieldViewIterator()=default
static FCbFieldViewIterator MakeSingle(const FCbFieldView &Field)
FCbFieldViewIterator(const TCbFieldIterator< OtherFieldType > &It)
FCbField FindIgnoreCase(FUtf8StringView Name) const
FCompositeBuffer GetBuffer() const
FCbField operator[](FUtf8StringView Name) const
FCbField AsField() &&
FCbField Find(FUtf8StringView Name) const
FCbField AsField() const &
ByteArray Bytes
const ByteArray & GetBytes() const
bool operator<(const FCbObjectId &B) const
bool operator!=(const FCbObjectId &B) const
FCbObjectId()=default
constexpr FMemoryView GetView() const
FCbObjectId(const ByteArray &ObjectId)
operator const ByteArray &() const
static FCbObjectId NewObjectId()
friend uint32 GetTypeHash(const FCbObjectId &Id)
friend TStringBuilderBase< CharType > & operator<<(TStringBuilderBase< CharType > &Builder, const FCbObjectId &Id)
FCbObjectId(FMemoryView ObjectId)
bool operator==(const FCbObjectId &B) const
FCbFieldView FindView(FUtf8StringView Name) const
uint64 GetSize() const
operator bool() const
FCbFieldView AsFieldView() const
FIoHash GetHash() const
void CopyTo(FArchive &Ar) const
FCbFieldView FindViewIgnoreCase(FUtf8StringView Name) const
void CopyTo(FMutableMemoryView Buffer) const
void AppendHash(FIoHashBuilder &Builder) const
FCbFieldView operator[](FUtf8StringView Name) const
void IterateAttachments(FCbFieldVisitor Visitor) const
static FCbObjectView FromFieldNoCheck(const FCbFieldView &Field)
bool Equals(const FCbObjectView &Other) const
bool TryGetView(FMemoryView &OutView) const
FCbObjectView(const FCbFieldView &Field)
static Type Clone(const ViewType &Value)
static Type MakeView(const ViewType &Value, FSharedBuffer OuterBuffer=FSharedBuffer())
static Type MakeView(const void *const Data, FSharedBuffer OuterBuffer=FSharedBuffer())
static Type Clone(const void *const Data)
constexpr FCbIteratorSentinel end() const
TCbBuffer()=default
FSharedBuffer Buffer
FCbFieldIterator begin() const
TCbBuffer(FSharedBuffer ValueBuffer, ECbFieldType Type=ECbFieldType::HasFieldType)
FSharedBuffer GetOuterBuffer() &&
const ViewType & AsView() const
const FSharedBuffer & GetOuterBuffer() const &
FCbField operator[](FUtf8StringView Name) const
void MakeOwned()
bool IsOwned() const
TCbBuffer(const ViewType &Value, TCbBuffer< OtherViewType > OuterBuffer)
TCbBuffer(const ViewType &Value, FSharedBuffer OuterBuffer)
FCbFieldIterator CreateIterator() const
TCbFieldIterator operator++(int)
static const void * GetFieldsEnd(const TCbFieldIterator< OtherFieldType > &It)
uint64 GetRangeSize() const
constexpr TCbFieldIterator(FieldType &&InField, const void *InFieldsEnd)
void CopyRangeTo(FMutableMemoryView Buffer) const
constexpr FCbIteratorSentinel end() const
bool TryGetRangeView(FMemoryView &OutView) const
constexpr bool operator==(const TCbFieldIterator< OtherFieldType > &Other) const
TCbFieldIterator & operator++()
constexpr FieldType & operator*()
constexpr TCbFieldIterator begin() const
constexpr TCbFieldIterator(FieldType InField)
constexpr bool operator!=(const FCbIteratorSentinel &) const
constexpr bool operator==(const FCbIteratorSentinel &) const
void CopyRangeTo(FArchive &Ar) const
constexpr FieldType * operator->()
constexpr bool operator!=(const TCbFieldIterator< OtherFieldType > &Other) const
constexpr bool Equals(const TCbFieldIterator< OtherFieldType > &Other) const
void AppendRangeHash(FIoHashBuilder &Builder) const
void IterateRangeAttachments(FCbFieldVisitor Visitor) const
const void * FieldsEnd
constexpr TCbFieldIterator()=default
FIoHash GetRangeHash() const
static constexpr FIntegerParams MakeIntegerParams()
Definition Vector.h:40
FMemoryView Data
FMemoryView Data
FUtf8StringView Name
Definition Guid.h:108
static FORCEINLINE int32 Memcmp(const void *Buf1, const void *Buf2, SIZE_T Count)
static FORCEINLINE void * Memcpy(void *Dest, const void *Src, SIZE_T Count)