Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
CompactBinaryWriter.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Containers/Array.h"
6#include "Containers/ContainersFwd.h"
7#include "Containers/StringFwd.h"
8#include "Containers/StringView.h"
9#include "CoreTypes.h"
10#include "HAL/PlatformCrt.h"
11#include "Memory/MemoryFwd.h"
12#include "Memory/MemoryView.h"
13#include "Serialization/CompactBinary.h"
14
15#include <type_traits>
16
17class FCompositeBuffer;
18class FSharedBuffer;
19
20///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
21
22class FArchive;
23class FCbAttachment;
24class FName;
25struct FDateTime;
26struct FGuid;
27struct FIoHash;
28struct FTimespan;
29
30/**
31 * A writer for compact binary object, arrays, and fields.
32 *
33 * The writer produces a sequence of fields that can be saved to a provided memory buffer or into
34 * a new owned buffer. The typical use case is to write a single object, which can be accessed by
35 * calling Save().AsObject() or Save(Buffer).AsObjectView().
36 *
37 * The writer will assert on most incorrect usage and will always produce valid compact binary if
38 * provided with valid input. The writer does not check for invalid UTF-8 string encoding, object
39 * fields with duplicate names, or invalid compact binary being copied from another source.
40 *
41 * It is most convenient to use the streaming API for the writer, as demonstrated in the example.
42 *
43 * When writing a small amount of compact binary data, TCbWriter can be more efficient as it uses
44 * a fixed-size stack buffer for storage before spilling onto the heap.
45 *
46 * @see TCbWriter
47 *
48 * Example:
49 *
50 * FCbObject WriteObject()
51 * {
52 * TCbWriter<256> Writer;
53 * Writer.BeginObject();
54 *
55 * Writer << "Resize" << true;
56 * Writer << "MaxWidth" << 1024;
57 * Writer << "MaxHeight" << 1024;
58 *
59 * Writer.BeginArray();
60 * Writer << "FormatA" << "FormatB" << "FormatC";
61 * Writer.EndArray();
62 *
63 * Writer.EndObject();
64 * return Writer.Save().AsObject();
65 * }
66 */
68{
69public:
72
73 FCbWriter(const FCbWriter&) = delete;
74 FCbWriter& operator=(const FCbWriter&) = delete;
75
76 /** Empty the writer without releasing any allocated memory. */
77 void Reset();
78
79 /**
80 * Serialize the field(s) to an owned buffer and return it as an iterator.
81 *
82 * It is not valid to call this function in the middle of writing an object, array, or field.
83 * The writer remains valid for further use when this function returns.
84 */
86
87 /**
88 * Serialize the field(s) to memory.
89 *
90 * It is not valid to call this function in the middle of writing an object, array, or field.
91 * The writer remains valid for further use when this function returns.
92 *
93 * @param Buffer A mutable memory view to write to. Must be exactly GetSaveSize() bytes.
94 * @return An iterator for the field(s) written to the buffer.
95 */
96 FCbFieldViewIterator Save(FMutableMemoryView Buffer) const;
97
98 /**
99 * Serialize the field(s) to an archive.
100 *
101 * It is not valid to call this function in the middle of writing an object, array, or field.
102 * The writer remains valid for further use when this function returns.
103 *
104 * @param Ar An archive to write to. Exactly GetSaveSize() bytes will be written.
105 */
106 void Save(FArchive& Ar) const;
107
108 /**
109 * The size of buffer (in bytes) required to serialize the fields that have been written.
110 *
111 * It is not valid to call this function in the middle of writing an object, array, or field.
112 */
113 uint64 GetSaveSize() const;
114
115 /**
116 * Sets the name of the next field to be written.
117 *
118 * It is not valid to call this function when writing a field inside an array.
119 * Names must be valid UTF-8 and must be unique within an object.
120 */
121 FCbWriter& SetName(FUtf8StringView Name);
122
123 /** Copy the value (not the name) of an existing field. */
124 inline void AddField(FUtf8StringView Name, const FCbFieldView& Value) { SetName(Name); AddField(Value); }
125 void AddField(const FCbFieldView& Value);
126 /** Copy the value (not the name) of an existing field. Holds a reference if owned. */
127 inline void AddField(FUtf8StringView Name, const FCbField& Value) { SetName(Name); AddField(Value); }
128 void AddField(const FCbField& Value);
129
130 /** Begin a new object. Must have a matching call to EndObject. */
131 inline void BeginObject(FUtf8StringView Name) { SetName(Name); BeginObject(); }
133 /** End an object after its fields have been written. */
134 void EndObject();
135
136 /** Copy the value (not the name) of an existing object. */
137 inline void AddObject(FUtf8StringView Name, const FCbObjectView& Value) { SetName(Name); AddObject(Value); }
138 void AddObject(const FCbObjectView& Value);
139 /** Copy the value (not the name) of an existing object. Holds a reference if owned. */
140 inline void AddObject(FUtf8StringView Name, const FCbObject& Value) { SetName(Name); AddObject(Value); }
141 void AddObject(const FCbObject& Value);
142
143 /** Begin a new array. Must have a matching call to EndArray. */
144 inline void BeginArray(FUtf8StringView Name) { SetName(Name); BeginArray(); }
146 /** End an array after its fields have been written. */
147 void EndArray();
148
149 /** Copy the value (not the name) of an existing array. */
150 inline void AddArray(FUtf8StringView Name, const FCbArrayView& Value) { SetName(Name); AddArray(Value); }
151 void AddArray(const FCbArrayView& Value);
152 /** Copy the value (not the name) of an existing array. Holds a reference if owned. */
153 inline void AddArray(FUtf8StringView Name, const FCbArray& Value) { SetName(Name); AddArray(Value); }
154 void AddArray(const FCbArray& Value);
155
156 /** Write a null field. */
157 inline void AddNull(FUtf8StringView Name) { SetName(Name); AddNull(); }
158 void AddNull();
159
160 /** Write a binary field by copying Size bytes from Value. */
161 inline void AddBinary(FUtf8StringView Name, const void* Value, uint64 Size) { SetName(Name); AddBinary(Value, Size); }
162 void AddBinary(const void* Value, uint64 Size);
163 /** Write a binary field by copying the view. */
164 inline void AddBinary(FUtf8StringView Name, FMemoryView Value) { SetName(Name); AddBinary(Value); }
165 inline void AddBinary(FMemoryView Value) { AddBinary(Value.GetData(), Value.GetSize()); }
166 /** Write a binary field by copying the buffer. Holds a reference if owned. */
167 inline void AddBinary(FUtf8StringView Name, const FSharedBuffer& Value) { SetName(Name); AddBinary(Value); }
168 void AddBinary(const FSharedBuffer& Value);
169 inline void AddBinary(FUtf8StringView Name, const FCompositeBuffer& Value) { SetName(Name); AddBinary(Value); }
170 void AddBinary(const FCompositeBuffer& Value);
171
172 /** Write a string field by copying the UTF-8 value. */
173 inline void AddString(FUtf8StringView Name, FUtf8StringView Value) { SetName(Name); AddString(Value); }
174 void AddString(FUtf8StringView Value);
175 /** Write a string field by converting the UTF-16 value to UTF-8. */
176 inline void AddString(FUtf8StringView Name, FWideStringView Value) { SetName(Name); AddString(Value); }
177 void AddString(FWideStringView Value);
178
179 /** Write an integer field. */
180 inline void AddInteger(FUtf8StringView Name, int32 Value) { SetName(Name); AddInteger(Value); }
181 void AddInteger(int32 Value);
182 /** Write an integer field. */
183 inline void AddInteger(FUtf8StringView Name, int64 Value) { SetName(Name); AddInteger(Value); }
184 void AddInteger(int64 Value);
185 /** Write an integer field. */
186 inline void AddInteger(FUtf8StringView Name, uint32 Value) { SetName(Name); AddInteger(Value); }
187 void AddInteger(uint32 Value);
188 /** Write an integer field. */
189 inline void AddInteger(FUtf8StringView Name, uint64 Value) { SetName(Name); AddInteger(Value); }
190 void AddInteger(uint64 Value);
191
192 /** Write a float field from a 32-bit float value. */
193 inline void AddFloat(FUtf8StringView Name, float Value) { SetName(Name); AddFloat(Value); }
194 void AddFloat(float Value);
195 /** Write a float field from a 64-bit float value. */
196 inline void AddFloat(FUtf8StringView Name, double Value) { SetName(Name); AddFloat(Value); }
197 void AddFloat(double Value);
198
199 /** Write a bool field. */
200 inline void AddBool(FUtf8StringView Name, bool bValue) { SetName(Name); AddBool(bValue); }
201 void AddBool(bool bValue);
202
203 /** Write a field referencing an object attachment by its hash. */
204 inline void AddObjectAttachment(FUtf8StringView Name, const FIoHash& Value) { SetName(Name); AddObjectAttachment(Value); }
205 void AddObjectAttachment(const FIoHash& Value);
206 /** Write a field referencing a binary attachment by its hash. */
207 inline void AddBinaryAttachment(FUtf8StringView Name, const FIoHash& Value) { SetName(Name); AddBinaryAttachment(Value); }
208 void AddBinaryAttachment(const FIoHash& Value);
209 /** Write a field referencing the attachment by its hash. */
210 inline void AddAttachment(FUtf8StringView Name, const FCbAttachment& Attachment) { SetName(Name); AddAttachment(Attachment); }
211 void AddAttachment(const FCbAttachment& Attachment);
212
213 /** Write a hash field. */
214 inline void AddHash(FUtf8StringView Name, const FIoHash& Value) { SetName(Name); AddHash(Value); }
215 void AddHash(const FIoHash& Value);
216 /** Write a UUID field. */
217 inline void AddUuid(FUtf8StringView Name, const FGuid& Value) { SetName(Name); AddUuid(Value); }
218 void AddUuid(const FGuid& Value);
219
220 /** Write a date/time field with the specified count of 100ns ticks since the epoch. */
221 inline void AddDateTimeTicks(FUtf8StringView Name, int64 Ticks) { SetName(Name); AddDateTimeTicks(Ticks); }
222 void AddDateTimeTicks(int64 Ticks);
223
224 /** Write a date/time field. */
225 void AddDateTime(FUtf8StringView Name, FDateTime Value);
227
228 /** Write a time span field with the specified count of 100ns ticks. */
229 inline void AddTimeSpanTicks(FUtf8StringView Name, int64 Ticks) { SetName(Name); AddTimeSpanTicks(Ticks); }
230 void AddTimeSpanTicks(int64 Ticks);
231
232 /** Write a time span field. */
233 void AddTimeSpan(FUtf8StringView Name, FTimespan Value);
235
236 /** Write an ObjectId field. */
237 inline void AddObjectId(FUtf8StringView Name, const FCbObjectId& Value) { SetName(Name); AddObjectId(Value); }
238 void AddObjectId(const FCbObjectId& Value);
239
240 /** Write a custom field with an integer sub-type identifier. */
241 inline void AddCustom(FUtf8StringView FieldName, uint64 TypeId, FMemoryView Value) { SetName(FieldName); AddCustom(TypeId, Value); }
242 void AddCustom(uint64 TypeId, FMemoryView Value);
243
244 /** Write a custom field with a string sub-type identifier. */
245 inline void AddCustom(FUtf8StringView FieldName, FUtf8StringView TypeName, FMemoryView Value) { SetName(FieldName); AddCustom(TypeName, Value); }
246 void AddCustom(FUtf8StringView TypeName, FMemoryView Value);
247
248 /** Private flags that are public to work with ENUM_CLASS_FLAGS. */
249 enum class EStateFlags : uint8;
250
251protected:
252 /** Reserve the specified size up front until the format is optimized. */
253 explicit FCbWriter(int64 InitialSize);
254
255private:
256
257 /** Begin writing a field. May be called twice for named fields. */
259
260 /** Finish writing a field by writing its type. */
262
263 /** Set the field name if valid in this state, otherwise write add a string field. */
264 void SetNameOrAddString(FUtf8StringView NameOrValue);
265
266 /** Returns a view of the name of the active field, if any, otherwise the empty view. */
267 FUtf8StringView GetActiveName() const;
268
269 /** Remove field types after the first to make the sequence uniform. */
270 void MakeFieldsUniform(int64 FieldBeginOffset, int64 FieldEndOffset);
271
272 /** State of the object, array, or top-level field being written. */
273 struct FState
274 {
275 EStateFlags Flags{};
276 /** The type of the fields in the sequence if uniform, otherwise None. */
278 /** The offset of the start of the current field. */
279 int64 Offset{};
280 /** The number of fields written in this state. */
281 uint64 Count{};
282 };
283
284private:
285 // This is a prototype-quality format for the writer. Using an array of bytes is inefficient,
286 // and will lead to many unnecessary copies and moves of the data to resize the array, insert
287 // object and array sizes, and remove field types for uniform objects and uniform arrays. The
288 // optimized format will be a list of power-of-two blocks and an optional first block that is
289 // provided externally, such as on the stack. That format will store the offsets that require
290 // object or array sizes to be inserted and field types to be removed, and will perform those
291 // operations only when saving to a buffer.
294
295public:
296 /** Write the field name if valid in this state, otherwise write the string value. */
297 inline FCbWriter& operator<<(FUtf8StringView NameOrValue)
298 {
299 SetNameOrAddString(NameOrValue);
300 return *this;
301 }
302
303 /** Write the field name if valid in this state, otherwise write the string value. */
304 inline FCbWriter& operator<<(const ANSICHAR* NameOrValue)
305 {
306 return *this << FAnsiStringView(NameOrValue);
307 }
308
309 /** Write the field name if valid in this state, otherwise write the string value. */
310 inline FCbWriter& operator<<(const UTF8CHAR* NameOrValue)
311 {
312 return *this << FUtf8StringView(NameOrValue);
313 }
314
315 inline FCbWriter& operator<<(const FCbFieldView& Value)
316 {
317 AddField(Value);
318 return *this;
319 }
320
321 inline FCbWriter& operator<<(const FCbField& Value)
322 {
323 AddField(Value);
324 return *this;
325 }
326
327 inline FCbWriter& operator<<(const FCbObjectView& Value)
328 {
329 AddObject(Value);
330 return *this;
331 }
332
333 inline FCbWriter& operator<<(const FCbObject& Value)
334 {
335 AddObject(Value);
336 return *this;
337 }
338
339 inline FCbWriter& operator<<(const FCbArrayView& Value)
340 {
341 AddArray(Value);
342 return *this;
343 }
344
345 inline FCbWriter& operator<<(const FCbArray& Value)
346 {
347 AddArray(Value);
348 return *this;
349 }
350
351 inline FCbWriter& operator<<(nullptr_t)
352 {
353 AddNull();
354 return *this;
355 }
356
357 inline FCbWriter& operator<<(FWideStringView Value)
358 {
359 AddString(Value);
360 return *this;
361 }
362
363 inline FCbWriter& operator<<(const WIDECHAR* Value)
364 {
365 AddString(Value);
366 return *this;
367 }
368
369 inline FCbWriter& operator<<(int32 Value)
370 {
371 AddInteger(Value);
372 return *this;
373 }
374
375 inline FCbWriter& operator<<(int64 Value)
376 {
377 AddInteger(Value);
378 return *this;
379 }
380
381 inline FCbWriter& operator<<(uint32 Value)
382 {
383 AddInteger(Value);
384 return *this;
385 }
386
387 inline FCbWriter& operator<<(uint64 Value)
388 {
389 AddInteger(Value);
390 return *this;
391 }
392
393 inline FCbWriter& operator<<(float Value)
394 {
395 AddFloat(Value);
396 return *this;
397 }
398
399 inline FCbWriter& operator<<(double Value)
400 {
401 AddFloat(Value);
402 return *this;
403 }
404
405 inline FCbWriter& operator<<(bool Value)
406 {
407 AddBool(Value);
408 return *this;
409 }
410
411 inline FCbWriter& operator<<(const FCbAttachment& Attachment)
412 {
413 AddAttachment(Attachment);
414 return *this;
415 }
416
417 inline FCbWriter& operator<<(const FIoHash& Value)
418 {
419 AddHash(Value);
420 return *this;
421 }
422
423 inline FCbWriter& operator<<(const FGuid& Value)
424 {
425 AddUuid(Value);
426 return *this;
427 }
428
429 FCbWriter& operator<<(FDateTime Value);
430 FCbWriter& operator<<(FTimespan Value);
431
432 inline FCbWriter& operator<<(const FCbObjectId& Value)
433 {
434 AddObjectId(Value);
435 return *this;
436 }
437
438 FCbWriter& operator<<(FName Value);
439
440 template <typename T, typename Allocator,
441 std::void_t<decltype(std::declval<FCbWriter&>() << std::declval<const T&>())>* = nullptr>
442 inline FCbWriter& operator<<(const TArray<T, Allocator>& Value)
443 {
444 BeginArray();
445 for (const T& Element : Value)
446 {
447 *this << Element;
448 }
449 EndArray();
450 return *this;
451 }
452};
453
454///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
455
456/**
457 * A writer for compact binary object, arrays, and fields that uses a fixed-size stack buffer.
458 *
459 * @see FCbWriter
460 */
461template <uint32 InlineBufferSize>
462class TCbWriter : public FCbWriter
463{
464public:
465 inline TCbWriter()
467 {
468 }
469
470 TCbWriter(const TCbWriter&) = delete;
471 TCbWriter& operator=(const TCbWriter&) = delete;
472
473private:
474 // Reserve the inline buffer now even though we are unable to use it. This will avoid causing
475 // new stack overflows when this functionality is properly implemented in the future.
476 uint8 Buffer[InlineBufferSize];
477};
478
479///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ECbFieldType
FCbWriter(int64 InitialSize)
void AddObject(const FCbObjectView &Value)
TArray64< uint8 > Data
void BeginObject()
void BeginArray()
void AddObjectId(FUtf8StringView Name, const FCbObjectId &Value)
void AddString(FWideStringView Value)
void AddBinaryAttachment(FUtf8StringView Name, const FIoHash &Value)
void AddObject(FUtf8StringView Name, const FCbObject &Value)
void AddCustom(FUtf8StringView TypeName, FMemoryView Value)
FUtf8StringView GetActiveName() const
void AddNull()
void AddHash(const FIoHash &Value)
void AddArray(const FCbArrayView &Value)
uint64 GetSaveSize() const
void AddFloat(FUtf8StringView Name, double Value)
void BeginField()
void AddString(FUtf8StringView Value)
void BeginArray(FUtf8StringView Name)
void AddField(const FCbField &Value)
void AddBinary(FUtf8StringView Name, const void *Value, uint64 Size)
void AddBinary(FUtf8StringView Name, const FCompositeBuffer &Value)
void AddFloat(double Value)
void AddBinary(FUtf8StringView Name, const FSharedBuffer &Value)
void AddInteger(uint64 Value)
void AddAttachment(const FCbAttachment &Attachment)
void AddBinary(FUtf8StringView Name, FMemoryView Value)
void AddBool(bool bValue)
void Save(FArchive &Ar) const
void AddInteger(FUtf8StringView Name, uint64 Value)
FCbWriter(const FCbWriter &)=delete
void AddObjectAttachment(const FIoHash &Value)
void AddObject(const FCbObject &Value)
void SetNameOrAddString(FUtf8StringView NameOrValue)
void AddInteger(FUtf8StringView Name, int32 Value)
void AddDateTimeTicks(FUtf8StringView Name, int64 Ticks)
FCbWriter & operator=(const FCbWriter &)=delete
void AddBinaryAttachment(const FIoHash &Value)
void AddInteger(uint32 Value)
void Reset()
void AddField(FUtf8StringView Name, const FCbFieldView &Value)
void EndField(ECbFieldType Type)
FCbFieldIterator Save() const
void AddDateTimeTicks(int64 Ticks)
void AddUuid(FUtf8StringView Name, const FGuid &Value)
TArray< FState > States
void AddString(FUtf8StringView Name, FUtf8StringView Value)
void AddCustom(FUtf8StringView FieldName, FUtf8StringView TypeName, FMemoryView Value)
void AddBool(FUtf8StringView Name, bool bValue)
void AddFloat(FUtf8StringView Name, float Value)
void AddArray(const FCbArray &Value)
void AddBinary(const FSharedBuffer &Value)
void AddFloat(float Value)
void AddTimeSpanTicks(FUtf8StringView Name, int64 Ticks)
void AddField(FUtf8StringView Name, const FCbField &Value)
void AddInteger(int32 Value)
void BeginObject(FUtf8StringView Name)
void AddNull(FUtf8StringView Name)
void AddTimeSpan(FUtf8StringView Name, FTimespan Value)
void AddUuid(const FGuid &Value)
void AddTimeSpanTicks(int64 Ticks)
void AddHash(FUtf8StringView Name, const FIoHash &Value)
void AddCustom(uint64 TypeId, FMemoryView Value)
void AddObjectId(const FCbObjectId &Value)
void AddArray(FUtf8StringView Name, const FCbArray &Value)
void EndObject()
void AddInteger(int64 Value)
void AddDateTime(FUtf8StringView Name, FDateTime Value)
void EndArray()
void AddObjectAttachment(FUtf8StringView Name, const FIoHash &Value)
void AddInteger(FUtf8StringView Name, int64 Value)
void AddField(const FCbFieldView &Value)
void AddBinary(FMemoryView Value)
void AddCustom(FUtf8StringView FieldName, uint64 TypeId, FMemoryView Value)
FCbFieldViewIterator Save(FMutableMemoryView Buffer) const
void AddBinary(const void *Value, uint64 Size)
void AddInteger(FUtf8StringView Name, uint32 Value)
void AddString(FUtf8StringView Name, FWideStringView Value)
void AddDateTime(FDateTime Value)
void AddObject(FUtf8StringView Name, const FCbObjectView &Value)
void AddBinary(const FCompositeBuffer &Value)
void MakeFieldsUniform(int64 FieldBeginOffset, int64 FieldEndOffset)
void AddTimeSpan(FTimespan Value)
void AddArray(FUtf8StringView Name, const FCbArrayView &Value)
FCbWriter & SetName(FUtf8StringView Name)
void AddAttachment(FUtf8StringView Name, const FCbAttachment &Attachment)
uint8 Buffer[InlineBufferSize]
TCbWriter & operator=(const TCbWriter &)=delete
TCbWriter(const TCbWriter &)=delete
Definition Guid.h:108