struct
sA struct
will have a corresponding view class, and functions to create views.
Make
Struct
View
free functiontemplate <typename T> auto MakeStructView(/* view parameters, */ T *data, size_t size);
template <typename T> auto MakeStructView(/* view parameters, */ T *container);
Struct
will be replaced by the name of the specific struct
whose view will be constructed; for example, to make a view for struct Message
, call the MakeMessageView
function.
View parameters will be replaced by one argument for each parameter attached to the struct
. E.g., for:
struct Foo(x: UInt:8): --
MakeFooView
will be:
template <typename T> auto MakeFooView(std::uint8_t x, T *data, size_t size);
template <typename T> auto MakeFooView(std::uint8_t x, T *container);
And for:
struct Bar(x: UInt:8, y: Int:32): --
MakeBarView
will be:
template <typename T> auto MakeBarView(std::uint8_t x, std::int32_t y, T *data, size_t size);
template <typename T> auto MakeBarView(std::uint8_t x, std::int32_t y, T *container);
The Make
Struct
View
functions construct a view for Struct
over the given bytes. For the data/size form, the type T
must be a character type: char
, const char
, unsigned char
, const unsigned char
, signed char
, or const signed char
. For the container form, the container can be a std::vector
, std::array
, or std::basic_string
of a character type, or any other type with a data()
method that returns a possibly-const
char *
, signed char *
, or unsigned char *
, and a size()
method that returns a size in bytes. Google's absl::string_view
is one example of such a type.
If given a pointer to a const
character type or a const
reference to a container, Make
Struct
View
will return a read-only view; otherwise it will return a read-write view.
The result of Make
Struct
View
should be stored in an auto
variable:
auto view = MakeFooView(byte_buffer, available_byte_count);
The specific type returned by Make
Struct
View
is subject to change.
CopyFrom
methodtemplate <typename OtherStorage> void CopyFrom(GenericStructView<OtherStorage> other) const;
The CopyFrom
method copies data from the view other
into the current view. When complete, the current view‘s backing storage will contain the same bytes as other
. This works even if the view’s backing storage overlaps, in which case other
's backing storage is modified by the operation.
UncheckedCopyFrom
methodtemplate <typename OtherStorage> void UncheckedCopyFrom(GenericStructView<OtherStorage> other) const;
The UncheckedCopyFrom
method performs the same operation as CopyFrom
but without any checks on the integrity of or the compatibility of the two views.
TryToCopyFrom
methodtemplate <typename OtherStorage> bool TryToCopyFrom(GenericStructView<OtherStorage> other) const;
TryToCopyFrom
copies data from other
into the current view, if other
is Ok()
and the current backing storage is large enough to hold other
's data.
Equals
methodtemplate <typename OtherStorage> bool Equals(GenericStructView<OtherStorage> other);
The Equals
method returns true
if and only if itself and other
contain the same fields yielding equivalent values (as measured by the ==
operator). Equals()
should only be called if Ok()
is true on both views.
UncheckedEquals
methodtemplate <typename OtherStorage> bool UncheckedEquals(GenericStructView<OtherStorage> other);
The UncheckedEquals
method performs the same operation as Equals
, but without any checks on the integrity of or the compatibility of the two views when reading values. UncheckedEquals()
should only be called if Ok()
is true on both views.
Ok
methodbool Ok() const;
The Ok
method returns true
if and only if there are enough bytes in the backing store, and the Ok
methods of all active fields return true
.
IsComplete
methodbool IsComplete() const;
The IsComplete
method returns true
if there are enough bytes in the backing store to fully contain the struct
. If IsComplete()
returns true
but Ok()
returns false
, then the structure is broken in some way that cannot be fixed by adding more bytes.
IntrinsicSizeInBytes
methodauto IntrinsicSizeInBytes() const;
or
static constexpr auto IntrinsicSizeInBytes() const;
The IntrinsicSizeInBytes
method is the field method for $size_in_bytes
. The Read
method of the result returns the size of the struct
, and the Ok
method returns true
if the struct
's intrinsic size is known; i.e.:
if (view.IntrinsicSizeInBytes().Ok()) { // The exact return type of view.IntrinsicSizeInBytes().Read() may vary, but // it will always be implicitly convertible to std::uint64_t. std::uint64_t view_size = view.IntrinsicSizeInBytes().Read(); }
Alternately, if you are sure the size is known:
std::uint64_t view_size = view.IntrinsicSizeInBytes().UncheckedRead();
Or, if the size is a compile-time constant:
constexpr std::uint64_t view_size = StructView::IntrinsicSizeInBytes().Read(); constexpr std::uint64_t view_size2 = Struct::IntrinsicSizeInBytes();
MaxSizeInBytes
methodauto MaxSizeInBytes() const;
or
static constexpr auto MaxSizeInBytes() const;
The MaxSizeInBytes
method is the field method for $max_size_in_bytes
. The Read
method of the result returns the maximum size of the struct
, and the Ok
always method returns true
.
assert(view.MaxSizeInBytes().Ok()); // The exact return type of view.MaxSizeInBytes().Read() may vary, but it will // always be implicitly convertible to std::uint64_t. std::uint64_t view_size = view.MaxSizeInBytes().Read();
Alternately:
std::uint64_t view_size = view.MaxSizeInBytes().UncheckedRead();
Or:
constexpr std::uint64_t view_size = StructView::MaxSizeInBytes().Read(); constexpr std::uint64_t view_size2 = Struct::MaxSizeInBytes();
MinSizeInBytes
methodauto MinSizeInBytes() const;
or
static constexpr auto MinSizeInBytes() const;
The MinSizeInBytes
method is the field method for $min_size_in_bytes
. The Read
method of the result returns the minimum size of the struct
, and the Ok
always method returns true
.
assert(view.MinSizeInBytes().Ok()); // The exact return type of view.MinSizeInBytes().Read() may vary, but it will // always be implicitly convertible to std::uint64_t. std::uint64_t view_size = view.MinSizeInBytes().Read();
Alternately:
std::uint64_t view_size = view.MinSizeInBytes().UncheckedRead();
Or:
constexpr std::uint64_t view_size = StructView::MinSizeInBytes().Read(); constexpr std::uint64_t view_size2 = Struct::MinSizeInBytes();
SizeIsKnown
methodbool SizeIsKnown() const;
or
static constexpr bool SizeIsKnown() const;
The SizeIsKnown
method is an alias of IntrinsicSizeInBytes().Ok()
.
The SizeIsKnown
method returns true
if the size of the struct
can be determined from the bytes that are available. For example, consider a struct
like:
struct Message: 0 [+4] UInt payload_length (pl) 4 [+pl] UInt:8[pl] payload
The Message
‘s view’s SizeIsKnown
method will return true
if at least four bytes are available in the backing store, because it can determine the actual size of the message if at least four bytes can be read. If the backing store contains three or fewer bytes, then SizeIsKnown
will be false.
Note that if the struct
contains no dynamically-sized or dynamically-located fields, then SizeIsKnown
will be a static constexpr
method that always return true
.
SizeInBytes
methodstd::size_t SizeInBytes() const;
or
static constexpr std::size_t SizeInBytes() const;
The SizeInBytes
method returns static_cast<std::size_t>(IntrinsicSizeInBytes().Read())
.
The SizeInBytes
method returns the size of the struct
in bytes. SizeInBytes
asserts that SizeIsKnown()
, so applications should ensure that SizeIsKnown()
before calling SizeInBytes
.
If the struct
contains no dynamically-sized or dynamically-located fields, then SizeInBytes
will be a static constexpr
method, and can always be called safely.
UpdateFromTextStream
methodtemplate <class Stream> bool UpdateFromTextStream(Stream *stream) const;
UpdateFromTextStream
will read a text-format representation of the structure from the given stream
and update fields. Generally, applications would not call this directly; instead, use the global UpdateFromText
method, which handles setting up a stream from a std::string
.
WriteToTextStream
methodtemplate <class Stream> bool WriteToTextStream(Stream *stream, const TextOutputOptions &options) const;
WriteToTextStream
will write a text representation of the current value in a form that can be decoded by UpdateFromTextStream
. Generally, applications would not call this directly; instead, use the global WriteToString
method, which handles setting up the stream and returning the resulting string.
BackingStorage
methodStorage BackingStorage() const;
Returns the backing storage for the view. The return type of BackingStorage()
is a template parameter on the view.
Each physical field and virtual field in the struct
will have a corresponding method in the generated view for that struct
, which returns a subview of that field. For example, take the struct
definition:
struct Foo: 0 [+4] UInt bar 4 [+4] Int baz let qux = 2 * bar let bar_alias = bar
In this case, the generated code will have methods
auto bar() const; auto baz() const; auto qux() const; auto bar_alias() const;
The bar
method will return a UInt
view, and baz()
will return an Int
view. The qux
method will return a pseudo-UInt
view which can only be read. The bar_alias
method actually forwards to bar
, and can be both read and written:
auto foo_view = MakeFooView(&vector_of_foo_bytes); uint32_t bar_value = foo_view.bar().Read(); int32_t baz_value = foo_view.baz().Read(); int64_t qux_value = foo_view.qux().Read(); uint32_t bar_alias_value = foo_view.bar_alias().Read(); foo_view.bar_alias().Write(100); assert(foo_view.bar().Read() == 100);
As with Make
Struct
View
, the exact return type of field methods is subject to change; if a field's view must be stored, use an auto
variable.
Fields in anonymous bits
are treated as if they were fields of the enclosing struct
in the generated code. Take this struct
:
struct Foo: 0 [+4] bits: 5 [+5] UInt bar
In C++, bar
would be read like so:
auto foo_view = MakeFooView(&vector_of_foo_bytes); uint8_t bar_value = foo_view.bar().Read();
For each field, there is a has_
field
()
method, which returns an object. has_
methods are typically used for conditional fields. Suppose you have a struct
like:
struct Foo: 0 [+1] enum message_type: BAR = 1 if message_type == MessageType.BAR: 1 [+25] Bar bar
When you have a view of a Foo
, you can call foo_view.has_bar().Known()
to find out whether foo_view
has enough information to determine if the field bar
should exist. If it does .Known()
returns true
, you may call foo_view.has_bar().Value()
to find out if bar
should exist. You can also call foo_view.has_bar().ValueOr(false)
, which will return true
if bar
's status is known, and bar
exists.
Every field will have a corresponding has_
method. In the example above, foo_view.has_message_type().Known()
and foo_view.has_message_type().Value()
are both supported calls; both will always return true
.
Note that just because a field “exists,” that does not mean that it can be read from or written to the current message: the field's bytes might be missing, or present but contain a non-Ok()
value. You can use view.field().Ok()
to determine if the field can be read, and view.field().IsComplete()
to determine if the field can be written.
Virtual fields whose values are compile-time constants can be read without instantiating a view:
struct Foo: let register_number = 0xf8 0 [+4] UInt foo
// Foo::register_number() is a constexpr function. static_assert(Foo::register_number() == 0xf8);
field
().Ok()
vs field
().IsComplete()
vs has_
field
()
Emboss provides a number of methods to query different kinds of validity.
has_
field
()
is used for checking the existence condition specified in the .emb
file:
struct Foo: 0 [+1] UInt x if x < 10: 1 [+1] UInt y
In the .cc file:
::std::array<char, 2> bytes = { 5, 7 }; auto foo = MakeFooView(&bytes); assert(foo.x().Read() == 5); // foo.x() is readable, so the existence condition on y is known. assert(foo.has_y().Known()); // foo.x().Read() < 10, so y exists in foo. assert(foo.has_y().Value()); foo.x().Write(15); // foo.x().Read() >= 10, so y no longer exists in foo. assert(foo.has_y().Known()); assert(!foo.has_y().Value()); // foo.has_x() is always true, since x's existence condition is just "true". assert(foo.has_x().Known()); assert(foo.has_x().Value()); // incomplete_foo has 0 bytes of backing storage, so x is unreadable. auto incomplete_foo = MakeFooView(&bytes[0], 0); // incomplete_foo.has_x() is known, since it does not depend on anything. assert(incomplete_foo.has_x().Known()); assert(incomplete_foo.has_x().Value()); // incomplete_foo.x().Ok() is false, since x cannot be read. assert(!incomplete_foo.x().Ok()); // Since x cannot be read, incomplete_foo.has_y().Known() is false. assert(!incomplete_foo.has_y().Known()); // Since has_y() is not Known(), calling has_y().Value() will crash if Emboss // assertions are enabled. // incomplete_foo.has_y().Value() // Would crash // It is safe to call has_y().ValueOr(false). assert(!incomplete_foo.has_y().ValueOr(false));
has_
field
()
is notional: it queries whether field
should be present in the view. Even if has_
field
().Value()
is true
, field
().IsComplete()
and field
().Ok()
might return false
.
field
().IsComplete()
tests if there are enough bytes in the backing storage to hold field
. If field
().IsComplete()
, it is safe to call Write()
on the field with a valid value for that field. field
().Ok()
tests if there are enough bytes in the backing storage to hold field
, and that those bytes contain a valid value for field
:
struct Bar: 0 [+1] Bcd x 1 [+1] Bcd y
::std::array<char, 1> bytes = { 0xbb }; // Not a valid BCD number. auto bar = MakeBarView(&bytes); // There are enough bytes to read and write x. assert(bar.x().IsComplete()); // The value in x is not correct. assert(!bar.x().Ok()); // Read() would crash if assertions are enabled. // bar.x().Read(); // Writing a valid value is safe. bar.x().Write(99); assert(bar.x().Ok()); // Notionally, bar should have y, even though y's byte is not available: assert(bar.has_y().Value()); // Since there is no byte to read y from, y is not complete: assert(!bar.y().IsComplete());
Note that all views have Ok()
and IsComplete()
methods. A view of a structure is Ok()
if all of its fields are either Ok()
or not present, and has_
field
().Known()
is true
for all fields.
A structure view IsComplete()
if its SizeIsKnown()
and its backing storage contains at least SizeInBits()
or SizeInBytes()
bits or bytes. In other words: IsComplete()
is true if Emboss can determine that (just) adding more bytes to the view‘s backing storage won’t help. Note that just because IsComplete()
is false, that does not mean that adding more bytes will help. It is possible to define incoherent structures that will confuse Emboss, such as:
struct SizeNeverKnown: if false: 0 [+1] UInt x_loc x_loc [+1] UInt x
bits
ViewsThe code generated for a bits
construct is very similar to the code generated for a struct
. The primary differences are that there is no Make
Bits
View
function and that SizeInBytes
is replaced by SizeInBits
.
Ok
methodbool Ok() const;
The Ok
method returns true
if and only if there are enough bytes in the backing store, and the Ok
methods of all active fields return true
.
IsComplete
methodbool IsComplete() const;
The IsComplete
method returns true
if there are enough bytes in the backing store to fully contain the bits
. If IsComplete()
returns true
but Ok()
returns false
, then the structure is broken in some way that cannot be fixed by adding more bytes.
IntrinsicSizeInBits
methodauto IntrinsicSizeInBits() const;
or
static constexpr auto IntrinsicSizeInBits() const;
The IntrinsicSizeInBits
method is the field method for $size_in_bits
. The Read
method of the result returns the size of the struct
, and the Ok
method returns true
if the struct
's intrinsic size is known; i.e.:
if (view.IntrinsicSizeInBits().Ok()) { std::uint64_t view_size = view.IntrinsicSizeInBits().Read(); }
Since the intrinsic size of a bits
is always a compile-time constant:
constexpr std::uint64_t view_size = BitsView::IntrinsicSizeInBits().Read(); constexpr std::uint64_t view_size2 = Bits::IntrinsicSizeInBits();
MaxSizeInBits
methodauto MaxSizeInBits() const;
or
static constexpr auto MaxSizeInBits() const;
The MaxSizeInBits
method is the field method for $max_size_in_bits
. The Read
method of the result returns the maximum size of the bits
, and the Ok
always method returns true
.
assert(view.MaxSizeInBits().Ok()); // The exact return type of view.MaxSizeInBits().Read() may vary, but it will // always be implicitly convertible to std::uint64_t. std::uint64_t view_size = view.MaxSizeInBits().Read();
Alternately:
std::uint64_t view_size = view.MaxSizeInBits().UncheckedRead();
Or:
constexpr std::uint64_t view_size = StructView::MaxSizeInBits().Read(); constexpr std::uint64_t view_size2 = Struct::MaxSizeInBits();
MinSizeInBits
methodauto MinSizeInBits() const;
or
static constexpr auto MinSizeInBits() const;
The MinSizeInBits
method is the field method for $min_size_in_bits
. The Read
method of the result returns the minimum size of the bits
, and the Ok
always method returns true
.
assert(view.MinSizeInBits().Ok()); // The exact return type of view.MinSizeInBits().Read() may vary, but it will // always be implicitly convertible to std::uint64_t. std::uint64_t view_size = view.MinSizeInBits().Read();
Alternately:
std::uint64_t view_size = view.MinSizeInBits().UncheckedRead();
Or:
constexpr std::uint64_t view_size = StructView::MinSizeInBits().Read(); constexpr std::uint64_t view_size2 = Struct::MinSizeInBits();
SizeIsKnown
methodstatic constexpr bool SizeIsKnown() const;
For a bits
construct, SizeIsKnown()
always returns true
, because the size of a bits
construct is always statically known at compilation time.
SizeInBits
methodstatic constexpr std::size_t SizeInBits() const;
The SizeInBits
method returns the size of the bits
in bits. It is equivalent to static_cast<std::size_t>(IntrinsicSizeInBits().Read())
.
UpdateFromTextStream
methodtemplate <class Stream> bool UpdateFromTextStream(Stream *stream) const;
UpdateFromTextStream
will read a text-format representation of the structure from the given stream
and update fields. Generally, applications would not call this directly; instead, use the global UpdateFromText
method, which handles setting up a stream from a std::string
.
WriteToTextStream
methodtemplate <class Stream> bool WriteToTextStream(Stream *stream, const TextOutputOptions &options) const;
WriteToTextStream
will write a text representation of the current value in a form that can be decoded by UpdateFromTextStream
. Generally, applications would not call this directly; instead, use the global WriteToString
method, which handles setting up the stream and returning the resulting string.
As with struct
, each field in a bits
will have a corresponding method of the same name generated, and each such method will return a view of the given field. Take the module:
bits Bar: 0 [+12] UInt baz 31 [+1] Flag qux let two_baz = baz * 2 struct Foo: 0 [+4] Bar bar
In this case, the generated code in the Bar
view will have methods
auto baz() const; auto qux() const; auto two_baz() const;
The baz
method will return a UInt
view, and qux()
will return a Flag
view:
auto foo_view = MakeFooView(&vector_of_foo_bytes); uint16_t baz_value = foo_view.bar().baz().Read(); bool qux_value = foo_view.bar().qux().Read(); uint32_t two_baz_value = foo_view.bar().two_baz().Read();
The exact return type of field methods is subject to change; if a field's view must be stored, use an auto
variable.
enum
sFor each enum
in an .emb
, the Emboss compiler will generate a corresponding C++11-style enum class
. Take the following Emboss enum
:
enum Foo: BAR = 1 BAZ = 1000
Emboss will generate something equivalent to the following C++:
enum class Foo : uint64_t { BAR = 1, BAZ = 1000, };
Additionally, like other Emboss entities, enum
s have corresponding view classes.
TryToGetEnumFromName
free functionstatic inline bool TryToGetEnumFromName(const char *name, EnumType *result);
The TryToGetEnumFromName
function will try to match name
against the names in the Emboss enum
definition. If it finds an exact match, it will return true
and update result
with the corresponding enum value. If it does not find a match, it will return false
and leave result
unchanged.
Note that TryToGetNameFromEnum
will not match the text of the numeric value of an enum; given the Foo
enum above, TryToGetEnumFromName("1000", &my_foo)
would return false
.
TryToGetNameFromEnum
free functionstatic inline const char *TryToGetNameFromEnum(EnumType value);
TryToGetNameFromEnum
will attempt to find the textual name for the corresponding enum value. If a name is found, it will be returned; otherwise TryToGetEnumFromName
will return nullptr
. (Note that C++ enums are allowed to contain numeric values that are not explicitly listed in the enum definition, as long as they are in range for the underlying integral type.) If the given value has more than one name, the first name that appears in the Emboss definition will be returned.
Read
methodEnumType Read() const;
The Read
method reads the enum from the underlying bytes and returns its value as a C++ enum. Read
will assert that there are enough bytes to read. If the application cannot tolerate a failed assertion, it should first call Ok()
to ensure that it can safely read the enum. If performance is critical and the application can assure that there will always be enough bytes to read the enum, it can call UncheckedRead
instead.
UncheckedRead
methodEnumType UncheckedRead() const;
Like Read
, UncheckedRead
reads the enum from the underlying bytes and returns it value as a C++ enum. Unlike Read
, UncheckedRead
does not attempt to validate that there are enough bytes in the backing store to actually perform the read. In performance-critical situations, if the application is otherwise able to ensure that there are sufficient bytes in the backing store to read the enum, UncheckedRead
may be used.
Write
methodvoid Write(EnumType value) const;
Write
writes the value
into the backing store. Like Read
, Write
asserts that there are enough bytes in the backing store to safely write the enum. If the application cannot tolerate an assertion failure, it can use TryToWrite
or the combination of IsComplete
and CouldWriteValue
.
TryToWrite
methodbool TryToWrite(EnumType value) const;
TryToWrite
attempts to write the value
into the backing store. If the backing store does not have enough bytes to hold the enum field, or value
is too large for the specific enum field, then TryToWrite
will return false
and not update anything.
CouldWriteValue
methodstatic constexpr bool CouldWriteValue(EnumType value);
CouldWriteValue
returns true
if the given value
could be written into the enum field, assuming that there were enough bytes in the backing store to cover the field.
Although CouldWriteValue
is static constexpr
, it is tricky to call statically; client code that wishes to call it statically must use decltype
and declval
to get the specific type for the specific enum field in question.
UncheckedWrite
methodvoid UncheckedWrite(EnumType value) const;
Like Write
, UncheckedWrite
writes the given value to the backing store. Unlike Write
, UncheckedWrite
does not check that there are actually enough bytes in the backing store to safely write; it should only be used if the application has ensured that there are sufficient bytes in the backing store in some other way, and performance is a concern.
Ok
methodbool Ok() const;
Ok
returns true
if there are enough bytes in the backing store for the enum field to be read or written.
In the future, Emboss may add a “known values only” annotation to enum fields, in which case Ok
would also check that the given field contains a known value.
IsComplete
methodbool IsComplete() const;
IsComplete
returns true
if there are enough bytes in the backing store for the enum field to be read or written.
UpdateFromTextStream
methodtemplate <class Stream> bool UpdateFromTextStream(Stream *stream) const;
UpdateFromTextStream
will read a text-format representation of the enum from the given stream
and write it into the backing store. Generally, applications would not call this directly; instead, use the global UpdateFromText
method, which handles setting up a stream from a std::string
.
WriteToTextStream
methodtemplate <class Stream> bool WriteToTextStream(Stream *stream, const TextOutputOptions &options) const;
WriteToTextStream
will write a text representation of the current value in a form that can be decoded by UpdateFromTextStream
. Generally, applications would not call this directly; instead, use the global WriteToString
method, which handles setting up the stream and returning the resulting string.
operator[]
methodElementView operator[](size_t index) const;
The operator[]
method of an array view returns a view of the array element at index
.
begin()
/rbegin()
and end()
/rend()
methodsElementViewIterator<> begin(); ElementViewIterator<> end(); ElementViewIterator<> rbegin(); ElementViewIterator<> rend();
The begin()
and end()
methods of an array view returns view iterators to the beginning and past-the-end of the array, respectively. They may be used with arrays in range-based for loops, for example:
auto view = MakeArrayView(...); for(auto element : view){ int a = view.member().Read(); ... }
The rbegin()
and rend()
methods of an array view returns reverse view iterators to the end and element preceding the first, respectively.
SizeInBytes
or SizeInBits
methodsize_t SizeInBytes() const;
or
size_t SizeInBits() const;
Arrays in struct
s have the SizeInBytes
method; arrays in bits
have the SizeInBits
method. SizeInBytes
returns the size of the array in bytes; SizeInBits
returns the size of the array in bits.
ElementCount
methodsize_t ElementCount() const;
ElementCount
returns the number of elements in the array.
Ok
methodbool Ok() const;
Ok
returns true
if there are enough bytes in the backing store to hold the entire array, and every element's Ok
method returns true
.
IsComplete
methodbool IsComplete() const;
IsComplete
returns true
if there are sufficient bytes in the backing store to hold the entire array.
ToString
methodtemplate <class String> String ToString() const;
Intended usage:
// Makes a copy of view's backing storage. auto str = view.ToString<std::string>(); // Points to view's backing storage. auto str_view = view.ToString<std::string_view>();
ToString()
returns a string type constructed from the backing storage of the array. Note that ToString()
is only enabled for arrays of 1-byte values, such as UInt:8[]
, and only when the array view's underlying storage is contiguous.
Although it is intended for use with std::string
and std::string_view
, ToString()
can work with any C++ type that:
data()
method that returns a pointer to the string's underlying data as a char
type.const declval(data())
pointer and a size_t
length.UpdateFromTextStream
methodtemplate <class Stream> bool UpdateFromTextStream(Stream *stream) const;
UpdateFromTextStream
will read a text-format representation of the structure from the given stream
and update array elements. Generally, applications would not call this directly; instead, use the global UpdateFromText
method, which handles setting up a stream from a std::string
.
WriteToTextStream
methodtemplate <class Stream> bool WriteToTextStream(Stream *stream, const TextOutputOptions &options) const;
WriteToTextStream
will write a text representation of the current value in a form that can be decoded by UpdateFromTextStream
. Generally, applications would not call this directly; instead, use the global WriteToString
method, which handles setting up the stream and returning the resulting string.
BackingStorage
methodStorage BackingStorage() const;
Returns the backing storage for the view. The return type of BackingStorage()
is a template parameter on the view.
UInt
ValueType
using ValueType = ...;
The ValueType
type alias maps to the least-width C++ unsigned integer type that contains enough bits to hold any value of the given UInt
. For example:
UInt:32
's ValueType
would be uint32_t
UInt:64
's ValueType
would be uint64_t
UInt:12
's ValueType
would be uint16_t
UInt:2
's ValueType
would be uint8_t
The Read
and Write
families of methods use ValueType
to return or accept values, respectively.
Read
methodValueType Read() const;
The Read
method reads the UInt
from the underlying bytes and returns its value as a C++ unsigned integer type. Read
will assert that there are enough bytes to read. If the application cannot tolerate a failed assertion, it should first call Ok()
to ensure that it can safely read the UInt
. If performance is critical and the application can assure that there will always be enough bytes to read the UInt
, it can call UncheckedRead
instead.
UncheckedRead
methodValueType UncheckedRead();
Like Read
, UncheckedRead
reads the UInt
from the underlying bytes and returns it value as a C++ unsigned integer type. Unlike Read
, UncheckedRead
does not attempt to validate that there are enough bytes in the backing store to actually perform the read. In performance-critical situations, if the application is otherwise able to ensure that there are sufficient bytes in the backing store to read the UInt
, UncheckedRead
may be used.
Write
methodvoid Write(ValueType value);
Write
writes the value
into the backing store. Like Read
, Write
asserts that there are enough bytes in the backing store to safely write the UInt
. If the application cannot tolerate an assertion failure, it can use TryToWrite
or the combination of IsComplete
and CouldWriteValue
.
TryToWrite
methodbool TryToWrite(ValueType value);
TryToWrite
attempts to write the value
into the backing store. If the backing store does not have enough bytes to hold the UInt
field, or value
is too large for the UInt
field, then TryToWrite
will return false
and not update anything.
CouldWriteValue
methodstatic constexpr bool CouldWriteValue(ValueType value);
CouldWriteValue
returns true
if the given value
could be written into the UInt
field, assuming that there were enough bytes in the backing store to cover the field.
Although CouldWriteValue
is static constexpr
, it is tricky to call statically; client code that wishes to call it statically must use decltype
and declval
to get the specific type for the specific UInt
field in question.
UncheckedWrite
methodvoid UncheckedWrite(ValueType value);
Like Write
, UncheckedWrite
writes the given value to the backing store. Unlike Write
, UncheckedWrite
does not check that there are actually enough bytes in the backing store to safely write; it should only be used if the application has ensured that there are sufficient bytes in the backing store in some other way, and performance is a concern.
Ok
methodbool Ok() const;
The Ok
method returns true
if there are enough bytes in the backing store to hold the given UInt
field.
IsComplete
methodbool IsComplete();
The IsComplete
method returns true
if there are enough bytes in the backing store to hold the given UInt
field.
UpdateFromTextStream
methodtemplate <class Stream> bool UpdateFromTextStream(Stream *stream) const;
UpdateFromTextStream
will read a text-format representation of the UInt
from the given stream
and update fields. Generally, applications would not call this directly; instead, use the global UpdateFromText
method, which handles setting up a stream from a std::string
.
WriteToTextStream
methodtemplate <class Stream> bool WriteToTextStream(Stream *stream, const TextOutputOptions &options) const;
WriteToTextStream
will write a text representation of the current value in a form that can be decoded by UpdateFromTextStream
. Generally, applications would not call this directly; instead, use the global WriteToString
method, which handles setting up the stream and returning the resulting string.
SizeInBits
methodstatic constexpr int SizeInBits();
The SizeInBits
method returns the size of this specific UInt
field, in bits.
Int
ValueType
using ValueType = ...;
The ValueType
type alias maps to the least-width C++ signed integer type that contains enough bits to hold any value of the given Int
. For example:
Int:32
's ValueType
would be int32_t
Int:64
's ValueType
would be int64_t
Int:12
's ValueType
would be int16_t
Int:2
's ValueType
would be int8_t
The Read
and Write
families of methods use ValueType
to return or accept values, respectively.
Read
methodValueType Read() const;
The Read
method reads the Int
from the underlying bytes and returns its value as a C++ signed integer type. Read
will assert that there are enough bytes to read. If the application cannot tolerate a failed assertion, it should first call Ok()
to ensure that it can safely read the Int
. If performance is critical and the application can assure that there will always be enough bytes to read the Int
, it can call UncheckedRead
instead.
UncheckedRead
methodValueType UncheckedRead();
Like Read
, UncheckedRead
reads the Int
from the underlying bytes and returns it value as a C++ signed integer type. Unlike Read
, UncheckedRead
does not attempt to validate that there are enough bytes in the backing store to actually perform the read. In performance-critical situations, if the application is otherwise able to ensure that there are sufficient bytes in the backing store to read the Int
, UncheckedRead
may be used.
Write
methodvoid Write(ValueType value);
Write
writes the value
into the backing store. Like Read
, Write
asserts that there are enough bytes in the backing store to safely write the Int
. If the application cannot tolerate an assertion failure, it can use TryToWrite
or the combination of IsComplete
and CouldWriteValue
.
TryToWrite
methodbool TryToWrite(ValueType value);
TryToWrite
attempts to write the value
into the backing store. If the backing store does not have enough bytes to hold the Int
field, or value
is too large for the Int
field, then TryToWrite
will return false
and not update anything.
CouldWriteValue
methodstatic constexpr bool CouldWriteValue(ValueType value);
CouldWriteValue
returns true
if the given value
could be written into the Int
field, assuming that there were enough bytes in the backing store to cover the field.
Although CouldWriteValue
is static constexpr
, it is tricky to call statically; client code that wishes to call it statically must use decltype
and declval
to get the specific type for the specific Int
field in question.
UncheckedWrite
methodvoid UncheckedWrite(ValueType value);
Like Write
, UncheckedWrite
writes the given value to the backing store. Unlike Write
, UncheckedWrite
does not check that there are actually enough bytes in the backing store to safely write; it should only be used if the application has ensured that there are sufficient bytes in the backing store in some other way, and performance is a concern.
Ok
methodbool Ok() const;
The Ok
method returns true
if there are enough bytes in the backing store to hold the given Int
field.
IsComplete
methodbool IsComplete();
The IsComplete
method returns true
if there are enough bytes in the backing store to hold the given Int
field.
UpdateFromTextStream
methodtemplate <class Stream> bool UpdateFromTextStream(Stream *stream) const;
UpdateFromTextStream
will read a text-format representation of the Int
from the given stream
and update fields. Generally, applications would not call this directly; instead, use the global UpdateFromText
method, which handles setting up a stream from a std::string
.
WriteToTextStream
methodtemplate <class Stream> bool WriteToTextStream(Stream *stream, const TextOutputOptions &options) const;
WriteToTextStream
will write a text representation of the current value in a form that can be decoded by UpdateFromTextStream
. Generally, applications would not call this directly; instead, use the global WriteToString
method, which handles setting up the stream and returning the resulting string.
SizeInBits
methodstatic constexpr int SizeInBits();
The SizeInBits
method returns the size of this specific Int
field, in bits.
Bcd
ValueType
using ValueType = ...;
The ValueType
type alias maps to a C++ unsigned integer type that contains at least enough bits to hold any value of the given Bcd
. For example:
Bcd:32
's ValueType
would be uint32_t
Bcd:64
's ValueType
would be uint64_t
Bcd:12
's ValueType
would be uint16_t
Bcd:2
's ValueType
would be uint8_t
The Read
and Write
families of methods use ValueType
to return or accept values, respectively.
Read
methodValueType Read() const;
The Read
method reads the Bcd
from the underlying bytes and returns its value as a C++ unsigned integer type. Read
will assert that there are enough bytes to read, and that the binary representation is a valid BCD integer. If the application cannot tolerate a failed assertion, it should first call Ok()
to ensure that it can safely read the Bcd
. If performance is critical and the application can assure that there will always be enough bytes to read the Bcd
, and that the bytes will be a valid BCD value, it can call UncheckedRead
instead.
UncheckedRead
methodValueType UncheckedRead();
Like Read
, UncheckedRead
reads the Bcd
from the underlying bytes and returns it value as a C++ unsigned integer type. Unlike Read
, UncheckedRead
does not attempt to validate that there are enough bytes in the backing store to actually perform the read, nor that the bytes contain an actual BCD number. In performance-critical situations, if the application is otherwise able to ensure that there are sufficient bytes in the backing store to read the Bcd
, UncheckedRead
may be used.
Write
methodvoid Write(ValueType value);
Write
writes the value
into the backing store. Like Read
, Write
asserts that there are enough bytes in the backing store to safely write the Bcd
. If the application cannot tolerate an assertion failure, it can use TryToWrite
or the combination of IsComplete
and CouldWriteValue
.
TryToWrite
methodbool TryToWrite(ValueType value);
TryToWrite
attempts to write the value
into the backing store. If the backing store does not have enough bytes to hold the Bcd
field, or value
is too large for the Bcd
field, then TryToWrite
will return false
and not update anything.
CouldWriteValue
methodstatic constexpr bool CouldWriteValue(ValueType value);
CouldWriteValue
returns true
if the given value
could be written into the Bcd
field, assuming that there were enough bytes in the backing store to cover the field.
Although CouldWriteValue
is static constexpr
, it is tricky to call statically; client code that wishes to call it statically must use decltype
and declval
to get the specific type for the specific Bcd
field in question.
UncheckedWrite
methodvoid UncheckedWrite(ValueType value);
Like Write
, UncheckedWrite
writes the given value to the backing store. Unlike Write
, UncheckedWrite
does not check that there are actually enough bytes in the backing store to safely write; it should only be used if the application has ensured that there are sufficient bytes in the backing store in some other way, and performance is a concern.
Ok
methodbool Ok() const;
The Ok
method returns true
if there are enough bytes in the backing store to hold the given Bcd
field, and the bytes contain a valid BCD number: that is, that every nibble in the backing store contains a value between 0 and 9, inclusive.
IsComplete
methodbool IsComplete();
The IsComplete
method returns true
if there are enough bytes in the backing store to hold the given Bcd
field.
UpdateFromTextStream
methodtemplate <class Stream> bool UpdateFromTextStream(Stream *stream) const;
UpdateFromTextStream
will read a text-format representation of the Bcd
from the given stream
and update fields. Generally, applications would not call this directly; instead, use the global UpdateFromText
method, which handles setting up a stream from a std::string
.
WriteToTextStream
methodtemplate <class Stream> bool WriteToTextStream(Stream *stream, const TextOutputOptions &options) const;
WriteToTextStream
will write a text representation of the current value in a form that can be decoded by UpdateFromTextStream
. Generally, applications would not call this directly; instead, use the global WriteToString
method, which handles setting up the stream and returning the resulting string.
SizeInBits
methodstatic constexpr int SizeInBits();
The SizeInBits
method returns the size of this specific Bcd
field, in bits.
Flag
Read
methodbool Read() const;
The Read
method reads the Flag
from the underlying bit and returns its value as a C++ bool
. Read
will assert that the underlying bit is in the backing store. If the application cannot tolerate a failed assertion, it should first call Ok()
to ensure that it can safely read the Flag
. If performance is critical and the application can assure that there will always be enough bytes to read the Flag
, it can call UncheckedRead
instead.
UncheckedRead
methodbool UncheckedRead();
Like Read
, UncheckedRead
reads the Flag
from the underlying bit and returns it value as a C++ bool. Unlike Read
, UncheckedRead
does not attempt to validate that the backing bit is actually in the backing store. In performance-critical situations, if the application is otherwise able to ensure that there are sufficient bytes in the backing store to read the Flag
, UncheckedRead
may be used.
Write
methodvoid Write(bool value);
Write
writes the value
into the backing store. Like Read
, Write
asserts that there are enough bytes in the backing store to safely write the Flag
. If the application cannot tolerate an assertion failure, it can use TryToWrite
or the combination of IsComplete
and CouldWriteValue
.
TryToWrite
methodbool TryToWrite(bool value);
TryToWrite
attempts to write the value
into the backing store. If the backing store does not contain the Flag
's bit, then TryToWrite
will return false
and not update anything.
CouldWriteValue
methodstatic constexpr bool CouldWriteValue(bool value);
CouldWriteValue
returns true
, as both C++ bool
values can be written to any Flag
.
UncheckedWrite
methodvoid UncheckedWrite(ValueType value);
Like Write
, UncheckedWrite
writes the given value to the backing store. Unlike Write
, UncheckedWrite
does not check that there are actually enough bytes in the backing store to safely write; it should only be used if the application has ensured that there are sufficient bytes in the backing store in some other way, and performance is a concern.
Ok
methodbool Ok() const;
The Ok
method returns true
if the backing store contains the Flag
's bit.
IsComplete
methodbool IsComplete();
The IsComplete
method returns true
if the backing store contains the Flag
's bit.
UpdateFromTextStream
methodtemplate <class Stream> bool UpdateFromTextStream(Stream *stream) const;
UpdateFromTextStream
will read a text-format representation of the Flag
from the given stream
and update fields. Generally, applications would not call this directly; instead, use the global UpdateFromText
method, which handles setting up a stream from a std::string
.
WriteToTextStream
methodtemplate <class Stream> bool WriteToTextStream(Stream *stream, const TextOutputOptions &options) const;
WriteToTextStream
will write a text representation of the current value in a form that can be decoded by UpdateFromTextStream
. Generally, applications would not call this directly; instead, use the global WriteToString
method, which handles setting up the stream and returning the resulting string.
Float
ValueType
using ValueType = ...;
The ValueType
type alias maps to the C++ floating-point type that matches the Float
field's type; generally float
for 32-bit Float
s and double
for 64-bit Float
s.
The Read
and Write
families of methods use ValueType
to return or accept values, respectively.
Read
methodValueType Read() const;
The Read
method reads the Float
from the underlying bytes and returns its value as a C++ floating point type. Read
will assert that there are enough bytes to read. If the application cannot tolerate a failed assertion, it should first call Ok()
to ensure that it can safely read the Float
. If performance is critical and the application can assure that there will always be enough bytes to read the Float
, it can call UncheckedRead
instead.
UncheckedRead
methodValueType UncheckedRead();
Like Read
, UncheckedRead
reads the Float
from the underlying bytes and returns it value as a C++ floating point type. Unlike Read
, UncheckedRead
does not attempt to validate that there are enough bytes in the backing store to actually perform the read. In performance-critical situations, if the application is otherwise able to ensure that there are sufficient bytes in the backing store to read the Float
, UncheckedRead
may be used.
Write
methodvoid Write(ValueType value);
Write
writes the value
into the backing store. Like Read
, Write
asserts that there are enough bytes in the backing store to safely write the Float
. If the application cannot tolerate an assertion failure, it can use TryToWrite
or the combination of IsComplete
and CouldWriteValue
.
TryToWrite
methodbool TryToWrite(ValueType value);
TryToWrite
attempts to write the value
into the backing store. If the backing store does not have enough bytes to hold the Float
field, then TryToWrite
will return false
and not update anything.
CouldWriteValue
methodstatic constexpr bool CouldWriteValue(ValueType value);
CouldWriteValue
returns true
.
UncheckedWrite
methodvoid UncheckedWrite(ValueType value);
Like Write
, UncheckedWrite
writes the given value to the backing store. Unlike Write
, UncheckedWrite
does not check that there are actually enough bytes in the backing store to safely write; it should only be used if the application has ensured that there are sufficient bytes in the backing store in some other way, and performance is a concern.
Ok
methodbool Ok() const;
The Ok
method returns true
if there are enough bytes in the backing store to hold the given Float
field.
IsComplete
methodbool IsComplete();
The IsComplete
method returns true
if there are enough bytes in the backing store to hold the given Float
field.
UpdateFromTextStream
methodtemplate <class Stream> bool UpdateFromTextStream(Stream *stream) const;
UpdateFromTextStream
will read a text-format representation of the Float
from the given stream
and update fields. Generally, applications would not call this directly; instead, use the global UpdateFromText
method, which handles setting up a stream from a std::string
.
Note: this method is not yet implemented.
WriteToTextStream
methodtemplate <class Stream> bool WriteToTextStream(Stream *stream, const TextOutputOptions &options) const;
WriteToTextStream
will write a text representation of the current value in a form that can be decoded by UpdateFromTextStream
. Generally, applications would not call this directly; instead, use the global WriteToString
method, which handles setting up the stream and returning the resulting string.
Note: this method is not yet implemented.
::emboss::UpdateFromText
functiontemplate <typename EmbossViewType> bool UpdateFromText(EmbossViewType view, const ::std::string &text) const;
The ::emboss::UpdateFromText
function constructs an appropriate text strem object from the given text
and calls view
's UpdateFromTextStream
method. This is the preferred way to read Emboss text format in C++.
::emboss::WriteToString
functiontemplate <typename EmbossViewType> ::std::string WriteToString(EmbossViewType view); template <typename EmbossViewType> ::std::string WriteToString(EmbossViewType view, TextOutputOptions options);
The ::emboss::WriteToString
function constructs a string stream, passes it into the view
's WriteToTextStream
method, and finally returns the text format of the view
.
The single-argument form WriteToString(view)
will return a single line of text. For more readable output, WriteToString(view, ::emboss::MultilineText())
should help.
::emboss::TextOutputOptions
classThe TextOutputOptions
is used to set options for text output, such as numeric base, whether or not to use multiple lines, etc.
PlusOneIndent
methodTextOutputOptions PlusOneIndent() const;
PlusOneIndent
returns a new TextOutputOptions
with one more level of indentation than the current TextOutputOptions
. This is primarily intended for use inside of WriteToTextStream
methods, as a way to get an indented TextOutputOptions
to pass to the WriteToTextStream
methods of child objects. However, application callers may use PlusOneIndent()
, possibly multiple times, to indent the entire output.
Multiline
methodTextOutputOptions Multiline(bool new_value) const;
Returns a new TextOutputOptions
with the same options as the current TextOutputOptions
, except for a new value for multiline()
.
WithIndent
methodTextOutputOptions WithIndent(::std::string new_value) const;
Returns a new TextOutputOptions
with the same options as the current TextOutputOptions
, except for a new value for indent()
.
WithComments
methodTextOutputOptions WithComments(bool new_value) const;
Returns a new TextOutputOptions
with the same options as the current TextOutputOptions
, except for a new value for comments()
.
WithDigitGrouping
methodTextOutputOptions WithDigitGrouping(bool new_value) const;
Returns a new TextOutputOptions
with the same options as the current TextOutputOptions
, except for a new value for digit_grouping()
.
WithNumericBase
methodTextOutputOptions WithNumericBase(int new_value) const;
Returns a new TextOutputOptions
with the same options as the current TextOutputOptions
, except for a new value for digit_grouping()
. The new numeric base should be 2, 10, or 16.
WithAllowPartialOutput
methodTextOutputOptions WithAllowPartialOutput(bool new_value) const;
Returns a new TextOutputOptions
with the same options as the current TextOutputOptions
, except for a new value for allow_partial_output()
.
current_indent
method::std::string current_indent() const; // Default "".
Returns the current indent string.
indent
method::std::string indent() const; // Default " ".
Returns the indent string. The indent string is the string used for a single level of indentation.
multiline
methodbool multiline() const; // Default false.
Returns true
if text output should use multiple lines, or false
if text output should be single-line only.
digit_grouping
methodbool digit_grouping() const; // Default false.
Returns true
if text output should include digit separators on numbers; i.e. 1_000_000
instead of 1000000
.
comments
methodbool comments() const; // Default false.
Returns true
if text output should include comments, e.g., to show numbers in multiple bases.
numeric_base
methoduint8_t numeric_base() const; // Default 10.
Returns the numeric base that should be used for formatting numbers. This should always be 2, 10, or 16.
allow_partial_output
methodbool allow_partial_output() const; // Default false.
Returns true
if text output should attempt to extract fields from a view that is not Ok()
. If so:
WriteToString()
or WriteToTextStream()
should never CHECK
-fail.Int
, UInt
, enum
, Flag
, etc. types) will not be written to the text stream if they cannot be read.comments()
is also true
, unreadable atomic fields will be commented in the text stream.struct
, bits
, or arrays) will be written, but may be missing fields or entirely empty if they have non-Ok()
members.