From c624a89b4f1cccfefd60424a3181d76e4692fa4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= Date: Fri, 2 Sep 2022 00:09:56 +0200 Subject: Add UniqueOk. --- c/util.h | 66 ++++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 18 deletions(-) (limited to 'c/util.h') diff --git a/c/util.h b/c/util.h index 7ed7636..eb2b2f8 100644 --- a/c/util.h +++ b/c/util.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -29,18 +30,12 @@ struct Finally }; #define FINALLY Finally _ = [=]() -template -inline void Delete(T v) noexcept -{ - delete v; -} - /* Unique is similar to unique_ptr, but it is designed for pointers * and handles of type T, where T is not an RAII class. Further, the * managed object is assumed to be in an invalid state until checked * with Good or Bad. Upon destruction, the object, if valid, is passed * to a given destructor function F. */ -template > +template struct Unique { union { T v; }; @@ -49,10 +44,7 @@ struct Unique Unique(T v) noexcept : v(v) {} Unique& operator =(T v_) noexcept { - if (ok) { - F(v); - v.~T(); - } + Destroy(); v = v_; ok = false; return *this; @@ -63,8 +55,7 @@ struct Unique } Unique& operator =(Unique&& other) noexcept { - if (ok) - F(v); + Destroy(); v = std::move(other.v); ok = other.ok; other.ok = false; @@ -78,15 +69,54 @@ struct Unique { return !(ok = v != u); } + template class UniqueOk; + template + UniqueOk ThrowIf(T u) noexcept + { + if (v == u) + throw E; + return std::move(*this); + } ~Unique() + { + Destroy(); + } +private: + void Destroy() { if (ok) { - F(v); + if constexpr (F) F(v); v.~T(); } } }; +/* UniqueOk contains a Unique that has already been validated. */ +template +struct UniqueOk +{ + T v; + UniqueOk(Unique&& u) : v(std::move(u.v)) + { + if (!u.ok) + throw std::runtime_error("cannot construct UniqueOk from non-ok Unique"); + u.ok = false; + } + UniqueOk& operator =(Unique&& u) + { + if (!u.ok) + throw std::runtime_error("cannot construct UniqueOk from non-ok Unique"); + F(v); + v = std::move(u.v); + u.ok = false; + return *this; + } + ~UniqueOk() + { + F(v); + } +}; + /* Buf is a span-like structure of a buffer and its size. */ template struct Buf @@ -96,10 +126,10 @@ struct Buf Buf(T* data, size_t c) noexcept : data(data), c(c) {} Buf(std::basic_string& s) noexcept : data(s.data()), c(s.capacity()) {} template Buf(T (&data)[N]) noexcept : data(data), c(N) {} - operator T*() noexcept { return data; } - T& operator *() noexcept { return *data; } - T& operator [](size_t i) noexcept { return data[i]; } - Buf operator +(size_t i) noexcept { return {data+i, c-i}; } + operator T*() const noexcept { return data; } + T& operator *() const noexcept { return *data; } + T& operator [](size_t i) const noexcept { return data[i]; } + Buf operator +(size_t i) const noexcept { return {data+i, c-i}; } //T operator -(size_t i) { return {data-i, c+i}; } }; -- cgit v1.2.3