blob: 4541bdb1196f1995d35a402a28f1cd022b07702b [file] [log] [blame]
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -*- mode: C++ -*-
// vim: set filetype=cpp:
// Fragments of C++ code used by the Emboss C++ code generator. Anything before
// the first template is ignored. The names between ** ** are used as template
// names. See code_template.py for more details. Local variable names are
// prefixed with `emboss_reserved_local_` to avoid conflicting with struct field
// names.
// ** outline ** ///////////////////////////////////////////////////////////////
// Generated by the Emboss compiler. DO NOT EDIT!
#ifndef $_header_guard_$
#define $_header_guard_$
#include <stdint.h>
#include <string.h>
#include <algorithm>
#include <ostream>
#include <type_traits>
#include <utility>
#include "runtime/cpp/emboss_cpp_util.h"
$_includes_$
$_body_$
#endif // $_header_guard_$
// ** include ** ///////////////////////////////////////////////////////////////
#include "$_file_name_$"
// ** body ** //////////////////////////////////////////////////////////////////
$_type_declarations_$
$_type_definitions_$
$_method_definitions_$
// ** namespace_wrap ** ////////////////////////////////////////////////////////
namespace $_component_$ {
$_body_$
} // namespace $_component_$
// ** structure_view_declaration ** ////////////////////////////////////////////
template <class Storage>
class Generic$_name_$View;
// ** structure_view_class ** //////////////////////////////////////////////////
template <class View>
struct EmbossReservedInternalIsGeneric$_name_$View;
template <class Storage>
class Generic$_name_$View final {
public:
Generic$_name_$View() : backing_() {}
explicit Generic$_name_$View(
$_constructor_parameters_$ Storage emboss_reserved_local_bytes)
: backing_(emboss_reserved_local_bytes) $_parameter_initializers_$
$_initialize_parameters_initialized_true_$ {}
// Views over compatible backing storage should be freely assignable.
template <typename OtherStorage>
Generic$_name_$View(
const Generic$_name_$View<OtherStorage> &emboss_reserved_local_other)
: backing_{emboss_reserved_local_other.BackingStorage()}
$_parameter_copy_initializers_$ {}
// Allow pass-through construction of backing_, but only if there is at least
// one argument, and, if exactly one argument, that argument is not a
// (possibly c/v/ref-qualified) Generic$_name_$View.
//
// Explicitly ruling out overloads that might match the copy or move
// constructor is necessary in order for the copy and move constructors to be
// reliably found during overload resolution.
template <typename Arg,
typename = typename ::std::enable_if<
!EmbossReservedInternalIsGeneric$_name_$View<
typename ::std::remove_cv<typename ::std::remove_reference<
Arg>::type>::type>::value>::type>
explicit Generic$_name_$View(
$_constructor_parameters_$ Arg &&emboss_reserved_local_arg)
: backing_(::std::forward<Arg>(
emboss_reserved_local_arg)) $_parameter_initializers_$
$_initialize_parameters_initialized_true_$ {}
template <typename Arg0, typename Arg1, typename... Args>
explicit Generic$_name_$View(
$_constructor_parameters_$ Arg0 &&emboss_reserved_local_arg0,
Arg1 &&emboss_reserved_local_arg1, Args &&... emboss_reserved_local_args)
: backing_(::std::forward<Arg0>(emboss_reserved_local_arg0),
::std::forward<Arg1>(emboss_reserved_local_arg1),
::std::forward<Args>(
emboss_reserved_local_args)...) $_parameter_initializers_$
$_initialize_parameters_initialized_true_$ {}
template <typename OtherStorage>
Generic$_name_$View<Storage> &operator=(
const Generic$_name_$View<OtherStorage> &emboss_reserved_local_other) {
backing_ = emboss_reserved_local_other.BackingStorage();
return *this;
}
$_enum_usings_$
bool Ok() const {
if (!IsComplete()) return false;
$_parameter_ok_checks_$
$_field_ok_checks_$
$_requires_check_$
return true;
}
Storage BackingStorage() const { return backing_; }
bool IsComplete() const {
return backing_.Ok() && IntrinsicSizeIn$_units_$().Ok() &&
backing_.SizeIn$_units_$() >=
static_cast</**/ ::std::size_t>(
IntrinsicSizeIn$_units_$().UncheckedRead());
}
$_size_method_$
template <typename OtherStorage>
bool Equals(
Generic$_name_$View<OtherStorage> emboss_reserved_local_other) const {
$_equals_method_body_$ return true;
}
template <typename OtherStorage>
bool UncheckedEquals(
Generic$_name_$View<OtherStorage> emboss_reserved_local_other) const {
$_unchecked_equals_method_body_$ return true;
}
// (Unchecked)CopyFrom copies the number of bytes included in the other view,
// and ignores the size of the current view. Even if they differ before
// copying, the destination view's size should match the source view's size
// after copying, because any fields used in the calculation of the
// destination view's size should be updated by the copy.
template <typename OtherStorage>
void UncheckedCopyFrom(
Generic$_name_$View<OtherStorage> emboss_reserved_local_other) const {
backing_.UncheckedCopyFrom(
emboss_reserved_local_other.BackingStorage(),
emboss_reserved_local_other.IntrinsicSizeIn$_units_$().UncheckedRead());
}
template <typename OtherStorage>
void CopyFrom(
Generic$_name_$View<OtherStorage> emboss_reserved_local_other) const {
backing_.CopyFrom(
emboss_reserved_local_other.BackingStorage(),
emboss_reserved_local_other.IntrinsicSizeIn$_units_$().Read());
}
template <typename OtherStorage>
bool TryToCopyFrom(
Generic$_name_$View<OtherStorage> emboss_reserved_local_other) const {
return emboss_reserved_local_other.Ok() && backing_.TryToCopyFrom(
emboss_reserved_local_other.BackingStorage(),
emboss_reserved_local_other.IntrinsicSizeIn$_units_$().Read());
}
template <class Stream>
bool UpdateFromTextStream(Stream *emboss_reserved_local_stream) const {
::std::string emboss_reserved_local_brace;
if (!::emboss::support::ReadToken(emboss_reserved_local_stream,
&emboss_reserved_local_brace))
return false;
if (emboss_reserved_local_brace != "{") return false;
for (;;) {
::std::string emboss_reserved_local_name;
if (!::emboss::support::ReadToken(emboss_reserved_local_stream,
&emboss_reserved_local_name))
return false;
if (emboss_reserved_local_name == ",")
if (!::emboss::support::ReadToken(emboss_reserved_local_stream,
&emboss_reserved_local_name))
return false;
if (emboss_reserved_local_name == "}") return true;
::std::string emboss_reserved_local_colon;
if (!::emboss::support::ReadToken(emboss_reserved_local_stream,
&emboss_reserved_local_colon))
return false;
if (emboss_reserved_local_colon != ":") return false;
$_decode_fields_$
// decode_fields will `continue` if it successfully finds a field.
return false;
}
}
template <class Stream>
void WriteToTextStream(
Stream *emboss_reserved_local_stream,
::emboss::TextOutputOptions emboss_reserved_local_options) const {
::emboss::TextOutputOptions emboss_reserved_local_field_options =
emboss_reserved_local_options.PlusOneIndent();
if (emboss_reserved_local_options.multiline()) {
emboss_reserved_local_stream->Write("{\n");
} else {
emboss_reserved_local_stream->Write("{");
}
bool emboss_reserved_local_wrote_field = false;
$_write_fields_$
// Avoid unused variable warnings for empty structures:
(void)emboss_reserved_local_wrote_field;
if (emboss_reserved_local_options.multiline()) {
emboss_reserved_local_stream->Write(
emboss_reserved_local_options.current_indent());
emboss_reserved_local_stream->Write("}");
} else {
emboss_reserved_local_stream->Write(" }");
}
}
static constexpr bool IsAggregate() { return true; }
$_field_method_declarations_$
private:
Storage backing_;
$_parameter_fields_$
$_parameters_initialized_flag_$
// This is a bit of a hack to handle Equals() and UncheckedEquals() between
// views with different underlying storage -- otherwise, structs with
// anonymous members run into access violations.
//
// TODO(bolms): Revisit this once the special-case code for anonymous members
// is replaced by explicit read/write virtual fields in the IR.
template <class OtherStorage>
friend class Generic$_name_$View;
};
using $_name_$View =
Generic$_name_$View</**/ ::emboss::support::ReadOnlyContiguousBuffer>;
using $_name_$Writer =
Generic$_name_$View</**/ ::emboss::support::ReadWriteContiguousBuffer>;
template <class View>
struct EmbossReservedInternalIsGeneric$_name_$View {
static constexpr const bool value = false;
};
template <class Storage>
struct EmbossReservedInternalIsGeneric$_name_$View<
Generic$_name_$View<Storage>> {
static constexpr const bool value = true;
};
template <typename T>
inline Generic$_name_$View<
/**/ ::emboss::support::ContiguousBuffer<
typename ::std::remove_reference<
decltype(*::std::declval<T>()->data())>::type,
1, 0>>
Make$_name_$View($_constructor_parameters_$ T &&emboss_reserved_local_arg) {
return Generic$_name_$View<
/**/ ::emboss::support::ContiguousBuffer<
typename ::std::remove_reference<decltype(
*::std::declval<T>()->data())>::type,
1, 0>>(
$_forwarded_parameters_$ ::std::forward<T>(emboss_reserved_local_arg));
}
template <typename T>
inline Generic$_name_$View</**/ ::emboss::support::ContiguousBuffer<T, 1, 0>>
Make$_name_$View($_constructor_parameters_$ T *emboss_reserved_local_data,
::std::size_t emboss_reserved_local_size) {
return Generic$_name_$View</**/ ::emboss::support::ContiguousBuffer<T, 1, 0>>(
$_forwarded_parameters_$ emboss_reserved_local_data,
emboss_reserved_local_size);
}
template <typename T, ::std::size_t kAlignment>
inline Generic$_name_$View<
/**/ ::emboss::support::ContiguousBuffer<T, kAlignment, 0>>
MakeAligned$_name_$View(
$_constructor_parameters_$ T *emboss_reserved_local_data,
::std::size_t emboss_reserved_local_size) {
return Generic$_name_$View<
/**/ ::emboss::support::ContiguousBuffer<T, kAlignment, 0>>(
$_forwarded_parameters_$ emboss_reserved_local_data,
emboss_reserved_local_size);
}
// ** decode_field ** //////////////////////////////////////////////////////////
// If the field name matches $_field_name_$, handle it, otherwise fall
// through to the next field.
if (emboss_reserved_local_name == "$_field_name_$") {
// TODO(bolms): How should missing optional fields be handled?
if (!$_field_name_$().UpdateFromTextStream(
emboss_reserved_local_stream)) {
return false;
}
continue;
}
// ** write_field_to_text_stream ** ////////////////////////////////////////////
if (has_$_field_name_$().ValueOr(false)) {
// Don't try to read the field if `allow_partial_output` is set and the
// field can't be `Read()`. Aggregates should still be visited, even if
// they are not `Ok()` overall, since submembers may still be `Ok()`.
if (!emboss_reserved_local_field_options.allow_partial_output() ||
$_field_name_$().IsAggregate() || $_field_name_$().Ok()) {
if (emboss_reserved_local_field_options.multiline()) {
emboss_reserved_local_stream->Write(
emboss_reserved_local_field_options.current_indent());
} else {
if (emboss_reserved_local_wrote_field) {
emboss_reserved_local_stream->Write(",");
}
emboss_reserved_local_stream->Write(" ");
}
emboss_reserved_local_stream->Write("$_field_name_$: ");
$_field_name_$().WriteToTextStream(emboss_reserved_local_stream,
emboss_reserved_local_field_options);
emboss_reserved_local_wrote_field = true;
if (emboss_reserved_local_field_options.multiline()) {
emboss_reserved_local_stream->Write("\n");
}
} else if (emboss_reserved_local_field_options.allow_partial_output() &&
emboss_reserved_local_field_options.comments() &&
!$_field_name_$().IsAggregate() && !$_field_name_$().Ok()) {
if (emboss_reserved_local_field_options.multiline()) {
emboss_reserved_local_stream->Write(
emboss_reserved_local_field_options.current_indent());
}
emboss_reserved_local_stream->Write("# $_field_name_$: UNREADABLE\n");
}
}
// ** write_read_only_field_to_text_stream ** //////////////////////////////////
if (has_$_field_name_$().ValueOr(false) &&
emboss_reserved_local_field_options.comments()) {
if (!emboss_reserved_local_field_options.allow_partial_output() ||
$_field_name_$().IsAggregate() || $_field_name_$().Ok()) {
emboss_reserved_local_stream->Write(
emboss_reserved_local_field_options.current_indent());
// TODO(bolms): When there are multiline read-only fields, add an option
// to TextOutputOptions to add `# ` to the current indent and use it
// here, so that subsequent lines are also commented out.
emboss_reserved_local_stream->Write("# $_field_name_$: ");
$_field_name_$().WriteToTextStream(emboss_reserved_local_stream,
emboss_reserved_local_field_options);
emboss_reserved_local_stream->Write("\n");
} else {
if (emboss_reserved_local_field_options.multiline()) {
emboss_reserved_local_stream->Write(
emboss_reserved_local_field_options.current_indent());
}
emboss_reserved_local_stream->Write("# $_field_name_$: UNREADABLE\n");
}
}
// ** constant_structure_size_method ** ////////////////////////////////////////
static constexpr ::std::size_t SizeIn$_units_$() {
return static_cast</**/ ::std::size_t>(IntrinsicSizeIn$_units_$().Read());
}
static constexpr bool SizeIsKnown() {
return IntrinsicSizeIn$_units_$().Ok();
}
// ** runtime_structure_size_method ** /////////////////////////////////////////
::std::size_t SizeIn$_units_$() const {
return static_cast</**/ ::std::size_t>(IntrinsicSizeIn$_units_$().Read());
}
bool SizeIsKnown() const { return IntrinsicSizeIn$_units_$().Ok(); }
// ** ok_method_test ** ////////////////////////////////////////////////////////
// If we don't have enough information to determine whether $_field_$ is
// present in the structure, then structure.Ok() should be false.
if (!has_$_field_$.Known()) return false;
// If $_field_$ is present, but not Ok(), then structure.Ok() should be
// false. If $_field_$ is not present, it does not matter whether it is
// Ok().
if (has_$_field_$.ValueOrDefault() && !$_field_$.Ok()) return false;
// ** equals_method_test ** ////////////////////////////////////////////////////
// If this->$_field_$ is not equal to emboss_reserved_local_other.$_field_$,
// then the structures are not equal.
// If either structure's has_$_field_$ is unknown, then default to not
// Equals().
//
// TODO(bolms): Should Equals() return Maybe<bool> and/or return true for
// non-Ok()-but-equivalent structures?
if (!has_$_field_$.Known()) return false;
if (!emboss_reserved_local_other.has_$_field_$.Known()) return false;
// If one side has $_field_$ but the other side does not, then the fields
// are not equal. We use ValueOrDefault() instead of Value() since Value()
// is more complex and non-constexpr, and we already know that
// has_$_field_$.Known() is true for both structures.
if (emboss_reserved_local_other.has_$_field_$.ValueOrDefault() &&
!has_$_field_$.ValueOrDefault())
return false;
if (has_$_field_$.ValueOrDefault() &&
!emboss_reserved_local_other.has_$_field_$.ValueOrDefault())
return false;
// If both sides have $_field_$, then check that their Equals() returns
// true.
if (emboss_reserved_local_other.has_$_field_$.ValueOrDefault() &&
has_$_field_$.ValueOrDefault() &&
!$_field_$.Equals(emboss_reserved_local_other.$_field_$))
return false;
// ** unchecked_equals_method_test ** //////////////////////////////////////////
// The contract for UncheckedEquals() is that the caller must assure that
// both views are Ok() (which implies that has_$_field_$.Known() is true),
// and UncheckedEquals() will never perform any assertion checks (which
// implies that UncheckedEquals() cannot call has_$_field_$.Value()).
// If this->has_$_field_$ but !emboss_reserved_local_other.has_$_field_$, or
// vice versa, then the structures are not equal. If neither structure
// has_$_field_$, then $_field_$ is considered equal.
if (emboss_reserved_local_other.has_$_field_$.ValueOr(false) &&
!has_$_field_$.ValueOr(false))
return false;
if (has_$_field_$.ValueOr(false) &&
!emboss_reserved_local_other.has_$_field_$.ValueOr(false))
return false;
// If $_field_$ is present in both structures, then check its equality.
if (emboss_reserved_local_other.has_$_field_$.ValueOr(false) &&
has_$_field_$.ValueOr(false) &&
!$_field_$.UncheckedEquals(emboss_reserved_local_other.$_field_$))
return false;
// ** structure_view_type ** ///////////////////////////////////////////////////
$_namespace_$::Generic$_name_$View<typename $_buffer_type_$>
// ** external_view_type ** ////////////////////////////////////////////////////
$_namespace_$::$_name_$View<
/**/ ::emboss::support::FixedSizeViewParameters<$_bits_$, $_validator_$>,
typename $_buffer_type_$>
// ** enum_view_type ** ////////////////////////////////////////////////////////
$_support_namespace_$::EnumView<
/**/ $_enum_type_$,
::emboss::support::FixedSizeViewParameters<$_bits_$, $_validator_$>,
typename $_buffer_type_$>
// ** array_view_adapter ** ////////////////////////////////////////////////////
$_support_namespace_$::GenericArrayView<
typename $_element_view_type_$, typename $_buffer_type_$, $_element_size_$,
$_addressable_unit_size_$ $_element_view_parameter_types_$>
// ** structure_field_validator ** /////////////////////////////////////////////
struct $_name_$ {
template <typename ValueType>
static constexpr bool ValueIsOk(ValueType emboss_reserved_local_value) {
(void)emboss_reserved_local_value; // Silence -Wunused-parameter
return ($_expression_$).ValueOrDefault();
}
};
// ** structure_single_field_method_declarations ** ////////////////////////////
$_visibility_$:
typename $_type_reader_$ $_name_$() const;
::emboss::support::Maybe<bool> has_$_name_$() const;
// ** structure_single_field_method_definitions ** /////////////////////////////
template <class Storage>
inline typename $_type_reader_$ Generic$_parent_type_$View<Storage>::$_name_$()
const {
// If it's not possible to read the location of this field, provide a view
// into a null storage -- the only safe methods to call on it will be Ok() and
// IsComplete(), but it is necessary to return a view so that client code can
// call those methods at all. Similarly, if the end of the field would come
// before the start, we provide a null storage, though arguably we should
// not.
$_parameter_subexpressions_$
if ($_parameters_known_$ has_$_name_$().ValueOr(false)) {
$_size_and_offset_subexpressions_$
auto emboss_reserved_local_size = $_size_$;
auto emboss_reserved_local_offset = $_offset_$;
if (emboss_reserved_local_size.Known() &&
emboss_reserved_local_size.ValueOr(0) >= 0 &&
emboss_reserved_local_offset.Known() &&
emboss_reserved_local_offset.ValueOr(0) >= 0) {
return $_type_reader_$(
$_parameter_values_$ backing_
.template GetOffsetStorage<$_alignment_$,
$_static_offset_$>(
emboss_reserved_local_offset.ValueOrDefault(),
emboss_reserved_local_size.ValueOrDefault()));
}
}
return $_type_reader_$();
}
template <class Storage>
inline ::emboss::support::Maybe<bool>
Generic$_parent_type_$View<Storage>::has_$_name_$() const {
return $_field_exists_$;
}
// ** structure_single_const_virtual_field_method_declarations ** //////////////
$_visibility_$:
class $_virtual_view_type_name_$ final {
public:
using ValueType = $_logical_type_$;
constexpr $_virtual_view_type_name_$() {}
$_virtual_view_type_name_$(const $_virtual_view_type_name_$ &) = default;
$_virtual_view_type_name_$($_virtual_view_type_name_$ &&) = default;
$_virtual_view_type_name_$ &operator=(const $_virtual_view_type_name_$ &) =
default;
$_virtual_view_type_name_$ &operator=($_virtual_view_type_name_$ &&) =
default;
~$_virtual_view_type_name_$() = default;
static constexpr $_logical_type_$ Read();
static constexpr $_logical_type_$ UncheckedRead();
static constexpr bool Ok() { return true; }
template <class Stream>
void WriteToTextStream(Stream *emboss_reserved_local_stream,
const ::emboss::TextOutputOptions
&emboss_reserved_local_options) const {
::emboss::support::$_write_to_text_stream_function_$(
this, emboss_reserved_local_stream, emboss_reserved_local_options);
}
static constexpr bool IsAggregate() { return false; }
};
static constexpr $_virtual_view_type_name_$ $_name_$() {
return $_virtual_view_type_name_$();
}
static constexpr ::emboss::support::Maybe<bool> has_$_name_$() {
return ::emboss::support::Maybe<bool>(true);
}
// ** structure_single_const_virtual_field_method_definitions ** ///////////////
namespace $_parent_type_$ {
inline constexpr $_logical_type_$ $_name_$() {
return $_read_value_$.ValueOrDefault();
}
} // namespace $_parent_type_$
template <class Storage>
inline constexpr $_logical_type_$
Generic$_parent_type_$View<Storage>::$_virtual_view_type_name_$::Read() {
return $_parent_type_$::$_name_$();
}
template <class Storage>
inline constexpr $_logical_type_$
Generic$_parent_type_$View<
Storage>::$_virtual_view_type_name_$::UncheckedRead() {
return $_parent_type_$::$_name_$();
}
// ** structure_single_virtual_field_method_declarations ** ////////////////////
$_visibility_$:
class $_virtual_view_type_name_$ final {
public:
using ValueType = $_logical_type_$;
explicit $_virtual_view_type_name_$(
const Generic$_parent_type_$View &emboss_reserved_local_view)
: view_(emboss_reserved_local_view) {}
$_virtual_view_type_name_$() = delete;
$_virtual_view_type_name_$(const $_virtual_view_type_name_$ &) = default;
$_virtual_view_type_name_$($_virtual_view_type_name_$ &&) = default;
$_virtual_view_type_name_$ &operator=(const $_virtual_view_type_name_$ &) =
default;
$_virtual_view_type_name_$ &operator=($_virtual_view_type_name_$ &&) =
default;
~$_virtual_view_type_name_$() = default;
$_logical_type_$ Read() const {
EMBOSS_CHECK(view_.has_$_name_$().ValueOr(false));
auto emboss_reserved_local_value = MaybeRead();
EMBOSS_CHECK(emboss_reserved_local_value.Known());
EMBOSS_CHECK(ValueIsOk(emboss_reserved_local_value.ValueOrDefault()));
return emboss_reserved_local_value.ValueOrDefault();
}
$_logical_type_$ UncheckedRead() const {
// UncheckedRead() on a virtual still calls Ok() on its dependencies;
// i.e., it still does some bounds checking. This is because of a subtle
// case, illustrated by the example below:
//
// # .emb
// struct Foo:
// 0 [+1] UInt x
// if x != 0:
// 1 [+1] UInt y
// let x_and_y = x != 0 && y != 0
//
// // .cc
// std::array<char, 1> buffer = {0};
// const auto view = MakeFooView(&buffer);
// assert(!view.x_and_y().UncheckedRead());
//
// Without the checks for Ok(), the implementation of UncheckedRead()
// looks something like:
//
// bool UncheckedRead() const {
// return And(view_.x().UncheckedRead(),
// view_.y().UncheckedRead()).ValueOrDefault();
// }
//
// Unfortunately, even if x().UncheckedRead() is false, this will call
// UncheckedRead() on y(), which will segfault.
//
// TODO(bolms): Figure out a way to minimize bounds checking, instead of
// just always checking here.
return MaybeRead().ValueOrDefault();
}
// Ok() can be false if some dependency is unreadable, *or* if there is an
// error somewhere in the arithmetic -- say, division by zero.
bool Ok() const {
auto emboss_reserved_local_value = MaybeRead();
return emboss_reserved_local_value.Known() &&
ValueIsOk(emboss_reserved_local_value.ValueOrDefault());
}
template <class Stream>
void WriteToTextStream(Stream *emboss_reserved_local_stream,
const ::emboss::TextOutputOptions
&emboss_reserved_local_options) const {
::emboss::support::$_write_to_text_stream_function_$(
this, emboss_reserved_local_stream, emboss_reserved_local_options);
}
static constexpr bool IsAggregate() { return false; }
$_write_methods_$
private:
::emboss::support::Maybe</**/ $_logical_type_$> MaybeRead() const {
$_read_subexpressions_$
return $_read_value_$;
}
static constexpr bool ValueIsOk(
$_logical_type_$ emboss_reserved_local_value) {
(void)emboss_reserved_local_value; // Silence -Wunused-parameter
return $_value_is_ok_$.ValueOr(false);
}
const Generic$_parent_type_$View view_;
};
$_virtual_view_type_name_$ $_name_$() const;
::emboss::support::Maybe<bool> has_$_name_$() const;
// ** structure_single_virtual_field_write_methods ** //////////////////////////
bool TryToWrite($_logical_type_$ emboss_reserved_local_value) {
const auto emboss_reserved_local_maybe_new_value = $_transform_$;
if (!CouldWriteValue(emboss_reserved_local_value)) return false;
return view_.$_destination_$.TryToWrite(
emboss_reserved_local_maybe_new_value.ValueOrDefault());
}
void Write($_logical_type_$ emboss_reserved_local_value) {
const bool result = TryToWrite(emboss_reserved_local_value);
(void)result;
EMBOSS_CHECK(result);
}
void UncheckedWrite($_logical_type_$ emboss_reserved_local_value) {
view_.$_destination_$.UncheckedWrite(($_transform_$).ValueOrDefault());
}
bool CouldWriteValue($_logical_type_$ emboss_reserved_local_value) {
if (!ValueIsOk(emboss_reserved_local_value)) return false;
const auto emboss_reserved_local_maybe_new_value = $_transform_$;
if (!emboss_reserved_local_maybe_new_value.Known()) return false;
return view_.$_destination_$.CouldWriteValue(
emboss_reserved_local_maybe_new_value.ValueOrDefault());
}
template <class Stream>
bool UpdateFromTextStream(Stream *emboss_reserved_local_stream) {
return ::emboss::support::ReadIntegerFromTextStream(
this, emboss_reserved_local_stream);
}
// ** structure_single_virtual_field_method_definitions ** /////////////////////
template <class Storage>
inline typename Generic$_parent_type_$View<Storage>::$_virtual_view_type_name_$
Generic$_parent_type_$View<Storage>::$_name_$() const {
return
typename Generic$_parent_type_$View<Storage>::$_virtual_view_type_name_$(
*this);
}
template <class Storage>
inline ::emboss::support::Maybe<bool>
Generic$_parent_type_$View<Storage>::has_$_name_$() const {
return $_field_exists_$;
}
// ** structure_single_field_indirect_method_declarations ** ///////////////////
$_visibility_$:
// The "this->" is required for (some versions of?) GCC.
auto $_name_$() const -> decltype(this->$_aliased_field_$) {
return has_$_name_$().ValueOrDefault() ? $_aliased_field_$
: decltype(this->$_aliased_field_$)();
}
::emboss::support::Maybe<bool> has_$_name_$() const;
// ** struct_single_field_indirect_method_definitions ** ///////////////////////
template <class Storage>
inline ::emboss::support::Maybe<bool>
Generic$_parent_type_$View<Storage>::has_$_name_$() const {
return $_field_exists_$;
}
// ** structure_single_parameter_field_method_declarations ** //////////////////
private:
// TODO(bolms): Is there any harm if these are public methods?
constexpr ::emboss::support::MaybeConstantView</**/ $_logical_type_$>
$_name_$() const {
return parameters_initialized_
? ::emboss::support::MaybeConstantView</**/ $_logical_type_$>(
$_name_$_)
: ::emboss::support::MaybeConstantView</**/ $_logical_type_$>();
}
constexpr ::emboss::support::Maybe<bool> has_$_name_$() const {
return ::emboss::support::Maybe<bool>(parameters_initialized_);
}
// ** enum_declaration ** //////////////////////////////////////////////////////
enum class $_enum_$ : $_enum_type_$;
// ** enum_definition ** ///////////////////////////////////////////////////////
enum class $_enum_$ : $_enum_type_$ {
$_enum_values_$
};
// This setup (ab)uses the fact that C++ templates can be defined in many
// translation units, but will be collapsed to a single definition at link time
// (or no definition, if no client code instantiates the template).
//
// Emboss could accomplish almost the same result by generating multiple .cc
// files (one per function), but Bazel doesn't have great support for specifying
// "the output of this rule is an indeterminate number of files, all of which
// should be used as input to this other rule," which would be necessary to
// generate all the .cc files and then build and link them into a library.
template <class Enum>
class EnumTraits;
template <>
class EnumTraits<$_enum_$> final {
public:
static bool TryToGetEnumFromName(const char *emboss_reserved_local_name,
$_enum_$ *emboss_reserved_local_result) {
if (emboss_reserved_local_name == nullptr) return false;
// TODO(bolms): The generated code here would be much more efficient for
// large enums if the mapping were performed using a prefix trie rather than
// repeated strcmp().
$_enum_from_name_cases_$
return false;
}
static const char *TryToGetNameFromEnum(
$_enum_$ emboss_reserved_local_value) {
switch (emboss_reserved_local_value) {
$_name_from_enum_cases_$
default: return nullptr;
}
}
static bool EnumIsKnown($_enum_$ emboss_reserved_local_value) {
switch (emboss_reserved_local_value) {
$_enum_is_known_cases_$
default:
return false;
}
}
static ::std::ostream &SendToOstream(::std::ostream &emboss_reserved_local_os,
$_enum_$ emboss_reserved_local_value) {
const char *emboss_reserved_local_name =
TryToGetNameFromEnum(emboss_reserved_local_value);
if (emboss_reserved_local_name == nullptr) {
emboss_reserved_local_os
<< static_cast</**/ ::std::underlying_type<$_enum_$>::type>(
emboss_reserved_local_value);
} else {
emboss_reserved_local_os << emboss_reserved_local_name;
}
return emboss_reserved_local_os;
}
};
// These functions are intended to be found via ADL.
static inline bool TryToGetEnumFromName(
const char *emboss_reserved_local_name,
$_enum_$ *emboss_reserved_local_result) {
return EnumTraits<$_enum_$>::TryToGetEnumFromName(
emboss_reserved_local_name, emboss_reserved_local_result);
}
static inline const char *TryToGetNameFromEnum(
$_enum_$ emboss_reserved_local_value) {
return EnumTraits<$_enum_$>::TryToGetNameFromEnum(
emboss_reserved_local_value);
}
static inline bool EnumIsKnown($_enum_$ emboss_reserved_local_value) {
return EnumTraits<$_enum_$>::EnumIsKnown(emboss_reserved_local_value);
}
static inline ::std::ostream &operator<<(
::std::ostream &emboss_reserved_local_os,
$_enum_$ emboss_reserved_local_value) {
return EnumTraits<$_enum_$>::SendToOstream(emboss_reserved_local_os,
emboss_reserved_local_value);
}
// ** enum_from_name_case ** ///////////////////////////////////////////////////
if (!strcmp("$_name_$", emboss_reserved_local_name)) {
*emboss_reserved_local_result = $_enum_$::$_name_$;
return true;
}
// ** name_from_enum_case ** ///////////////////////////////////////////////////
case $_enum_$::$_name_$: return "$_name_$";
// ** enum_is_known_case ** ////////////////////////////////////////////////////
case $_enum_$::$_name_$: return true;
// ** enum_value ** ////////////////////////////////////////////////////////////
$_name_$ = $_value_$,
// ** enum_using_statement ** //////////////////////////////////////////////////
using $_name_$ = $_component_$;