summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorVladimir Glavnyy <31897320+vglavnyy@users.noreply.github.com>2020-09-19 02:51:17 +0700
committerGitHub <noreply@github.com>2020-09-18 12:51:17 -0700
commit8c67b5b129f445c6bf5dbcbf2a18fec4c6334f16 (patch)
treed66e068636de0b57a475f0f942c5ccfae2b6ef2c /include
parent6228b66d3d1f0e5d2f79e59834c8931d84cccaaf (diff)
downloadflatbuffers-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.h25
-rw-r--r--include/flatbuffers/flatbuffers.h35
-rw-r--r--include/flatbuffers/idl.h5
-rw-r--r--include/flatbuffers/stl_emulation.h162
-rw-r--r--include/flatbuffers/util.h1
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>