[01/20] abg-cxx-compat: add simplified version of std::optional
Commit Message
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 | 84 ++++++++++++++++++++++++++++++++++++++++
tests/test-cxx-compat.cc | 52 +++++++++++++++++++++++++
2 files changed, 136 insertions(+)
Comments
Matthias Maennich <maennich@google.com> a écrit:
> 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>
Applied to master, thanks!
Cheers,
[...]
@@ -8,8 +8,92 @@
#ifndef __ABG_CXX_COMPAT_H
#define __ABG_CXX_COMPAT_H
+// 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 >= 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 maintenance 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
@@ -12,3 +12,55 @@
#include "lib/catch.hpp"
#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);
+}