[PATCH v2 01/21] abg-cxx-compat: add simplified version of std::optional
Matthias Maennich
maennich@google.com
Fri Jul 3 16:46:31 GMT 2020
In the absence (but desire) of std::optional<T>, add a simplified
version of it to abg_compat:: in case we are compiling with a pre-C++17
standard. Otherwise use std::optional from <optional> directly.
This is being used by a later patch and serves as a prerequisite.
It only serves the purpose of being a compatibility implementation and
does not claim to be complete at all. Just enough for the project's
needs.
* include/abg-cxx-compat.h (abg_compat::optional): Add new class.
* tests/tests-cxx-compat.cc: Add new test cases.
Reviewed-by: Giuliano Procida <gprocida@google.com>
Signed-off-by: Matthias Maennich <maennich@google.com>
---
include/abg-cxx-compat.h | 86 ++++++++++++++++++++++++++++++++++++++++
tests/test-cxx-compat.cc | 51 ++++++++++++++++++++++++
2 files changed, 137 insertions(+)
diff --git a/include/abg-cxx-compat.h b/include/abg-cxx-compat.h
index 714177183945..1283e9191d46 100644
--- a/include/abg-cxx-compat.h
+++ b/include/abg-cxx-compat.h
@@ -23,6 +23,8 @@
#ifndef __ABG_CXX_COMPAT_H
#define __ABG_CXX_COMPAT_H
+// C++11 support (mostly via tr1 if compiled with earlier standard)
+
#if __cplusplus >= 201103L
#include <functional>
@@ -39,6 +41,18 @@
#endif
+// C++17 support (via custom implementations if compiled with earlier standard)
+
+#if __cplusplus >= 201703L
+
+#include <optional>
+
+#else
+
+#include <stdexcept> // for throwing std::runtime_error("bad_optional_access")
+
+#endif
+
namespace abg_compat {
#if __cplusplus >= 201103L
@@ -77,6 +91,78 @@ using std::tr1::unordered_set;
#endif
+#if __cplusplus >= 201703L
+
+using std::optional;
+
+#else
+
+// <optional>
+
+/// Simplified implementation of std::optional just enough to be used as a
+/// replacement for our purposes and when compiling with pre C++17.
+///
+/// The implementation intentionally does not support a whole lot of features
+/// to minimize the maintainence effort with this.
+template <typename T> class optional
+{
+ bool has_value_;
+ T value_;
+
+public:
+ optional() : has_value_(false), value_() {}
+ optional(const T& value) : has_value_(true), value_(value) {}
+
+ bool
+ has_value() const
+ {
+ return has_value_;
+ }
+
+ const T&
+ value() const
+ {
+ if (!has_value_)
+ throw std::runtime_error("bad_optional_access");
+ return value_;
+ }
+
+ const T
+ value_or(const T& default_value) const
+ {
+ if (!has_value_)
+ return default_value;
+ return value_;
+ }
+
+ const T&
+ operator*() const
+ { return value_; }
+
+ T&
+ operator*()
+ { return value_; }
+
+ const T*
+ operator->() const
+ { return &value_; }
+
+ T*
+ operator->()
+ { return &value_; }
+
+ optional&
+ operator=(const T& value)
+ {
+ has_value_ = true;
+ value_ = value;
+ return *this;
+ }
+
+ explicit operator bool() const { return has_value_; }
+};
+
+#endif
}
#endif // __ABG_CXX_COMPAT_H
diff --git a/tests/test-cxx-compat.cc b/tests/test-cxx-compat.cc
index 0a230a54e1a5..adeb7b8d7e4f 100644
--- a/tests/test-cxx-compat.cc
+++ b/tests/test-cxx-compat.cc
@@ -28,3 +28,54 @@
#include "abg-cxx-compat.h"
+using abg_compat::optional;
+
+TEST_CASE("OptionalConstruction", "[abg_compat::optional]")
+{
+ optional<bool> opt1;
+ REQUIRE_FALSE(opt1.has_value());
+
+ optional<bool> opt2(true);
+ REQUIRE(opt2.has_value());
+ CHECK(opt2.value() == true);
+
+ optional<bool> opt3(false);
+ REQUIRE(opt3.has_value());
+ CHECK(opt3.value() == false);
+}
+
+TEST_CASE("OptionalValue", "[abg_compat::optional]")
+{
+ optional<bool> opt;
+ REQUIRE_FALSE(opt.has_value());
+ REQUIRE_THROWS(opt.value());
+
+ opt = true;
+ REQUIRE_NOTHROW(opt.value());
+ CHECK(opt.value() == true);
+}
+
+TEST_CASE("OptionalValueOr", "[abg_compat::optional]")
+{
+ optional<std::string> opt;
+ REQUIRE_FALSE(opt.has_value());
+
+ const std::string& mine = "mine";
+ // Ensure we get a copy of our own value.
+ CHECK(opt.value_or(mine) == mine);
+
+ // Now set the value
+ const std::string& other = "other";
+ opt = other;
+ CHECK(opt.value_or(mine) != mine);
+ CHECK(opt.value_or(mine) == other);
+}
+
+TEST_CASE("OptionalDeref", "[abg_compat::optional]")
+{
+ optional<std::string> opt("asdf");
+ REQUIRE(opt.has_value());
+
+ CHECK(*opt == "asdf");
+ CHECK(opt->size() == 4);
+}
--
2.27.0.212.ge8ba1cc988-goog
More information about the Libabigail
mailing list