diff options
Diffstat (limited to 'intl/icu_capi/cpp/include/diplomat_runtime.hpp')
-rw-r--r-- | intl/icu_capi/cpp/include/diplomat_runtime.hpp | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/intl/icu_capi/cpp/include/diplomat_runtime.hpp b/intl/icu_capi/cpp/include/diplomat_runtime.hpp new file mode 100644 index 0000000000..841752280d --- /dev/null +++ b/intl/icu_capi/cpp/include/diplomat_runtime.hpp @@ -0,0 +1,175 @@ +#ifndef DIPLOMAT_RUNTIME_CPP_H +#define DIPLOMAT_RUNTIME_CPP_H + +#include <string> +#include <variant> +#include <array> +#include <optional> +#include <type_traits> + +#if __cplusplus >= 202002L +#include<span> +#endif + +#include "diplomat_runtime.h" + +namespace diplomat { + +extern "C" inline void Flush(capi::DiplomatWriteable* w) { + std::string* string = reinterpret_cast<std::string*>(w->context); + string->resize(w->len); +}; + +extern "C" inline bool Grow(capi::DiplomatWriteable* w, uintptr_t requested) { + std::string* string = reinterpret_cast<std::string*>(w->context); + string->resize(requested); + w->cap = string->length(); + w->buf = &(*string)[0]; + return true; +}; + +inline capi::DiplomatWriteable WriteableFromString(std::string& string) { + capi::DiplomatWriteable w; + w.context = &string; + w.buf = &string[0]; + w.len = string.length(); + // Same as length, since C++ strings are not supposed + // to be written to past their len; you resize *first* + w.cap = string.length(); + w.flush = Flush; + w.grow = Grow; + return w; +}; + +template<typename T> struct WriteableTrait { + // static inline capi::DiplomatWriteable Construct(T& t); +}; + + +template<> struct WriteableTrait<std::string> { + static inline capi::DiplomatWriteable Construct(std::string& t) { + return diplomat::WriteableFromString(t); + } +}; + +template<class T> struct Ok { + T inner; + explicit Ok(T&& i): inner(std::move(i)) {} + // We don't want to expose an lvalue-capable constructor in general + // however there is no problem doing this for trivially copyable types + template<typename X = T, typename = typename std::enable_if<std::is_trivially_copyable<X>::value>::type> + explicit Ok(const T& i): inner(i) {} + Ok() = default; + Ok(Ok&&) noexcept = default; + Ok(const Ok &) = default; + Ok& operator=(const Ok&) = default; + Ok& operator=(Ok&&) noexcept = default; +}; + +template<class T> struct Err { + T inner; + explicit Err(T&& i): inner(std::move(i)) {} + // We don't want to expose an lvalue-capable constructor in general + // however there is no problem doing this for trivially copyable types + template<typename X = T, typename = typename std::enable_if<std::is_trivially_copyable<X>::value>::type> + explicit Err(const T& i): inner(i) {} + Err() = default; + Err(Err&&) noexcept = default; + Err(const Err &) = default; + Err& operator=(const Err&) = default; + Err& operator=(Err&&) noexcept = default; +}; + +template<class T, class E> +class result { +private: + std::variant<Ok<T>, Err<E>> val; +public: + explicit result(Ok<T>&& v): val(std::move(v)) {} + explicit result(Err<E>&& v): val(std::move(v)) {} + result() = default; + result(const result &) = default; + result& operator=(const result&) = default; + result& operator=(Ok<T>&& t) { + this->val = Ok<T>(std::move(t)); + return *this; + } + result& operator=(Err<E>&& e) { + this->val = Err<E>(std::move(e)); + return *this; + } + result& operator=(result&&) noexcept = default; + result(result &&) noexcept = default; + ~result() = default; + bool is_ok() const { + return std::holds_alternative<Ok<T>>(this->val); + }; + bool is_err() const { + return std::holds_alternative<Err<E>>(this->val); + }; + + std::optional<T> ok() && { + if (!this->is_ok()) { + return std::nullopt; + } + return std::make_optional(std::move(std::get<Ok<T>>(std::move(this->val)).inner)); + }; + std::optional<E> err() && { + if (!this->is_err()) { + return std::nullopt; + } + return std::make_optional(std::move(std::get<Err<E>>(std::move(this->val)).inner)); + } + + void set_ok(T&& t) { + this->val = Ok<T>(std::move(t)); + } + + void set_err(E&& e) { + this->val = Err<E>(std::move(e)); + } + + template<typename T2> + result<T2, E> replace_ok(T2&& t) { + if (this->is_err()) { + return result<T2, E>(Err<E>(std::get<Err<E>>(std::move(this->val)))); + } else { + return result<T2, E>(Ok<T2>(std::move(t))); + } + } +}; + + +// Use custom std::span on C++17, otherwise use std::span +#if __cplusplus >= 202002L + +template<class T> using span = std::span<T>; + +#else // __cplusplus >= 202002L + +// C++-17-compatible std::span +template<class T> +class span { + +public: + constexpr span(T* data, size_t size) + : data_(data), size_(size) {} + template<size_t N> + explicit constexpr span(std::array<typename std::remove_const<T>::type, N>& arr) + : data_(const_cast<T*>(arr.data())), size_(N) {} + constexpr T* data() const noexcept { + return this->data_; + } + constexpr size_t size() const noexcept { + return this->size_; + } +private: + T* data_; + size_t size_; +}; + +#endif // __cplusplus >= 202002L + +} + +#endif |