muwerk ustd Library
A low-resource, minimal implementation of Arrays, Maps and Queues for low-resource avrs.
Loading...
Searching...
No Matches
ustd_functional.h
Go to the documentation of this file.
1// This implementation of functionals for low-resource AVRs
2// is completely based on: project function-avr by
3// https://github.com/winterscar, see:
4// https://github.com/winterscar/functional-avr
5
52#pragma once
53
54#if defined __ATTINY__ || defined(__ARDUINO__) || defined(__ARM__) || defined(__RISC_V__)
55// ATTINY is broken currently.
56// using size_t = decltype(sizeof(int));
57
58#ifdef __ATTINY__
59#include <Arduino.h>
60using nullptr_t = decltype(nullptr);
61#endif
62
63// NEW_H is some new Arduino implementation of new operator
64#if !defined(NEW_H) && !defined(USTD_FEATURE_SUPPORTS_NEW_OPERATOR)
65inline void *operator new(size_t size, void *ptr) {
66 return ptr;
67}
68#endif
69
70namespace ustd {
71
72template <class T> struct tag { using type = T; };
73template <class Tag> using type_t = typename Tag::type;
74
75// using size_t=decltype(sizeof(int));
76
77// move
78
79template <class T> T &&move(T &t) {
80 return static_cast<T &&>(t);
81}
82
83// forward
84
85template <class T> struct remove_reference : tag<T> {};
86template <class T> struct remove_reference<T &> : tag<T> {};
87template <class T> using remove_reference_t = type_t<remove_reference<T>>;
88
89template <class T> T &&forward(remove_reference_t<T> &t) {
90 return static_cast<T &&>(t);
91}
92template <class T> T &&forward(remove_reference_t<T> &&t) {
93 return static_cast<T &&>(t);
94}
95
96// decay
97
98template <class T> struct remove_const : tag<T> {};
99template <class T> struct remove_const<T const> : tag<T> {};
100
101template <class T> struct remove_volatile : tag<T> {};
102template <class T> struct remove_volatile<T volatile> : tag<T> {};
103
104template <class T> struct remove_cv : remove_const<type_t<remove_volatile<T>>> {};
105
106template <class T> struct decay3 : remove_cv<T> {};
107template <class R, class... Args> struct decay3<R(Args...)> : tag<R (*)(Args...)> {};
108template <class T> struct decay2 : decay3<T> {};
109template <class T, size_t N> struct decay2<T[N]> : tag<T *> {};
110
111template <class T> struct decay : decay2<remove_reference_t<T>> {};
112
113template <class T> using decay_t = type_t<decay<T>>;
114
115// is_convertible
116
117template <class T> T declval(); // no implementation
118
119template <class T, T t> struct integral_constant {
120 static constexpr T value = t;
121 constexpr integral_constant(){};
122 constexpr operator T() const {
123 return value;
124 }
125 constexpr T operator()() const {
126 return value;
127 }
128};
129template <bool b> using bool_t = integral_constant<bool, b>;
130using true_type = bool_t<true>;
131using false_type = bool_t<false>;
132
133template <class...> struct voider : tag<void> {};
134template <class... Ts> using void_t = type_t<voider<Ts...>>;
135
136namespace details {
137template <template <class...> class Z, class, class... Ts> struct can_apply : false_type {};
138template <template <class...> class Z, class... Ts>
139struct can_apply<Z, void_t<Z<Ts...>>, Ts...> : true_type {};
140} // namespace details
141template <template <class...> class Z, class... Ts>
142using can_apply = details::can_apply<Z, void, Ts...>;
143
144namespace details {
145template <class From, class To> using try_convert = decltype(To{declval<From>()});
146}
147template <class From, class To>
148struct is_convertible : can_apply<details::try_convert, From, To> {};
149template <> struct is_convertible<void, void> : true_type {};
150
151// enable_if
152
153template <bool, class = void> struct enable_if {};
154template <class T> struct enable_if<true, T> : tag<T> {};
155template <bool b, class T = void> using enable_if_t = type_t<enable_if<b, T>>;
156
157// res_of
158
159namespace details {
160template <class G, class... Args> using invoke_t = decltype(declval<G>()(declval<Args>()...));
161
162template <class Sig, class = void> struct res_of {};
163template <class G, class... Args>
164struct res_of<G(Args...), void_t<invoke_t<G, Args...>>> : tag<invoke_t<G, Args...>> {};
165} // namespace details
166template <class Sig> using res_of = details::res_of<Sig>;
167template <class Sig> using res_of_t = type_t<res_of<Sig>>;
168
169// aligned_storage
170
171template <size_t size, size_t align> struct alignas(align) aligned_storage_t { char buff[size]; };
172
173// is_same
174
175template <class A, class B> struct is_same : false_type {};
176template <class A> struct is_same<A, A> : true_type {};
177
178template <class Sig, size_t sz, size_t algn> struct small_task;
179
180template <class R, class... Args, size_t sz, size_t algn> struct small_task<R(Args...), sz, algn> {
181 struct vtable_t {
182 void (*mover)(void *src, void *dest);
183 void (*destroyer)(void *);
184 R (*invoke)(void const *t, Args &&...args);
185 template <class T> static vtable_t const *get() {
186 static const vtable_t table = {
187 [](void *src, void *dest) { new (dest) T(move(*static_cast<T *>(src))); },
188 [](void *t) { static_cast<T *>(t)->~T(); },
189 [](void const *t, Args &&...args) -> R {
190 return (*static_cast<T const *>(t))(forward<Args>(args)...);
191 }};
192 return &table;
193 }
194 };
195 vtable_t const *table = nullptr;
196 aligned_storage_t<sz, algn> data;
197 template <class F, class dF = decay_t<F>, enable_if_t<!is_same<dF, small_task>{}> * = nullptr,
198 enable_if_t<is_convertible<res_of_t<dF &(Args...)>, R>{}> * = nullptr>
199 small_task(F &&f) : table(vtable_t::template get<dF>()) {
200 static_assert(sizeof(dF) <= sz, "object too large");
201 static_assert(alignof(dF) <= algn, "object too aligned");
202 new (&data) dF(forward<F>(f));
203 }
204 ~small_task() {
205 if (table)
206 table->destroyer(&data);
207 }
208 small_task(const small_task &o) : table(o.table) {
209 data = o.data;
210 }
211 small_task(small_task &&o) : table(o.table) {
212 if (table)
213 table->mover(&o.data, &data);
214 }
215 small_task() {
216 }
217 small_task &operator=(const small_task &o) {
218 this->~small_task();
219 new (this) small_task(move(o));
220 return *this;
221 }
222 small_task &operator=(small_task &&o) {
223 this->~small_task();
224 new (this) small_task(move(o));
225 return *this;
226 }
227 explicit operator bool() const {
228 return table;
229 }
230 R operator()(Args... args) const {
231 return table->invoke(&data, forward<Args>(args)...);
232 }
233};
234
235template <class R, class... Args, size_t sz, size_t algn>
236inline bool operator==(const small_task<R(Args...), sz, algn> &__f, nullptr_t) {
237 return !static_cast<bool>(__f);
238}
239
241template <class R, class... Args, size_t sz, size_t algn>
242inline bool operator==(nullptr_t, const small_task<R(Args...), sz, algn> &__f) {
243 return !static_cast<bool>(__f);
244}
245
246template <class R, class... Args, size_t sz, size_t algn>
247inline bool operator!=(const small_task<R(Args...), sz, algn> &__f, nullptr_t) {
248 return static_cast<bool>(__f);
249}
250
252template <class R, class... Args, size_t sz, size_t algn>
253inline bool operator!=(nullptr_t, const small_task<R(Args...), sz, algn> &__f) {
254 return static_cast<bool>(__f);
255}
256
257template <class Sig> using function = small_task<Sig, sizeof(void *) * 4, alignof(void *)>;
258} // namespace ustd
259
260#endif
The ustd namespace.
Definition: ustd_array.h:34