ICU4X
International Components for Unicode
Loading...
Searching...
No Matches
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 <string_view>
7#include <type_traits>
8#include <variant>
9#include <cstdint>
10#include <functional>
11#include <memory>
12#include <limits>
13
14
15#if __cplusplus >= 202002L
16#include <span>
17#else
18#include <array>
19#endif
20
21namespace diplomat {
22
23namespace capi {
24extern "C" {
25
26static_assert(sizeof(char) == sizeof(uint8_t), "your architecture's `char` is not 8 bits");
27static_assert(sizeof(char16_t) == sizeof(uint16_t), "your architecture's `char16_t` is not 16 bits");
28static_assert(sizeof(char32_t) == sizeof(uint32_t), "your architecture's `char32_t` is not 32 bits");
29
30typedef struct DiplomatWrite {
31 void* context;
32 char* buf;
33 size_t len;
34 size_t cap;
35 bool grow_failed;
36 void (*flush)(struct DiplomatWrite*);
37 bool (*grow)(struct DiplomatWrite*, size_t);
38} DiplomatWrite;
39
40bool diplomat_is_str(const char* buf, size_t len);
41
42#define MAKE_SLICES(name, c_ty) \
43 typedef struct Diplomat##name##View { \
44 const c_ty* data; \
45 size_t len; \
46 } Diplomat##name##View; \
47 typedef struct Diplomat##name##ViewMut { \
48 c_ty* data; \
49 size_t len; \
50 } Diplomat##name##ViewMut; \
51 typedef struct Diplomat##name##Array { \
52 const c_ty* data; \
53 size_t len; \
54 } Diplomat##name##Array;
55
56#define MAKE_SLICES_AND_OPTIONS(name, c_ty) \
57 MAKE_SLICES(name, c_ty) \
58 typedef struct Option##name {union { c_ty ok; }; bool is_ok; } Option##name; \
59 typedef struct Option##name##View {union { Diplomat##name##View ok; }; bool is_ok; } Option##name##View; \
60 typedef struct Option##name##ViewMut {union { Diplomat##name##ViewMut ok; }; bool is_ok; } Option##name##ViewMut; \
61 typedef struct Option##name##Array {union { Diplomat##name##Array ok; }; bool is_ok; } Option##name##Array; \
62
64MAKE_SLICES_AND_OPTIONS(U8, uint8_t)
65MAKE_SLICES_AND_OPTIONS(I16, int16_t)
66MAKE_SLICES_AND_OPTIONS(U16, uint16_t)
67MAKE_SLICES_AND_OPTIONS(I32, int32_t)
68MAKE_SLICES_AND_OPTIONS(U32, uint32_t)
69MAKE_SLICES_AND_OPTIONS(I64, int64_t)
70MAKE_SLICES_AND_OPTIONS(U64, uint64_t)
71MAKE_SLICES_AND_OPTIONS(Isize, intptr_t)
72MAKE_SLICES_AND_OPTIONS(Usize, size_t)
74MAKE_SLICES_AND_OPTIONS(F64, double)
76MAKE_SLICES_AND_OPTIONS(Char, char32_t)
77MAKE_SLICES_AND_OPTIONS(String, char)
78MAKE_SLICES_AND_OPTIONS(String16, char16_t)
79MAKE_SLICES_AND_OPTIONS(Strings, DiplomatStringView)
80MAKE_SLICES_AND_OPTIONS(Strings16, DiplomatString16View)
81
82} // extern "C"
83} // namespace capi
84
85extern "C" inline void _flush(capi::DiplomatWrite* w) {
86 std::string* string = reinterpret_cast<std::string*>(w->context);
87 string->resize(w->len);
88}
89
90extern "C" inline bool _grow(capi::DiplomatWrite* w, uintptr_t requested) {
91 std::string* string = reinterpret_cast<std::string*>(w->context);
92 string->resize(requested);
93 w->cap = string->length();
94 w->buf = &(*string)[0];
95 return true;
96}
97
98inline capi::DiplomatWrite WriteFromString(std::string& string) {
99 capi::DiplomatWrite w;
100 w.context = &string;
101 w.buf = &string[0];
102 w.len = string.length();
103 w.cap = string.length();
104 // Will never become true, as _grow is infallible.
105 w.grow_failed = false;
106 w.flush = _flush;
107 w.grow = _grow;
108 return w;
109}
110
111template<class T> struct Ok {
113 Ok(T&& i): inner(std::forward<T>(i)) {}
114 // We don't want to expose an lvalue-capable constructor in general
115 // however there is no problem doing this for trivially copyable types
116 template<typename X = T, typename = typename std::enable_if<std::is_trivially_copyable<X>::value>::type>
117 Ok(T i): inner(i) {}
118 Ok() = default;
119 Ok(Ok&&) noexcept = default;
120 Ok(const Ok &) = default;
121 Ok& operator=(const Ok&) = default;
122 Ok& operator=(Ok&&) noexcept = default;
123};
124
125template<class T> struct Err {
127 Err(T&& i): inner(std::forward<T>(i)) {}
128 // We don't want to expose an lvalue-capable constructor in general
129 // however there is no problem doing this for trivially copyable types
130 template<typename X = T, typename = typename std::enable_if<std::is_trivially_copyable<X>::value>::type>
131 Err(T i): inner(i) {}
132 Err() = default;
133 Err(Err&&) noexcept = default;
134 Err(const Err &) = default;
135 Err& operator=(const Err&) = default;
136 Err& operator=(Err&&) noexcept = default;
137};
138
139template<class T, class E>
140class result {
141private:
142 std::variant<Ok<T>, Err<E>> val;
143public:
144 result(Ok<T>&& v): val(std::move(v)) {}
145 result(Err<E>&& v): val(std::move(v)) {}
146 result() = default;
147 result(const result &) = default;
148 result& operator=(const result&) = default;
149 result& operator=(result&&) noexcept = default;
150 result(result &&) noexcept = default;
151 ~result() = default;
152 bool is_ok() const {
153 return std::holds_alternative<Ok<T>>(this->val);
154 }
155 bool is_err() const {
156 return std::holds_alternative<Err<E>>(this->val);
157 }
158
159 template<typename U = T, typename std::enable_if_t<!std::is_reference_v<U>, std::nullptr_t> = nullptr>
160 std::optional<T> ok() && {
161 if (!this->is_ok()) {
162 return std::nullopt;
163 }
164 return std::make_optional(std::move(std::get<Ok<T>>(std::move(this->val)).inner));
165 }
166
167 template<typename U = E, typename std::enable_if_t<!std::is_reference_v<U>, std::nullptr_t> = nullptr>
168 std::optional<E> err() && {
169 if (!this->is_err()) {
170 return std::nullopt;
171 }
172 return std::make_optional(std::move(std::get<Err<E>>(std::move(this->val)).inner));
173 }
174
175 // std::optional does not work with reference types directly, so wrap them if present
176 template<typename U = T, typename std::enable_if_t<std::is_reference_v<U>, std::nullptr_t> = nullptr>
177 std::optional<std::reference_wrapper<std::remove_reference_t<T>>> ok() && {
178 if (!this->is_ok()) {
179 return std::nullopt;
180 }
181 return std::make_optional(std::reference_wrapper(std::forward<T>(std::get<Ok<T>>(std::move(this->val)).inner)));
182 }
183
184 template<typename U = E, typename std::enable_if_t<std::is_reference_v<U>, std::nullptr_t> = nullptr>
185 std::optional<std::reference_wrapper<std::remove_reference_t<E>>> err() && {
186 if (!this->is_err()) {
187 return std::nullopt;
188 }
189 return std::make_optional(std::reference_wrapper(std::forward<E>(std::get<Err<E>>(std::move(this->val)).inner)));
190 }
191
192 void set_ok(T&& t) {
193 this->val = Ok<T>(std::move(t));
194 }
195
196 void set_err(E&& e) {
197 this->val = Err<E>(std::move(e));
198 }
199
200 template<typename T2>
202 if (this->is_err()) {
203 return result<T2, E>(Err<E>(std::get<Err<E>>(std::move(this->val))));
204 } else {
205 return result<T2, E>(Ok<T2>(std::move(t)));
206 }
207 }
208};
209
210class Utf8Error {};
211
212// Use custom std::span on C++17, otherwise use std::span
213#if __cplusplus >= 202002L
214
215constexpr std::size_t dynamic_extent = std::dynamic_extent;
216template<class T, std::size_t E = dynamic_extent> using span = std::span<T, E>;
217
218#else // __cplusplus < 202002L
219
220// C++-17-compatible-ish std::span
221constexpr size_t dynamic_extent = std::numeric_limits<std::size_t>::max();
222template <class T, std::size_t Extent = dynamic_extent>
223class span {
224public:
225 constexpr span(T *data = nullptr, size_t size = Extent)
226 : data_(data), size_(size) {}
227
228 constexpr span(const span<T> &o)
229 : data_(o.data_), size_(o.size_) {}
230 template <size_t N>
231 constexpr span(std::array<typename std::remove_const_t<T>, N> &arr)
232 : data_(const_cast<T *>(arr.data())), size_(N) {}
233
234 constexpr T* data() const noexcept {
235 return this->data_;
236 }
237 constexpr size_t size() const noexcept {
238 return this->size_;
239 }
240
241 constexpr T *begin() const noexcept { return data(); }
242 constexpr T *end() const noexcept { return data() + size(); }
243
245 data_ = o.data_;
246 size_ = o.size_;
247 }
248
249private:
250 T* data_;
251 size_t size_;
252};
253
254#endif // __cplusplus >= 202002L
255
256// Interop between std::function & our C Callback wrapper type
257
258template <typename T, typename = void>
259struct as_ffi {
260 using type = T;
261};
262
263template <typename T>
264struct as_ffi<T, std::void_t<decltype(std::declval<std::remove_pointer_t<T>>().AsFFI())>> {
265 using type = decltype(std::declval<std::remove_pointer_t<T>>().AsFFI());
266};
267
268template<typename T>
269using as_ffi_t = typename as_ffi<T>::type;
270
271template<typename T>
272using replace_string_view_t = std::conditional_t<std::is_same_v<T, std::string_view>, capi::DiplomatStringView, T>;
273
274template<typename T>
275using replace_ref_with_ptr_t = std::conditional_t<std::is_reference_v<T>, std::add_pointer_t<std::remove_reference_t<T>>, T>;
276
278template<typename T>
280
281template <typename T> struct fn_traits;
282template <typename Ret, typename... Args> struct fn_traits<std::function<Ret(Args...)>> {
283 using fn_ptr_t = Ret(Args...);
284 using function_t = std::function<fn_ptr_t>;
285 using ret = Ret;
286
287 // For a given T, creates a function that take in the C ABI version & return the C++ type.
288 template<typename T>
289 static T replace(replace_fn_t<T> val) {
290 if constexpr(std::is_same_v<T, std::string_view>) {
291 return std::string_view{val.data, val.len};
292 } else if constexpr (!std::is_same_v<T, as_ffi_t<T>>) {
293 if constexpr (std::is_lvalue_reference_v<T>) {
294 return *std::remove_reference_t<T>::FromFFI(val);
295 }
296 else {
297 return T::FromFFI(val);
298 }
299 }
300 else {
301 return val;
302 }
303 }
304
305 static Ret c_run_callback(const void *cb, replace_fn_t<Args>... args) {
306 return (*reinterpret_cast<const function_t *>(cb))(replace<Args>(args)...);
307 }
308
309 static void c_delete(const void *cb) {
310 delete reinterpret_cast<const function_t *>(cb);
311 }
312
313 fn_traits(function_t) {} // Allows less clunky construction (avoids decltype)
314};
315
316// additional deduction guide required
317template<class T>
319
320// Trait for extracting inner types from either std::optional or std::unique_ptr.
321// These are the two potential types returned by next() functions
322template<typename T> struct inner { using type = T; };
323template<typename T> struct inner<std::unique_ptr<T>> { using type = T; };
324template<typename T> struct inner<std::optional<T>>{ using type = T; };
325
326template<typename T, typename U = typename inner<T>::type>
327inline const U get_inner_if_present(T v) {
328 if constexpr(std::is_same_v<T,U>) {
329 return std::move(v);
330 } else {
331 return *std::move(v);
332 }
333}
334
335// Adapter for iterator types
336template<typename T, typename U = void> struct has_next : std::false_type {};
337template<typename T> struct has_next < T, std::void_t<decltype(std::declval<T>().next())>> : std::true_type {};
338template<typename T> constexpr bool has_next_v = has_next<T>::value;
339
341template<typename T>
343 static_assert(has_next_v<T>, "next_to_iter_helper may only be used with types implementing next()");
344 using next_type = decltype(std::declval<T>().next());
345
346 // STL Iterator trait definitions
348 using difference_type = void;
349 using reference = std::add_lvalue_reference_t<value_type>;
350 using iterator_category = std::input_iterator_tag;
351
352 next_to_iter_helper(std::unique_ptr<T>&& ptr) : _ptr(std::move(ptr)), _curr(_ptr->next()) {}
353
354 // https://en.cppreference.com/w/cpp/named_req/InputIterator requires that the type be copyable
356
357 void operator++() { _curr = _ptr->next(); }
358 void operator++(int) { ++(*this); }
359 const value_type& operator*() const { return *_curr; }
360
361 bool operator!=(std::nullopt_t) {
362 return (bool)_curr;
363 }
364
365 std::shared_ptr<T> _ptr; // shared to satisfy the copyable requirement
367};
368
369} // namespace diplomat
370
371#endif
Definition diplomat_runtime.hpp:210
result(Err< E > &&v)
Definition diplomat_runtime.hpp:145
result(const result &)=default
result & operator=(const result &)=default
result & operator=(result &&) noexcept=default
bool is_err() const
Definition diplomat_runtime.hpp:155
result(Ok< T > &&v)
Definition diplomat_runtime.hpp:144
std::optional< T > ok() &&
Definition diplomat_runtime.hpp:160
std::optional< E > err() &&
Definition diplomat_runtime.hpp:168
std::optional< std::reference_wrapper< std::remove_reference_t< E > > > err() &&
Definition diplomat_runtime.hpp:185
void set_ok(T &&t)
Definition diplomat_runtime.hpp:192
bool is_ok() const
Definition diplomat_runtime.hpp:152
result< T2, E > replace_ok(T2 &&t)
Definition diplomat_runtime.hpp:201
result()=default
std::optional< std::reference_wrapper< std::remove_reference_t< T > > > ok() &&
Definition diplomat_runtime.hpp:177
void set_err(E &&e)
Definition diplomat_runtime.hpp:196
Definition diplomat_runtime.hpp:223
void operator=(span< T > o)
Definition diplomat_runtime.hpp:244
constexpr T * data() const noexcept
Definition diplomat_runtime.hpp:234
constexpr T * begin() const noexcept
Definition diplomat_runtime.hpp:241
constexpr span(T *data=nullptr, size_t size=Extent)
Definition diplomat_runtime.hpp:225
constexpr span(const span< T > &o)
Definition diplomat_runtime.hpp:228
constexpr span(std::array< typename std::remove_const_t< T >, N > &arr)
Definition diplomat_runtime.hpp:231
constexpr size_t size() const noexcept
Definition diplomat_runtime.hpp:237
constexpr T * end() const noexcept
Definition diplomat_runtime.hpp:242
#define MAKE_SLICES_AND_OPTIONS(name, c_ty)
Definition diplomat_runtime.hpp:56
Definition diplomat_runtime.hpp:21
constexpr bool has_next_v
Definition diplomat_runtime.hpp:338
std::conditional_t< std::is_reference_v< T >, std::add_pointer_t< std::remove_reference_t< T > >, T > replace_ref_with_ptr_t
Definition diplomat_runtime.hpp:275
std::conditional_t< std::is_same_v< T, std::string_view >, capi::DiplomatStringView, T > replace_string_view_t
Definition diplomat_runtime.hpp:272
replace_string_view_t< as_ffi_t< T > > replace_fn_t
Replace the argument types from the std::function with the argument types for th function pointer.
Definition diplomat_runtime.hpp:279
const U get_inner_if_present(T v)
Definition diplomat_runtime.hpp:327
constexpr size_t dynamic_extent
Definition diplomat_runtime.hpp:221
typename as_ffi< T >::type as_ffi_t
Definition diplomat_runtime.hpp:269
fn_traits(T) -> fn_traits< T >
Definition diplomat_runtime.hpp:125
Err(T i)
Definition diplomat_runtime.hpp:131
T inner
Definition diplomat_runtime.hpp:126
Err(T &&i)
Definition diplomat_runtime.hpp:127
Err(Err &&) noexcept=default
Err()=default
Definition diplomat_runtime.hpp:111
Ok(T i)
Definition diplomat_runtime.hpp:117
Ok(T &&i)
Definition diplomat_runtime.hpp:113
T inner
Definition diplomat_runtime.hpp:112
Ok()=default
Ok(Ok &&) noexcept=default
Definition diplomat_runtime.hpp:259
T type
Definition diplomat_runtime.hpp:260
Ret ret
Definition diplomat_runtime.hpp:285
fn_traits(function_t)
Definition diplomat_runtime.hpp:313
static T replace(replace_fn_t< T > val)
Definition diplomat_runtime.hpp:289
std::function< fn_ptr_t > function_t
Definition diplomat_runtime.hpp:284
static void c_delete(const void *cb)
Definition diplomat_runtime.hpp:309
static Ret c_run_callback(const void *cb, replace_fn_t< Args >... args)
Definition diplomat_runtime.hpp:305
Ret(Args...) fn_ptr_t
Definition diplomat_runtime.hpp:283
Definition diplomat_runtime.hpp:281
Definition diplomat_runtime.hpp:336
T type
Definition diplomat_runtime.hpp:324
T type
Definition diplomat_runtime.hpp:323
Definition diplomat_runtime.hpp:322
T type
Definition diplomat_runtime.hpp:322
next_type _curr
Definition diplomat_runtime.hpp:366
typename inner< next_type >::type value_type
Definition diplomat_runtime.hpp:347
decltype(std::declval< T >().next()) next_type
Definition diplomat_runtime.hpp:344
std::add_lvalue_reference_t< value_type > reference
Definition diplomat_runtime.hpp:349
std::input_iterator_tag iterator_category
Definition diplomat_runtime.hpp:350
void operator++()
Definition diplomat_runtime.hpp:357
bool operator!=(std::nullopt_t)
Definition diplomat_runtime.hpp:361
void difference_type
Definition diplomat_runtime.hpp:348
next_to_iter_helper(std::unique_ptr< T > &&ptr)
Definition diplomat_runtime.hpp:352
std::shared_ptr< T > _ptr
Definition diplomat_runtime.hpp:365
next_to_iter_helper(const next_to_iter_helper &o)
Definition diplomat_runtime.hpp:355
void operator++(int)
Definition diplomat_runtime.hpp:358
const value_type & operator*() const
Definition diplomat_runtime.hpp:359