ICU4X
International Components for Unicode
All Classes Namespaces Files Functions Variables Typedefs Macros Pages
diplomat_runtime.hpp
Go to the documentation of this file.
1#ifndef DIPLOMAT_RUNTIME_CPP_H
2#define DIPLOMAT_RUNTIME_CPP_H
3
4#include <optional>
5#include <string>
6#include <type_traits>
7#include <variant>
8#include <cstdint>
9#include <functional>
10
11#if __cplusplus >= 202002L
12#include <span>
13#else
14#include <array>
15#endif
16
17namespace diplomat {
18
19namespace capi {
20extern "C" {
21
22static_assert(sizeof(char) == sizeof(uint8_t), "your architecture's `char` is not 8 bits");
23static_assert(sizeof(char16_t) == sizeof(uint16_t), "your architecture's `char16_t` is not 16 bits");
24static_assert(sizeof(char32_t) == sizeof(uint32_t), "your architecture's `char32_t` is not 32 bits");
25
26typedef struct DiplomatWrite {
27 void* context;
28 char* buf;
29 size_t len;
30 size_t cap;
31 bool grow_failed;
32 void (*flush)(struct DiplomatWrite*);
33 bool (*grow)(struct DiplomatWrite*, size_t);
34} DiplomatWrite;
35
36bool diplomat_is_str(const char* buf, size_t len);
37
38#define MAKE_SLICES(name, c_ty) \
39 typedef struct Diplomat##name##View { \
40 const c_ty* data; \
41 size_t len; \
42 } Diplomat##name##View; \
43 typedef struct Diplomat##name##ViewMut { \
44 c_ty* data; \
45 size_t len; \
46 } Diplomat##name##ViewMut; \
47 typedef struct Diplomat##name##Array { \
48 const c_ty* data; \
49 size_t len; \
50 } Diplomat##name##Array;
51
52#define MAKE_SLICES_AND_OPTIONS(name, c_ty) \
53 MAKE_SLICES(name, c_ty) \
54 typedef struct Option##name {union { c_ty ok; }; bool is_ok; } Option##name; \
55 typedef struct Option##name##View {union { Diplomat##name##View ok; }; bool is_ok; } Option##name##View; \
56 typedef struct Option##name##ViewMut {union { Diplomat##name##ViewMut ok; }; bool is_ok; } Option##name##ViewMut; \
57 typedef struct Option##name##Array {union { Diplomat##name##Array ok; }; bool is_ok; } Option##name##Array; \
58
60MAKE_SLICES_AND_OPTIONS(U8, uint8_t)
61MAKE_SLICES_AND_OPTIONS(I16, int16_t)
62MAKE_SLICES_AND_OPTIONS(U16, uint16_t)
63MAKE_SLICES_AND_OPTIONS(I32, int32_t)
64MAKE_SLICES_AND_OPTIONS(U32, uint32_t)
65MAKE_SLICES_AND_OPTIONS(I64, int64_t)
66MAKE_SLICES_AND_OPTIONS(U64, uint64_t)
67MAKE_SLICES_AND_OPTIONS(Isize, intptr_t)
68MAKE_SLICES_AND_OPTIONS(Usize, size_t)
70MAKE_SLICES_AND_OPTIONS(F64, double)
72MAKE_SLICES_AND_OPTIONS(Char, char32_t)
73MAKE_SLICES_AND_OPTIONS(String, char)
74MAKE_SLICES_AND_OPTIONS(String16, char16_t)
75MAKE_SLICES_AND_OPTIONS(Strings, DiplomatStringView)
76MAKE_SLICES_AND_OPTIONS(Strings16, DiplomatString16View)
77
78} // extern "C"
79} // namespace capi
80
81extern "C" inline void _flush(capi::DiplomatWrite* w) {
82 std::string* string = reinterpret_cast<std::string*>(w->context);
83 string->resize(w->len);
84}
85
86extern "C" inline bool _grow(capi::DiplomatWrite* w, uintptr_t requested) {
87 std::string* string = reinterpret_cast<std::string*>(w->context);
88 string->resize(requested);
89 w->cap = string->length();
90 w->buf = &(*string)[0];
91 return true;
92}
93
94inline capi::DiplomatWrite WriteFromString(std::string& string) {
95 capi::DiplomatWrite w;
96 w.context = &string;
97 w.buf = &string[0];
98 w.len = string.length();
99 w.cap = string.length();
100 // Will never become true, as _grow is infallible.
101 w.grow_failed = false;
102 w.flush = _flush;
103 w.grow = _grow;
104 return w;
105}
106
107template<class T> struct Ok {
109 Ok(T&& i): inner(std::forward<T>(i)) {}
110 // We don't want to expose an lvalue-capable constructor in general
111 // however there is no problem doing this for trivially copyable types
112 template<typename X = T, typename = typename std::enable_if<std::is_trivially_copyable<X>::value>::type>
113 Ok(T i): inner(i) {}
114 Ok() = default;
115 Ok(Ok&&) noexcept = default;
116 Ok(const Ok &) = default;
117 Ok& operator=(const Ok&) = default;
118 Ok& operator=(Ok&&) noexcept = default;
119};
120
121template<class T> struct Err {
123 Err(T&& i): inner(std::forward<T>(i)) {}
124 // We don't want to expose an lvalue-capable constructor in general
125 // however there is no problem doing this for trivially copyable types
126 template<typename X = T, typename = typename std::enable_if<std::is_trivially_copyable<X>::value>::type>
127 Err(T i): inner(i) {}
128 Err() = default;
129 Err(Err&&) noexcept = default;
130 Err(const Err &) = default;
131 Err& operator=(const Err&) = default;
132 Err& operator=(Err&&) noexcept = default;
133};
134
135template<class T, class E>
136class result {
137private:
138 std::variant<Ok<T>, Err<E>> val;
139public:
140 result(Ok<T>&& v): val(std::move(v)) {}
141 result(Err<E>&& v): val(std::move(v)) {}
142 result() = default;
143 result(const result &) = default;
144 result& operator=(const result&) = default;
145 result& operator=(result&&) noexcept = default;
146 result(result &&) noexcept = default;
147 ~result() = default;
148 bool is_ok() const {
149 return std::holds_alternative<Ok<T>>(this->val);
150 }
151 bool is_err() const {
152 return std::holds_alternative<Err<E>>(this->val);
153 }
154
155 template<typename U = T, typename std::enable_if_t<!std::is_reference_v<U>, std::nullptr_t> = nullptr>
156 std::optional<T> ok() && {
157 if (!this->is_ok()) {
158 return std::nullopt;
159 }
160 return std::make_optional(std::move(std::get<Ok<T>>(std::move(this->val)).inner));
161 }
162
163 template<typename U = E, typename std::enable_if_t<!std::is_reference_v<U>, std::nullptr_t> = nullptr>
164 std::optional<E> err() && {
165 if (!this->is_err()) {
166 return std::nullopt;
167 }
168 return std::make_optional(std::move(std::get<Err<E>>(std::move(this->val)).inner));
169 }
170
171 // std::optional does not work with reference types directly, so wrap them if present
172 template<typename U = T, typename std::enable_if_t<std::is_reference_v<U>, std::nullptr_t> = nullptr>
173 std::optional<std::reference_wrapper<std::remove_reference_t<T>>> ok() && {
174 if (!this->is_ok()) {
175 return std::nullopt;
176 }
177 return std::make_optional(std::reference_wrapper(std::forward<T>(std::get<Ok<T>>(std::move(this->val)).inner)));
178 }
179
180 template<typename U = E, typename std::enable_if_t<std::is_reference_v<U>, std::nullptr_t> = nullptr>
181 std::optional<std::reference_wrapper<std::remove_reference_t<E>>> err() && {
182 if (!this->is_err()) {
183 return std::nullopt;
184 }
185 return std::make_optional(std::reference_wrapper(std::forward<E>(std::get<Err<E>>(std::move(this->val)).inner)));
186 }
187
188 void set_ok(T&& t) {
189 this->val = Ok<T>(std::move(t));
190 }
191
192 void set_err(E&& e) {
193 this->val = Err<E>(std::move(e));
194 }
195
196 template<typename T2>
198 if (this->is_err()) {
199 return result<T2, E>(Err<E>(std::get<Err<E>>(std::move(this->val))));
200 } else {
201 return result<T2, E>(Ok<T2>(std::move(t)));
202 }
203 }
204};
205
206class Utf8Error {};
207
208// Use custom std::span on C++17, otherwise use std::span
209#if __cplusplus >= 202002L
210
211template<class T> using span = std::span<T>;
212
213#else // __cplusplus < 202002L
214
215// C++-17-compatible std::span
216template<class T>
217class span {
218
219public:
220 constexpr span(T* data, size_t size)
221 : data_(data), size_(size) {}
222 template<size_t N>
223 constexpr span(std::array<typename std::remove_const<T>::type, N>& arr)
224 : data_(const_cast<T*>(arr.data())), size_(N) {}
225 constexpr T* data() const noexcept {
226 return this->data_;
227 }
228 constexpr size_t size() const noexcept {
229 return this->size_;
230 }
231private:
232 T* data_;
233 size_t size_;
234};
235
236#endif // __cplusplus >= 202002L
237
238// Interop between std::function & our C Callback wrapper type
239
240template <typename T> struct fn_traits;
241template <typename Ret, typename... Args> struct fn_traits<std::function<Ret(Args...)>> {
242 using fn_ptr_t = Ret(Args...);
243 using function_t = std::function<fn_ptr_t>;
244 using ret = Ret;
245
246 template <typename T, typename = void>
247 struct as_ffi {
248 using type = T;
249 };
250
251 template <typename T>
252 struct as_ffi<T, std::void_t<decltype(&T::AsFFI)>> {
253 using type = decltype(std::declval<T>().AsFFI());
254 };
255
256 template<typename T>
257 using as_ffi_t = typename as_ffi<T>::type;
258
259 template<typename T>
260 using replace_string_view_t = std::conditional_t<std::is_same_v<T, std::string_view>, capi::DiplomatStringView, T>;
261
262 template<typename T>
264
265 // For a given T, creates a function that take in the C ABI version & return the C++ type.
266 template<typename T>
267 static T replace(replace_fn_t<T> val) {
268 if constexpr(std::is_same_v<T, std::string_view>) {
269 return std::string_view{val.data, val.len};
270 } else if constexpr(!std::is_same_v<T, as_ffi_t<T>>) {
271 return T::FromFFI(val);
272 }
273 else {
274 return val;
275 }
276 }
277
278 static Ret c_run_callback(const void *cb, replace_fn_t<Args>... args) {
279 return (*reinterpret_cast<const function_t *>(cb))(replace<Args>(args)...);
280 }
281
282 static void c_delete(const void *cb) {
283 delete reinterpret_cast<const function_t *>(cb);
284 }
285
286 fn_traits(function_t) {} // Allows less clunky construction (avoids decltype)
287};
288
289// additional deduction guide required
290template<class T>
292
293} // namespace diplomat
294
295#endif
Definition: diplomat_runtime.hpp:206
Definition: diplomat_runtime.hpp:136
result(Err< E > &&v)
Definition: diplomat_runtime.hpp:141
result(const result &)=default
result & operator=(const result &)=default
result & operator=(result &&) noexcept=default
bool is_err() const
Definition: diplomat_runtime.hpp:151
result(Ok< T > &&v)
Definition: diplomat_runtime.hpp:140
std::optional< T > ok() &&
Definition: diplomat_runtime.hpp:156
std::optional< E > err() &&
Definition: diplomat_runtime.hpp:164
std::optional< std::reference_wrapper< std::remove_reference_t< E > > > err() &&
Definition: diplomat_runtime.hpp:181
void set_ok(T &&t)
Definition: diplomat_runtime.hpp:188
result< T2, E > replace_ok(T2 &&t)
Definition: diplomat_runtime.hpp:197
result()=default
std::optional< std::reference_wrapper< std::remove_reference_t< T > > > ok() &&
Definition: diplomat_runtime.hpp:173
void set_err(E &&e)
Definition: diplomat_runtime.hpp:192
Definition: diplomat_runtime.hpp:217
constexpr T * data() const noexcept
Definition: diplomat_runtime.hpp:225
constexpr size_t size() const noexcept
Definition: diplomat_runtime.hpp:228
constexpr span(std::array< typename std::remove_const< T >::type, N > &arr)
Definition: diplomat_runtime.hpp:223
constexpr span(T *data, size_t size)
Definition: diplomat_runtime.hpp:220
#define MAKE_SLICES_AND_OPTIONS(name, c_ty)
Definition: diplomat_runtime.hpp:52
Definition: diplomat_runtime.hpp:17
bool _grow(capi::DiplomatWrite *w, uintptr_t requested)
Definition: diplomat_runtime.hpp:86
void _flush(capi::DiplomatWrite *w)
Definition: diplomat_runtime.hpp:81
capi::DiplomatWrite WriteFromString(std::string &string)
Definition: diplomat_runtime.hpp:94
Definition: diplomat_runtime.hpp:121
Err(T i)
Definition: diplomat_runtime.hpp:127
T inner
Definition: diplomat_runtime.hpp:122
Err(T &&i)
Definition: diplomat_runtime.hpp:123
Err(Err &&) noexcept=default
Err()=default
Definition: diplomat_runtime.hpp:107
Ok(T i)
Definition: diplomat_runtime.hpp:113
Ok(T &&i)
Definition: diplomat_runtime.hpp:109
T inner
Definition: diplomat_runtime.hpp:108
Ok()=default
Ok(Ok &&) noexcept=default
Ret ret
Definition: diplomat_runtime.hpp:244
typename as_ffi< T >::type as_ffi_t
Definition: diplomat_runtime.hpp:257
fn_traits(function_t)
Definition: diplomat_runtime.hpp:286
std::conditional_t< std::is_same_v< T, std::string_view >, capi::DiplomatStringView, T > replace_string_view_t
Definition: diplomat_runtime.hpp:260
static T replace(replace_fn_t< T > val)
Definition: diplomat_runtime.hpp:267
std::function< fn_ptr_t > function_t
Definition: diplomat_runtime.hpp:243
static void c_delete(const void *cb)
Definition: diplomat_runtime.hpp:282
replace_string_view_t< as_ffi_t< T > > replace_fn_t
Definition: diplomat_runtime.hpp:263
static Ret c_run_callback(const void *cb, replace_fn_t< Args >... args)
Definition: diplomat_runtime.hpp:278
Ret(Args...) fn_ptr_t
Definition: diplomat_runtime.hpp:242
Definition: diplomat_runtime.hpp:240