diff options
author | Vladimir Glavnyy <31897320+vglavnyy@users.noreply.github.com> | 2020-09-19 02:51:17 +0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-18 12:51:17 -0700 |
commit | 8c67b5b129f445c6bf5dbcbf2a18fec4c6334f16 (patch) | |
tree | d66e068636de0b57a475f0f942c5ccfae2b6ef2c /include | |
parent | 6228b66d3d1f0e5d2f79e59834c8931d84cccaaf (diff) | |
download | flatbuffers-8c67b5b129f445c6bf5dbcbf2a18fec4c6334f16.tar.gz flatbuffers-8c67b5b129f445c6bf5dbcbf2a18fec4c6334f16.tar.bz2 flatbuffers-8c67b5b129f445c6bf5dbcbf2a18fec4c6334f16.zip |
Add support of Optional<T> scalars to C++ code generator (#6092)
Diffstat (limited to 'include')
-rw-r--r-- | include/flatbuffers/base.h | 25 | ||||
-rw-r--r-- | include/flatbuffers/flatbuffers.h | 35 | ||||
-rw-r--r-- | include/flatbuffers/idl.h | 5 | ||||
-rw-r--r-- | include/flatbuffers/stl_emulation.h | 162 | ||||
-rw-r--r-- | include/flatbuffers/util.h | 1 |
5 files changed, 211 insertions, 17 deletions
diff --git a/include/flatbuffers/base.h b/include/flatbuffers/base.h index d83c7756..8e97c084 100644 --- a/include/flatbuffers/base.h +++ b/include/flatbuffers/base.h @@ -47,22 +47,17 @@ #include <memory> #if defined(__unix__) && !defined(FLATBUFFERS_LOCALE_INDEPENDENT) -#include <unistd.h> -#endif + #include <unistd.h> +#endif #ifdef _STLPORT_VERSION #define FLATBUFFERS_CPP98_STL #endif -#ifndef FLATBUFFERS_CPP98_STL - #include <functional> -#endif #ifdef __ANDROID__ #include <android/api-level.h> #endif -#include "flatbuffers/stl_emulation.h" - #if defined(__ICCARM__) #include <intrinsics.h> #endif @@ -162,10 +157,12 @@ namespace flatbuffers { defined(__clang__) #define FLATBUFFERS_FINAL_CLASS final #define FLATBUFFERS_OVERRIDE override + #define FLATBUFFERS_EXPLICIT_CPP11 explicit #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE : flatbuffers::voffset_t #else #define FLATBUFFERS_FINAL_CLASS #define FLATBUFFERS_OVERRIDE + #define FLATBUFFERS_EXPLICIT_CPP11 #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE #endif @@ -173,10 +170,14 @@ namespace flatbuffers { (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \ (defined(__cpp_constexpr) && __cpp_constexpr >= 200704) #define FLATBUFFERS_CONSTEXPR constexpr + #define FLATBUFFERS_CONSTEXPR_CPP11 constexpr + #define FLATBUFFERS_CONSTEXPR_DEFINED #else #define FLATBUFFERS_CONSTEXPR const + #define FLATBUFFERS_CONSTEXPR_CPP11 #endif +// This macro is never used in code! #if (defined(__cplusplus) && __cplusplus >= 201402L) || \ (defined(__cpp_constexpr) && __cpp_constexpr >= 201304) #define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR @@ -202,6 +203,16 @@ namespace flatbuffers { #define FLATBUFFERS_DELETE_FUNC(func) private: func; #endif +// Check if we can use template aliases +// Not possible if Microsoft Compiler before 2012 +// Possible is the language feature __cpp_alias_templates is defined well +// Or possible if the C++ std is C+11 or newer +#if (defined(_MSC_VER) && _MSC_VER > 1700 /* MSVC2012 */) \ + || (defined(__cpp_alias_templates) && __cpp_alias_templates >= 200704) \ + || (defined(__cplusplus) && __cplusplus >= 201103L) + #define FLATBUFFERS_TEMPLATES_ALIASES +#endif + #ifndef FLATBUFFERS_HAS_STRING_VIEW // Only provide flatbuffers::string_view if __has_include can be used // to detect a header that provides an implementation diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 12ab68af..28441248 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -18,6 +18,11 @@ #define FLATBUFFERS_H_ #include "flatbuffers/base.h" +#include "flatbuffers/stl_emulation.h" + +#ifndef FLATBUFFERS_CPP98_STL + #include <functional> +#endif #if defined(FLATBUFFERS_NAN_DEFAULTS) # include <cmath> @@ -1303,6 +1308,11 @@ class FlatBufferBuilder { TrackField(field, off); } + template<typename T> void AddElement(voffset_t field, T e) { + auto off = PushElement(e); + TrackField(field, off); + } + template<typename T> void AddOffset(voffset_t field, Offset<T> off) { if (off.IsNull()) return; // Don't store. AddElement(field, ReferTo(off.o), static_cast<uoffset_t>(0)); @@ -2460,12 +2470,26 @@ class Table { return field_offset ? reinterpret_cast<P>(p) : nullptr; } + template<typename Raw, typename Face> + flatbuffers::Optional<Face> GetOptional(voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + auto p = data_ + field_offset; + return field_offset ? Optional<Face>(static_cast<Face>(ReadScalar<Raw>(p))) + : Optional<Face>(); + } + template<typename T> bool SetField(voffset_t field, T val, T def) { auto field_offset = GetOptionalFieldOffset(field); if (!field_offset) return IsTheSameAs(val, def); WriteScalar(data_ + field_offset, val); return true; } + template<typename T> bool SetField(voffset_t field, T val) { + auto field_offset = GetOptionalFieldOffset(field); + if (!field_offset) return false; + WriteScalar(data_ + field_offset, val); + return true; + } bool SetPointer(voffset_t field, const uint8_t *val) { auto field_offset = GetOptionalFieldOffset(field); @@ -2533,6 +2557,17 @@ class Table { uint8_t data_[1]; }; +// This specialization allows avoiding warnings like: +// MSVC C4800: type: forcing value to bool 'true' or 'false'. +template<> +inline flatbuffers::Optional<bool> Table::GetOptional<uint8_t, bool>( + voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + auto p = data_ + field_offset; + return field_offset ? Optional<bool>(ReadScalar<uint8_t>(p) != 0) + : Optional<bool>(); +} + template<typename T> void FlatBufferBuilder::Required(Offset<T> table, voffset_t field) { auto table_ptr = reinterpret_cast<const Table *>(buf_.data_at(table.o)); diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index a361c653..a3c31883 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -847,6 +847,11 @@ class Parser : public ParserState { FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg); + // @brief Verify that any of 'opts.lang_to_generate' supports Optional scalars + // in a schema. + // @param opts Options used to parce a schema and generate code. + static bool SupportsOptionalScalars(const flatbuffers::IDLOptions &opts); + private: void Message(const std::string &msg); void Warning(const std::string &msg); diff --git a/include/flatbuffers/stl_emulation.h b/include/flatbuffers/stl_emulation.h index d7d655ef..c9a1a8bf 100644 --- a/include/flatbuffers/stl_emulation.h +++ b/include/flatbuffers/stl_emulation.h @@ -18,6 +18,7 @@ #define FLATBUFFERS_STL_EMULATION_H_ // clang-format off +#include "flatbuffers/base.h" #include <string> #include <type_traits> @@ -25,6 +26,17 @@ #include <memory> #include <limits> +// Detect C++17 compatible compiler. +// __cplusplus >= 201703L - a compiler has support of 'static inline' variables. +#if defined(FLATBUFFERS_USE_STD_OPTIONAL) \ + || (defined(__cplusplus) && __cplusplus >= 201703L) \ + || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)) + #include <optional> + #ifndef FLATBUFFERS_USE_STD_OPTIONAL + #define FLATBUFFERS_USE_STD_OPTIONAL + #endif +#endif + #if defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL) #define FLATBUFFERS_CPP98_STL #endif // defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL) @@ -33,16 +45,6 @@ #include <cctype> #endif // defined(FLATBUFFERS_CPP98_STL) -// Check if we can use template aliases -// Not possible if Microsoft Compiler before 2012 -// Possible is the language feature __cpp_alias_templates is defined well -// Or possible if the C++ std is C+11 or newer -#if (defined(_MSC_VER) && _MSC_VER > 1700 /* MSVC2012 */) \ - || (defined(__cpp_alias_templates) && __cpp_alias_templates >= 200704) \ - || (defined(__cplusplus) && __cplusplus >= 201103L) - #define FLATBUFFERS_TEMPLATES_ALIASES -#endif - // This header provides backwards compatibility for C++98 STLs like stlport. namespace flatbuffers { @@ -302,6 +304,146 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) { #endif // !FLATBUFFERS_CPP98_STL +#ifdef FLATBUFFERS_USE_STD_OPTIONAL +template<class T> +using Optional = std::optional<T>; +using nullopt_t = std::nullopt_t; +inline constexpr nullopt_t nullopt = std::nullopt; + +#else +// Limited implementation of Optional<T> type for a scalar T. +// This implementation limited by trivial types compatible with +// std::is_arithmetic<T> or std::is_enum<T> type traits. + +// A tag to indicate an empty flatbuffers::optional<T>. +struct nullopt_t { + explicit FLATBUFFERS_CONSTEXPR_CPP11 nullopt_t(int) {} +}; + +#if defined(FLATBUFFERS_CONSTEXPR_DEFINED) + namespace internal { + template <class> struct nullopt_holder { + static constexpr nullopt_t instance_ = nullopt_t(0); + }; + template<class Dummy> + constexpr nullopt_t nullopt_holder<Dummy>::instance_; + } + static constexpr const nullopt_t &nullopt = internal::nullopt_holder<void>::instance_; + +#else + namespace internal { + template <class> struct nullopt_holder { + static const nullopt_t instance_; + }; + template<class Dummy> + const nullopt_t nullopt_holder<Dummy>::instance_ = nullopt_t(0); + } + static const nullopt_t &nullopt = internal::nullopt_holder<void>::instance_; + +#endif + +template<class T> +class Optional FLATBUFFERS_FINAL_CLASS { + // Non-scalar 'T' would extremely complicated Optional<T>. + // Use is_scalar<T> checking because flatbuffers flatbuffers::is_arithmetic<T> + // isn't implemented. + static_assert(flatbuffers::is_scalar<T>::value, "unexpected type T"); + + public: + ~Optional() {} + + FLATBUFFERS_CONSTEXPR_CPP11 Optional() FLATBUFFERS_NOEXCEPT + : value_(), has_value_(false) {} + + FLATBUFFERS_CONSTEXPR_CPP11 Optional(nullopt_t) FLATBUFFERS_NOEXCEPT + : value_(), has_value_(false) {} + + FLATBUFFERS_CONSTEXPR_CPP11 Optional(T val) FLATBUFFERS_NOEXCEPT + : value_(val), has_value_(true) {} + + FLATBUFFERS_CONSTEXPR_CPP11 Optional(const Optional &other) FLATBUFFERS_NOEXCEPT + : value_(other.value_), has_value_(other.has_value_) {} + + FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(const Optional &other) FLATBUFFERS_NOEXCEPT { + value_ = other.value_; + has_value_ = other.has_value_; + return *this; + } + + FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(nullopt_t) FLATBUFFERS_NOEXCEPT { + value_ = T(); + has_value_ = false; + return *this; + } + + FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(T val) FLATBUFFERS_NOEXCEPT { + value_ = val; + has_value_ = true; + return *this; + } + + void reset() FLATBUFFERS_NOEXCEPT { + *this = nullopt; + } + + void swap(Optional &other) FLATBUFFERS_NOEXCEPT { + std::swap(value_, other.value_); + std::swap(has_value_, other.has_value_); + } + + FLATBUFFERS_CONSTEXPR_CPP11 FLATBUFFERS_EXPLICIT_CPP11 operator bool() const FLATBUFFERS_NOEXCEPT { + return has_value_; + } + + FLATBUFFERS_CONSTEXPR_CPP11 bool has_value() const FLATBUFFERS_NOEXCEPT { + return has_value_; + } + + FLATBUFFERS_CONSTEXPR_CPP11 const T& operator*() const FLATBUFFERS_NOEXCEPT { + return value_; + } + + const T& value() const { + FLATBUFFERS_ASSERT(has_value()); + return value_; + } + + T value_or(T default_value) const FLATBUFFERS_NOEXCEPT { + return has_value() ? value_ : default_value; + } + + private: + T value_; + bool has_value_; +}; + +template<class T> +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& opt, nullopt_t) FLATBUFFERS_NOEXCEPT { + return !opt; +} +template<class T> +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(nullopt_t, const Optional<T>& opt) FLATBUFFERS_NOEXCEPT { + return !opt; +} + +template<class T, class U> +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& lhs, const U& rhs) FLATBUFFERS_NOEXCEPT { + return static_cast<bool>(lhs) && (*lhs == rhs); +} + +template<class T, class U> +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const T& lhs, const Optional<U>& rhs) FLATBUFFERS_NOEXCEPT { + return static_cast<bool>(rhs) && (lhs == *rhs); +} + +template<class T, class U> +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) FLATBUFFERS_NOEXCEPT { + return static_cast<bool>(lhs) != static_cast<bool>(rhs) + ? false + : !static_cast<bool>(lhs) ? false : (*lhs == *rhs); +} +#endif // FLATBUFFERS_USE_STD_OPTIONAL + } // namespace flatbuffers #endif // FLATBUFFERS_STL_EMULATION_H_ diff --git a/include/flatbuffers/util.h b/include/flatbuffers/util.h index b6340a2a..37ea1b91 100644 --- a/include/flatbuffers/util.h +++ b/include/flatbuffers/util.h @@ -20,6 +20,7 @@ #include <errno.h> #include "flatbuffers/base.h" +#include "flatbuffers/stl_emulation.h" #ifndef FLATBUFFERS_PREFER_PRINTF # include <sstream> |