aboutsummaryrefslogtreecommitdiff
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
parenta26488497cc765890dd5dff122a1f08ca6c5ca95 (diff)
downloadEpisodeBrowser-c624a89b4f1cccfefd60424a3181d76e4692fa4d.tar.gz
Add UniqueOk.
-rw-r--r--c/data.cpp27
-rw-r--r--c/layout.h8
-rw-r--r--c/util.h66
3 files changed, 66 insertions, 35 deletions
diff --git a/c/data.cpp b/c/data.cpp
index 7ae6ad1..d9df68c 100644
--- a/c/data.cpp
+++ b/c/data.cpp
@@ -11,16 +11,15 @@
#include "util.h"
#include "win.h"
-static Unique<HINTERNET, InternetCloseHandle> s_hi =
- InternetOpenW(L"Episode Browser", INTERNET_OPEN_TYPE_DIRECT, nullptr, nullptr, 0);
-
-Unique<htmlParserCtxtPtr, xmlFreeParserCtxt> RemoteParserCtxt(const wchar_t* wszUrl, const char* szUrl)
+UniqueOk<htmlParserCtxtPtr, xmlFreeParserCtxt> RemoteParserCtxt(const wchar_t* wszUrl, const char* szUrl)
{
- if (s_hi.Bad(0))
- throw Win32Error();
+ static Unique<HINTERNET, InternetCloseHandle> hi =
+ InternetOpenW(L"Episode Browser", INTERNET_OPEN_TYPE_DIRECT, nullptr, nullptr, 0);
+ if (hi.Bad(0))
+ throw Win32Error();
Unique<HINTERNET, InternetCloseHandle> hiUrl = InternetOpenUrlW(
- s_hi.v, wszUrl, nullptr, 0, INTERNET_FLAG_NO_UI, 0);
+ hi.v, wszUrl, nullptr, 0, INTERNET_FLAG_NO_UI, 0);
if (hiUrl.Bad(0))
throw InternetError();
@@ -81,7 +80,7 @@ bool WcharsFromXmlchars(wchar_t (&dst)[N], Unique<xmlChar*, XmlFree> utf8)
* shared byte. At any given time, only a single fetch thread may be
* performing work. */
-enum Signal
+enum Signal : unsigned char
{
READY = 1<<0, /* Main -> fetch: start working! */
DONE = 1<<1, /* Fetch -> main: work is done. */
@@ -161,7 +160,7 @@ void FetchData(unsigned char* sig)
* specific XPath query. This is fragile theoretically, but
* unlikely to break practically. */
- Unique<htmlParserCtxtPtr, xmlFreeParserCtxt> ctx =
+ UniqueOk<htmlParserCtxtPtr, xmlFreeParserCtxt> ctx =
RemoteParserCtxt(L"https://www.detectiveconanworld.com/wiki/Anime",
"https://www.detectiveconanworld.com/wiki/Anime");
@@ -251,6 +250,9 @@ void FetchScreenwriters(unsigned char* sig)
const wchar_t prefix[] = L"https://www.detectiveconanworld.com";
wchar_t url[256];
Wcscpy(url, prefix);
+
+ Unique<xmlXPathContextPtr, xmlXPathFreeContext> xpathCtx;
+ Unique<xmlXPathObjectPtr, xmlXPathFreeObject> xpathObj;
for (iLast++; iLast < iMax; iLast++) {
if (*sig & ABORT)
return;
@@ -265,13 +267,12 @@ void FetchScreenwriters(unsigned char* sig)
/* Retrieve screenwriter from HTML. */
- Unique<htmlParserCtxtPtr, xmlFreeParserCtxt> ctx = RemoteParserCtxt(url, nullptr);
- Unique<xmlXPathContextPtr, xmlXPathFreeContext> xpathCtx = xmlXPathNewContext(ctx.v->myDoc);
+ UniqueOk<htmlParserCtxtPtr, xmlFreeParserCtxt> ctx = RemoteParserCtxt(url, nullptr);
+ xpathCtx = xmlXPathNewContext(ctx.v->myDoc);
if (xpathCtx.Bad(0))
throw XmlError();
- Unique<xmlXPathObjectPtr, xmlXPathFreeObject> xpathObj =
- xmlXPathEvalExpression(reinterpret_cast<const xmlChar*>(
+ xpathObj = xmlXPathEvalExpression(reinterpret_cast<const xmlChar*>(
"//th[contains(text(), 'Screenplay:')]/following-sibling::td"),
xpathCtx.v);
if (xpathObj.Bad(0))
diff --git a/c/layout.h b/c/layout.h
index 937a50c..07eee56 100644
--- a/c/layout.h
+++ b/c/layout.h
@@ -21,13 +21,13 @@ struct Dragger
protected:
bool IsDown() const;
bool IsDouble(const long time, const POINT& pt);
- virtual bool InDragArea(int x, int y) const;
+ virtual bool InDragArea(int x, int y) const = 0;
/* Perform drag, resizing relevant windows. */
- virtual void Drag(int x, int y) const;
+ virtual void Drag(int x, int y) const = 0;
/* Reset dragger to automatic position. */
- virtual void Reset() const;
+ virtual void Reset() const = 0;
/* Called after drag, when mouse button is released. */
- virtual void Done() const;
+ virtual void Done() const = 0;
private:
bool m_bActive = false;
long m_time0 = 0;
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}; }
};