aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-06-27 14:55:27 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-06-27 14:55:27 +0200
commit524322f78775dc14c61d33cbdb719b8330c2ad5c (patch)
tree4a101a1359025b916ca01d33339197c78bbb1872
parent0071c616f02de72f8a6ed82448a7b9e8a6c9a40c (diff)
Reimplement optional not to require default-constructible value types
-rw-r--r--libbutl/optional.ixx210
-rw-r--r--libbutl/optional.mxx147
-rw-r--r--libbutl/timestamp.cxx86
3 files changed, 376 insertions, 67 deletions
diff --git a/libbutl/optional.ixx b/libbutl/optional.ixx
new file mode 100644
index 0000000..2c40d30
--- /dev/null
+++ b/libbutl/optional.ixx
@@ -0,0 +1,210 @@
+// file : libbutl/optional.ixx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+namespace butl
+{
+ namespace details
+ {
+ // optional_data<T, false>
+ //
+
+ template <typename T>
+ inline optional_data<T, false>& optional_data<T, false>::
+ operator= (nullopt_t)
+ {
+ if (v_)
+ {
+ d_.~T ();
+ v_ = false;
+ }
+
+ return *this;
+ }
+
+ template <typename T>
+ inline optional_data<T, false>& optional_data<T, false>::
+ operator= (const T& v)
+ {
+ if (v_)
+ {
+ d_.~T ();
+ v_ = false;
+ }
+
+ new (&d_) T (v);
+ v_ = true;
+
+ return *this;
+ }
+
+ template <typename T>
+ inline optional_data<T, false>& optional_data<T, false>::
+ operator= (T&& v)
+ {
+ if (v_)
+ {
+ d_.~T ();
+ v_ = false;
+ }
+
+ new (&d_) T (std::move (v));
+ v_ = true;
+
+ return *this;
+ }
+
+ template <typename T>
+ inline optional_data<T, false>::
+ optional_data (const optional_data& o)
+ : v_ (o.v_)
+ {
+ if (v_)
+ new (&d_) T (o.d_);
+ }
+
+ template <typename T>
+ inline optional_data<T, false>::
+ optional_data (optional_data&& o)
+ : v_ (o.v_)
+ {
+ if (v_)
+ new (&d_) T (std::move (o.d_));
+ }
+
+ template <typename T>
+ inline optional_data<T, false>& optional_data<T, false>::
+ operator= (const optional_data& o)
+ {
+ if (v_)
+ {
+ d_.~T ();
+ v_ = false;
+ }
+
+ if (o.v_)
+ {
+ new (&d_) T (o.d_);
+ v_ = true;
+ }
+
+ return *this;
+ }
+
+ template <typename T>
+ inline optional_data<T, false>& optional_data<T, false>::
+ operator= (optional_data&& o)
+ {
+ if (v_)
+ {
+ d_.~T ();
+ v_ = false;
+ }
+
+ if (o.v_)
+ {
+ new (&d_) T (std::move (o.d_));
+ v_ = true;
+ }
+
+ return *this;
+ }
+
+ template <typename T>
+ inline optional_data<T, false>::
+ ~optional_data ()
+ {
+ if (v_)
+ d_.~T ();
+ }
+
+ // optional_data<T, true>
+ //
+
+ template <typename T>
+ inline optional_data<T, true>& optional_data<T, true>::
+ operator= (nullopt_t)
+ {
+ if (v_)
+ v_ = false;
+
+ return *this;
+ }
+
+ template <typename T>
+ inline optional_data<T, true>& optional_data<T, true>::
+ operator= (const T& v)
+ {
+ if (v_)
+ v_ = false;
+
+ new (&d_) T (v);
+ v_ = true;
+
+ return *this;
+ }
+
+ template <typename T>
+ inline optional_data<T, true>& optional_data<T, true>::
+ operator= (T&& v)
+ {
+ if (v_)
+ v_ = false;
+
+ new (&d_) T (std::move (v));
+ v_ = true;
+
+ return *this;
+ }
+
+ template <typename T>
+ inline optional_data<T, true>::
+ optional_data (const optional_data& o)
+ : v_ (o.v_)
+ {
+ if (v_)
+ new (&d_) T (o.d_);
+ }
+
+ template <typename T>
+ inline optional_data<T, true>::
+ optional_data (optional_data&& o)
+ : v_ (o.v_)
+ {
+ if (v_)
+ new (&d_) T (std::move (o.d_));
+ }
+
+ template <typename T>
+ inline optional_data<T, true>& optional_data<T, true>::
+ operator= (const optional_data& o)
+ {
+ if (v_)
+ v_ = false;
+
+ if (o.v_)
+ {
+ new (&d_) T (o.d_);
+ v_ = true;
+ }
+
+ return *this;
+ }
+
+ template <typename T>
+ inline optional_data<T, true>& optional_data<T, true>::
+ operator= (optional_data&& o)
+ {
+ if (v_)
+ v_ = false;
+
+ if (o.v_)
+ {
+ new (&d_) T (std::move (o.d_));
+ v_ = true;
+ }
+
+ return *this;
+ }
+ }
+}
diff --git a/libbutl/optional.mxx b/libbutl/optional.mxx
index cddf59a..ae72399 100644
--- a/libbutl/optional.mxx
+++ b/libbutl/optional.mxx
@@ -9,8 +9,9 @@
// C includes.
#ifndef __cpp_lib_modules
-#include <utility> // move()
-#include <functional> // hash
+#include <utility> // move()
+#include <functional> // hash
+#include <type_traits> // is_trivially_destructible
#endif
// Other includes.
@@ -34,55 +35,145 @@ LIBBUTL_MODEXPORT namespace butl
#endif
constexpr nullopt_t nullopt (1);
+ namespace details
+ {
+ template <typename T, bool = std::is_trivially_destructible<T>::value>
+ struct optional_data;
+
+ template <typename T>
+ struct optional_data<T, false>
+ {
+ struct empty {};
+
+ union
+ {
+ empty e_;
+ T d_;
+ };
+ bool v_;
+
+#if !defined(_MSC_VER) || _MSC_VER > 1900
+ constexpr optional_data (): e_ (), v_ (false) {}
+ constexpr optional_data (nullopt_t): e_ (), v_ (false) {}
+ constexpr optional_data (const T& v): d_ (v), v_ (true) {}
+ constexpr optional_data (T&& v): d_ (std::move (v)), v_ (true) {}
+#else
+ optional_data (): e_ (), v_ (false) {}
+ optional_data (nullopt_t): e_ (), v_ (false) {}
+ optional_data (const T& v): d_ (v), v_ (true) {}
+ optional_data (T&& v): d_ (std::move (v)), v_ (true) {}
+#endif
+
+ optional_data& operator= (nullopt_t);
+ optional_data& operator= (const T&);
+ optional_data& operator= (T&&);
+
+ optional_data (const optional_data&);
+ optional_data (optional_data&&);
+
+ optional_data& operator= (const optional_data&);
+ optional_data& operator= (optional_data&&);
+
+ ~optional_data ();
+ };
+
+ template <typename T>
+ struct optional_data<T, true>
+ {
+ struct empty {};
+
+ union
+ {
+ empty e_;
+ T d_;
+ };
+ bool v_;
+
+#if !defined(_MSC_VER) || _MSC_VER > 1900
+ constexpr optional_data (): e_ (), v_ (false) {}
+ constexpr optional_data (nullopt_t): e_ (), v_ (false) {}
+ constexpr optional_data (const T& v): d_ (v), v_ (true) {}
+ constexpr optional_data (T&& v): d_ (std::move (v)), v_ (true) {}
+#else
+ optional_data (): e_ (), v_ (false) {}
+ optional_data (nullopt_t): e_ (), v_ (false) {}
+ optional_data (const T& v): d_ (v), v_ (true) {}
+ optional_data (T&& v): d_ (std::move (v)), v_ (true) {}
+#endif
+
+ optional_data& operator= (nullopt_t);
+ optional_data& operator= (const T&);
+ optional_data& operator= (T&&);
+
+ optional_data (const optional_data&);
+ optional_data (optional_data&&);
+
+ optional_data& operator= (const optional_data&);
+ optional_data& operator= (optional_data&&);
+ };
+ }
+
template <typename T>
- class optional
+ class optional: private details::optional_data<T>
{
+ using base = details::optional_data<T>;
+
public:
- typedef T value_type;
+ using value_type = T;
+
+#if !defined(_MSC_VER) || _MSC_VER > 1900
+ constexpr optional () {}
+ constexpr optional (nullopt_t) {}
+ constexpr optional (const T& v): base (v) {}
+ constexpr optional (T&& v): base (std::move (v)) {}
+#else
+ optional () {}
+ optional (nullopt_t) {}
+ optional (const T& v): base (v) {}
+ optional (T&& v): base (std::move (v)) {}
+#endif
- constexpr optional (): value_ (), null_ (true) {} // VC14 needs value_().
- constexpr optional (nullopt_t): value_ (), null_ (true) {}
- constexpr optional (const T& v): value_ (v), null_ (false) {}
- constexpr optional (T&& v): value_ (std::move (v)), null_ (false) {}
+ optional& operator= (nullopt_t v) {static_cast<base&> (*this) = v; return *this;}
+ optional& operator= (const T& v) {static_cast<base&> (*this) = v; return *this;}
+ optional& operator= (T&& v) {static_cast<base&> (*this) = std::move (v); return *this;}
- optional& operator= (nullopt_t) {value_ = T (); null_ = true; return *this;}
- optional& operator= (const T& v) {value_ = v; null_ = false; return *this;}
- optional& operator= (T&& v) {value_ = std::move (v); null_ = false; return *this;}
+ T& value () {return this->d_;}
+ const T& value () const {return this->d_;}
- T& value () {return value_;}
- const T& value () const {return value_;}
+ T* operator-> () {return &value ();}
+ const T* operator-> () const {return &value ();}
- T* operator-> () {return &value_;}
- const T* operator-> () const {return &value_;}
+ T& operator* () {return value ();}
+ const T& operator* () const {return value ();}
- T& operator* () {return value_;}
- const T& operator* () const {return value_;}
+ bool has_value () const {return this->v_;}
+ explicit operator bool () const {return this->v_;}
- bool has_value () const {return !null_;}
- explicit operator bool () const {return !null_;}
+ optional (const optional&) = default;
+ optional (optional&&) = default;
- private:
- T value_;
- bool null_;
+ optional& operator= (const optional&) = default;
+ optional& operator= (optional&&) = default;
};
template <typename T>
inline auto
- operator== (const optional<T>& x, const optional<T>& y) -> decltype (*x == *y)
+ operator== (const optional<T>& x, const optional<T>& y)
{
- return static_cast<bool> (x) == static_cast<bool> (y) && (!x || *x == *y);
+ bool px (x), py (y);
+ return px == py && (!px || *x == *y);
}
template <typename T>
inline auto
- operator!= (const optional<T>& x, const optional<T>& y) -> decltype (x == y)
+ operator!= (const optional<T>& x, const optional<T>& y)
{
return !(x == y);
}
template <typename T>
inline auto
- operator< (const optional<T>& x, const optional<T>& y) -> decltype (*x < *y)
+ operator< (const optional<T>& x, const optional<T>& y)
{
bool px (x), py (y);
return px < py || (px && py && *x < *y);
@@ -90,7 +181,7 @@ LIBBUTL_MODEXPORT namespace butl
template <typename T>
inline auto
- operator> (const optional<T>& x, const optional<T>& y) -> decltype (*x > *y)
+ operator> (const optional<T>& x, const optional<T>& y)
{
return y < x;
}
@@ -111,3 +202,5 @@ namespace std
}
};
}
+
+#include <libbutl/optional.ixx>
diff --git a/libbutl/timestamp.cxx b/libbutl/timestamp.cxx
index 437ea52..b0bb9ad 100644
--- a/libbutl/timestamp.cxx
+++ b/libbutl/timestamp.cxx
@@ -89,33 +89,36 @@ using namespace std;
// of the std::tm argument.
//
#ifdef __GLIBCXX__
-namespace details
+namespace butl
{
- struct put_time_data
+ namespace details
{
- const std::tm* tm;
- const char* fmt;
- };
+ struct put_time_data
+ {
+ const std::tm* tm;
+ const char* fmt;
+ };
- inline put_time_data
- put_time (const std::tm* tm, const char* fmt)
- {
- return put_time_data {tm, fmt};
- }
+ inline put_time_data
+ put_time (const std::tm* tm, const char* fmt)
+ {
+ return put_time_data {tm, fmt};
+ }
- inline ostream&
- operator<< (ostream& os, const put_time_data& d)
- {
- char buf[256];
- if (strftime (buf, sizeof (buf), d.fmt, d.tm) != 0)
- os << buf;
- else
- os.setstate (ostream::badbit);
- return os;
+ inline ostream&
+ operator<< (ostream& os, const put_time_data& d)
+ {
+ char buf[256];
+ if (strftime (buf, sizeof (buf), d.fmt, d.tm) != 0)
+ os << buf;
+ else
+ os.setstate (ostream::badbit);
+ return os;
+ }
}
}
-using namespace details;
+using namespace butl::details;
#endif
// Thread-safe implementations of gmtime() and localtime().
@@ -133,36 +136,39 @@ using namespace details;
// one common tm structure per thread for the conversion", which mean that they
// are thread-safe.
//
-namespace details
+namespace butl
{
- static tm*
- gmtime (const time_t* t, tm* r)
+ namespace details
{
+ static tm*
+ gmtime (const time_t* t, tm* r)
+ {
#ifdef _WIN32
- const tm* gt (::gmtime (t));
- if (gt == nullptr)
- return nullptr;
+ const tm* gt (::gmtime (t));
+ if (gt == nullptr)
+ return nullptr;
- *r = *gt;
- return r;
+ *r = *gt;
+ return r;
#else
- return gmtime_r (t, r);
+ return gmtime_r (t, r);
#endif
- }
+ }
- static tm*
- localtime (const time_t* t, tm* r)
- {
+ static tm*
+ localtime (const time_t* t, tm* r)
+ {
#ifdef _WIN32
- const tm* lt (::localtime (t));
- if (lt == nullptr)
- return nullptr;
+ const tm* lt (::localtime (t));
+ if (lt == nullptr)
+ return nullptr;
- *r = *lt;
- return r;
+ *r = *lt;
+ return r;
#else
- return localtime_r (t, r);
+ return localtime_r (t, r);
#endif
+ }
}
}
@@ -219,7 +225,7 @@ timegm (tm* ctm)
// offset is effectively the time difference between MSK and GMT time zones.
//
tm gtm;
- if (details::gmtime (&t, &gtm) == nullptr)
+ if (butl::details::gmtime (&t, &gtm) == nullptr)
return e;
// gmtime() being called for the timepoint t returns 6 AM. So now we have