aboutsummaryrefslogtreecommitdiff
path: root/c/util.h
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2022-09-02 00:09:56 +0200
committerJohn Ankarström <john@ankarstrom.se>2022-09-02 00:09:56 +0200
commitc624a89b4f1cccfefd60424a3181d76e4692fa4d (patch)
tree3449c8bcc9ad200c01fb2bed3154a68cb0c7c907 /c/util.h
parenta26488497cc765890dd5dff122a1f08ca6c5ca95 (diff)
downloadEpisodeBrowser-c624a89b4f1cccfefd60424a3181d76e4692fa4d.tar.gz
Add UniqueOk.
Diffstat (limited to 'c/util.h')
-rw-r--r--c/util.h66
1 files changed, 48 insertions, 18 deletions
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 <cstring>
#include <memory>
+#include <stdexcept>
#include <string>
#include <windows.h>
@@ -29,18 +30,12 @@ struct Finally
};
#define FINALLY Finally _ = [=]()
-template <typename T>
-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 <typename T, auto F = Delete<T>>
+template <typename T, auto F>
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 <typename, auto> class UniqueOk;
+ template <auto E>
+ UniqueOk<T, F> 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 <typename T, auto F>
+struct UniqueOk
+{
+ T v;
+ UniqueOk(Unique<T, F>&& 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<T, F>&& 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 <typename T>
struct Buf
@@ -96,10 +126,10 @@ struct Buf
Buf(T* data, size_t c) noexcept : data(data), c(c) {}
Buf(std::basic_string<T>& s) noexcept : data(s.data()), c(s.capacity()) {}
template <size_t N> 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<T> 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<T> operator +(size_t i) const noexcept { return {data+i, c-i}; }
//T operator -(size_t i) { return {data-i, c+i}; }
};