...

Text file src/github.com/google/flatbuffers/tests/cpp17/stringify_util.h

Documentation: github.com/google/flatbuffers/tests/cpp17

     1/*
     2 * Copyright 2020 Google Inc. All rights reserved.
     3 *
     4 * Licensed under the Apache License, Version 2.0 (the "License");
     5 * you may not use this file except in compliance with the License.
     6 * You may obtain a copy of the License at
     7 *
     8 *     http://www.apache.org/licenses/LICENSE-2.0
     9 *
    10 * Unless required by applicable law or agreed to in writing, software
    11 * distributed under the License is distributed on an "AS IS" BASIS,
    12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13 * See the License for the specific language governing permissions and
    14 * limitations under the License.
    15 */
    16
    17// This contains some utilities/examples for how to leverage the static reflec-
    18// tion features of tables and structs in the C++17 code generation to recur-
    19// sively produce a string representation of any Flatbuffer table or struct use
    20// compile-time iteration over the fields. Note that this code is completely
    21// generic in that it makes no reference to any particular Flatbuffer type.
    22
    23#include <optional>
    24#include <string>
    25#include <type_traits>
    26#include <utility>
    27#include <vector>
    28
    29#include "flatbuffers/flatbuffers.h"
    30#include "flatbuffers/util.h"
    31
    32namespace cpp17 {
    33
    34// User calls this; need to forward declare it since it is called recursively.
    35template<typename T>
    36std::optional<std::string> StringifyFlatbufferValue(
    37    T &&val, const std::string &indent = "");
    38
    39namespace detail {
    40
    41/*******************************************************************************
    42** Metaprogramming helpers for detecting Flatbuffers Tables, Structs, & Vectors.
    43*******************************************************************************/
    44template<typename FBS, typename = void>
    45struct is_flatbuffers_table_or_struct : std::false_type {};
    46
    47// We know it's a table or struct when it has a Traits subclass.
    48template<typename FBS>
    49struct is_flatbuffers_table_or_struct<FBS, std::void_t<typename FBS::Traits>>
    50    : std::true_type {};
    51
    52template<typename FBS>
    53inline constexpr bool is_flatbuffers_table_or_struct_v =
    54    is_flatbuffers_table_or_struct<FBS>::value;
    55
    56template<typename T> struct is_flatbuffers_vector : std::false_type {};
    57
    58template<typename T>
    59struct is_flatbuffers_vector<flatbuffers::Vector<T>> : std::true_type {};
    60
    61template<typename T>
    62inline constexpr bool is_flatbuffers_vector_v = is_flatbuffers_vector<T>::value;
    63
    64/*******************************************************************************
    65** Compile-time Iteration & Recursive Stringification over Flatbuffers types.
    66*******************************************************************************/
    67template<size_t Index, typename FBS>
    68std::string AddStringifiedField(const FBS &fbs, const std::string &indent) {
    69  auto value_string =
    70      StringifyFlatbufferValue(fbs.template get_field<Index>(), indent);
    71  if (!value_string) { return ""; }
    72  return indent + FBS::Traits::field_names[Index] + " = " + *value_string +
    73         "\n";
    74}
    75
    76template<typename FBS, size_t... Indexes>
    77std::string StringifyTableOrStructImpl(const FBS &fbs,
    78                                       const std::string &indent,
    79                                       std::index_sequence<Indexes...>) {
    80  // This line is where the compile-time iteration happens!
    81  return (AddStringifiedField<Indexes>(fbs, indent) + ...);
    82}
    83
    84template<typename FBS>
    85std::string StringifyTableOrStruct(const FBS &fbs, const std::string &indent) {
    86  (void)fbs;
    87  (void)indent;
    88  static constexpr size_t field_count = FBS::Traits::fields_number;
    89  std::string out;
    90  if constexpr (field_count > 0) {
    91    out = std::string(FBS::Traits::fully_qualified_name) + "{\n" +
    92          StringifyTableOrStructImpl(fbs, indent + "  ",
    93                                     std::make_index_sequence<field_count>{}) +
    94          indent + '}';
    95  }
    96  return out;
    97}
    98
    99template<typename T>
   100std::string StringifyVector(const flatbuffers::Vector<T> &vec,
   101                            const std::string &indent) {
   102  const auto prologue = indent + std::string("  ");
   103  const auto epilogue = std::string(",\n");
   104  std::string text;
   105  text += "[\n";
   106  for (auto it = vec.cbegin(), end = vec.cend(); it != end; ++it) {
   107    text += prologue;
   108    text += StringifyFlatbufferValue(*it).value_or("(field absent)");
   109    text += epilogue;
   110  }
   111  if (vec.cbegin() != vec.cend()) {
   112    text.resize(text.size() - epilogue.size());
   113  }
   114  text += '\n' + indent + ']';
   115  return text;
   116}
   117
   118template<typename T> std::string StringifyArithmeticType(T val) {
   119  return flatbuffers::NumToString(val);
   120}
   121
   122}  // namespace detail
   123
   124/*******************************************************************************
   125** Take any flatbuffer type (table, struct, Vector, int...) and stringify it.
   126*******************************************************************************/
   127template<typename T>
   128std::optional<std::string> StringifyFlatbufferValue(T &&val,
   129                                                    const std::string &indent) {
   130  (void)indent;
   131  constexpr bool is_pointer = std::is_pointer_v<std::remove_reference_t<T>>;
   132  if constexpr (is_pointer) {
   133    if (val == nullptr) return std::nullopt;  // Field is absent.
   134  }
   135  using decayed =
   136      std::decay_t<std::remove_pointer_t<std::remove_reference_t<T>>>;
   137
   138  // Is it a Flatbuffers Table or Struct?
   139  if constexpr (detail::is_flatbuffers_table_or_struct_v<decayed>) {
   140    // We have a nested table or struct; use recursion!
   141    if constexpr (is_pointer)
   142      return detail::StringifyTableOrStruct(*val, indent);
   143    else
   144      return detail::StringifyTableOrStruct(val, indent);
   145  }
   146
   147  // Is it an 8-bit number?  If so, print it like an int (not char).
   148  else if constexpr (std::is_same_v<decayed, int8_t> ||
   149                     std::is_same_v<decayed, uint8_t>) {
   150    return detail::StringifyArithmeticType(static_cast<int>(val));
   151  }
   152
   153  // Is it an enum? If so, print it like an int, since Flatbuffers doesn't yet
   154  // have type-based reflection for enums, so we can't print the enum's name :(
   155  else if constexpr (std::is_enum_v<decayed>) {
   156    return StringifyFlatbufferValue(
   157        static_cast<std::underlying_type_t<decayed>>(val), indent);
   158  }
   159
   160  // Is it an int, double, float, uint32_t, etc.?
   161  else if constexpr (std::is_arithmetic_v<decayed>) {
   162    return detail::StringifyArithmeticType(val);
   163  }
   164
   165  // Is it a Flatbuffers string?
   166  else if constexpr (std::is_same_v<decayed, flatbuffers::String>) {
   167    return '"' + val->str() + '"';
   168  }
   169
   170  // Is it a Flatbuffers Vector?
   171  else if constexpr (detail::is_flatbuffers_vector_v<decayed>) {
   172    return detail::StringifyVector(*val, indent);
   173  }
   174
   175  // Is it a void pointer?
   176  else if constexpr (std::is_same_v<decayed, void>) {
   177    // Can't format it.
   178    return std::nullopt;
   179  }
   180
   181  else {
   182    // Not sure how to format this type, whatever it is.
   183    static_assert(sizeof(T) != sizeof(T),
   184                  "Do not know how to format this type T (the compiler error "
   185                  "should tell you nearby what T is).");
   186  }
   187}
   188
   189}  // namespace cpp17

View as plain text