1///////////////////////////////////////////////////////////////////////////////
3// Module : purescript.hh
4// Copyright : (c) Andy Arvanitis 2015
7// Maintainer : Andy Arvanitis <andy.arvanitis@gmail.com>
8// Stability : experimental
11// Basic types and functions to support purescript-to-C++1x rendering
13///////////////////////////////////////////////////////////////////////////////
18#if !defined(__cplusplus)
19#error This is a C++ file!
42#include <iso646.h> // mostly for MS Visual Studio compiler
43#include "purescript_memory.hh"
47using cstring = const char *; // TODO: deprecated
50using std::runtime_error;
53 struct SymbolGeneratorAnchor {};
56 struct SymbolGenerator {
57 constexpr static SymbolGeneratorAnchor anchor = SymbolGeneratorAnchor{};
60 constexpr SymbolGeneratorAnchor SymbolGenerator<T>::anchor;
62 using Symbol = const SymbolGeneratorAnchor *;
65#define DEFINE_SYMBOL(S) namespace PureScript { \
72#define SYM(S) (&Private::SymbolGenerator<::PureScript::Private::Symbols::S_ ## S>::anchor)
74constexpr bool undefined = false;
76// TODO: Not a real limit, just used for simpler accessors
77static constexpr size_t unknown_size = 64;
79// A variant data class designed to provide some features of dynamic typing.
84 static constexpr auto _managed_ = 0x10;
111 inline static auto isManaged(const Tag tag) -> decltype(_managed_) {
112 return static_cast<decltype(_managed_)>(tag) & _managed_;
114 static_assert(static_cast<decltype(_managed_)>(Tag::Invalid) & _managed_, "outside of range");
119 static constexpr as_thunk unthunk = as_thunk{};
121 using dict_pair = std::pair<const Private::Symbol, const any>;
123 using dict = std::array<const dict_pair, N>;
126 using data = std::array<const any, N>;
128 using array = std::deque<any WITH_ALLOCATOR(any)>;
131 auto operator ()(const char *, const char *) const -> bool;
133 using record = std::map<const char *,
136 WITH_ALLOCATOR_PAIR(char * const, any)>;
138 using fn = auto (*)(const any&) -> any;
139 using eff_fn = auto (*)() -> any;
140 using thunk = auto (*)(const as_thunk) -> const any&;
145 virtual auto operator()(const any&) const -> any = 0;
149 template <typename T>
150 class Closure_ : public Closure {
153 Closure_(const T& l) noexcept : lambda(l) {}
154 auto operator()(const any& arg) const -> any override {
161 virtual auto operator()() const -> any = 0;
162 virtual ~EffClosure();
165 template <typename T>
166 class EffClosure_ : public EffClosure {
169 EffClosure_(const T& l) noexcept : lambda(l) {}
170 auto operator()() const -> any override {
186 mutable managed<void> p;
191 any(const int val) noexcept : tag(Tag::Integer), i(val) {}
192 any(const long val) noexcept : tag(Tag::Integer), i(static_cast<decltype(i)>(val)) {
193 assert(val >= std::numeric_limits<decltype(i)>::min() &&
194 val <= std::numeric_limits<decltype(i)>::max());
196 any(const size_t val) noexcept : tag(Tag::Integer), i(static_cast<decltype(i)>(val)) {
197 assert(val <= std::numeric_limits<decltype(i)>::max());
199 any(const double val) noexcept : tag(Tag::Double), d(val) {}
200 any(const char32_t val) noexcept : tag(Tag::Character), c(val) {}
201 any(const char val) noexcept : tag(Tag::Character), c(val) {}
203 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
204 any(const T val) noexcept : tag(Tag::Boolean), b(val) {}
206 any(const char * val) : tag(Tag::String), p(make_managed_and_finalized<string>(val)) {}
207 any(const string& val) : tag(Tag::String), p(make_managed_and_finalized<string>(val)) {}
208 any(string&& val) noexcept : tag(Tag::String), p(make_managed_and_finalized<string>(std::move(val))) {}
210 any(const managed<string>& val) noexcept : tag(Tag::String), p(val) {}
211 any(managed<string>&& val) noexcept : tag(Tag::String), p(std::move(val)) {}
214 any(dict<N>&& val) noexcept : tag(Tag::Dictionary), p(make_managed<dict<N>>(std::move(val))) {}
217 any(data<N>&& val) noexcept : tag(Tag::Data), p(make_managed<data<N>>(std::move(val))) {}
219 any(const array& val) : tag(Tag::Array), p(make_managed<array>(val)) {}
220 any(array&& val) noexcept : tag(Tag::Array), p(make_managed<array>(std::move(val))) {}
222 any(const record& val) : tag(Tag::Record), p(make_managed<record>(val)) {}
223 any(record&& val) noexcept : tag(Tag::Record), p(make_managed<record>(std::move(val))) {}
225 template <typename T>
226 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0) noexcept
227 : tag(Tag::Function), f(val) {}
229 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
230 !std::is_convertible<T,fn>::value>::type>
231 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
232 : tag(Tag::Closure), p(make_managed<Closure_<T>>(val)) {}
234 template <typename T>
235 any(const T& val, typename std::enable_if<std::is_convertible<T,eff_fn>::value>::type* = 0) noexcept
236 : tag(Tag::EffFunction), e(val) {}
238 template <typename T,
239 typename = typename std::enable_if<!std::is_same<any,T>::value &&
240 !std::is_convertible<T,eff_fn>::value>::type>
241 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
242 : tag(Tag::EffClosure), p(make_managed<EffClosure_<T>>(val)) {}
244 template <typename T>
245 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0) noexcept
246 : tag(Tag::Thunk), t(val) {}
248 template <typename T,
249 typename = typename std::enable_if<std::is_class<typename std::remove_pointer<T>::type>::value>::type>
250 any(const T& val, typename std::enable_if<IS_POINTER_TYPE(T)::value>::type* = 0) noexcept
251 : tag(Tag::Pointer), p(val) {}
253 template <typename T>
254 any(T&& val, typename std::enable_if<std::is_assignable<managed<void>,T>::value>::type* = 0) noexcept
255 : tag(Tag::Pointer), p(std::move(val)) {}
257 any(void * val) noexcept : tag(Tag::RawPointer), v(val) {}
258 any(nullptr_t) noexcept : tag(Tag::RawPointer), v(nullptr) {}
262 auto destruct() const noexcept -> void {
263 if (isManaged(tag)) {
268 static_assert(sizeof(any::u) >= sizeof(any::t), "size assumption");
269 static_assert(sizeof(any::u) >= sizeof(any::i), "size assumption");
270 static_assert(sizeof(any::u) >= sizeof(any::d), "size assumption");
271 static_assert(sizeof(any::u) >= sizeof(any::c), "size assumption");
272 static_assert(sizeof(any::u) >= sizeof(any::b), "size assumption");
273 static_assert(sizeof(any::u) >= sizeof(any::f), "size assumption");
274 static_assert(sizeof(any::u) >= sizeof(any::e), "size assumption");
275 static_assert(sizeof(any::u) >= sizeof(any::v), "size assumption");
277 auto copyAssign(const any& other) const noexcept -> void {
278 if (isManaged(other.tag)) {
279 new (&p) managed<void>(other.p);
284 auto moveAssign(any& other) const noexcept -> void {
285 if (isManaged(other.tag)) {
286 new (&p) managed<void>(std::move(other.p));
293 any(const any& other) noexcept : tag(other.tag) {
297 any(any&& other) noexcept : tag(other.tag) {
301 auto operator=(const any& rhs) noexcept -> any& {
308 auto operator=(any&& rhs) noexcept -> any& {
318#endif // !defined(USE_GC)
323 auto operator()(const any&) const -> any;
324 auto operator()(const as_thunk) const -> const any&;
325 auto operator()() const -> any;
327 operator int() const;
328 operator double() const;
329 operator bool() const;
330 operator char32_t() const;
331 operator char() const;
332 operator size_t() const;
333 operator const string&() const;
334 operator const char *() const;
335 operator const array&() const;
336 operator const record&() const;
338 operator void *() const {
342 template <typename T,
343 typename = typename std::enable_if<std::is_pointer<T>::value &&
344 std::is_class<typename std::remove_pointer<T>::type>::value>::type>
346 return static_cast<T>(rawPointer());
349 auto operator[](const int) const -> const any&;
350 auto at(const char *) const -> const any&;
351 auto size() const -> size_t;
352 auto empty() const -> bool;
353 auto contains(const Private::Symbol) const -> bool;
355 auto extractPointer(IF_DEBUG(const Tag)) const -> void*;
357 auto rawPointer() const -> void* {
358 const any& variant = unthunkVariant(*this);
359 assert(tag == Tag::RawPointer);
363 static auto unthunkVariant(const any&) -> const any&;
365 #define DEFINE_OPERATOR(op) \
366 template <typename T, \
367 typename = typename std::enable_if<!std::is_same<T,any>::value && \
368 !std::is_same<T,const char *>::value>::type> \
369 inline friend auto operator op (const any& lhs, T rhs) -> T { \
370 return static_cast<typename std::add_lvalue_reference<typename std::add_const<T>::type >::type>(lhs) op rhs; \
372 template <typename T, \
373 typename = typename std::enable_if<!std::is_same<T,any>::value && \
374 !std::is_same<T,const char *>::value>::type> \
375 inline friend auto operator op (T lhs, const any& rhs) -> T { \
376 return lhs op static_cast<typename std::add_lvalue_reference<typename std::add_const<T>::type >::type>(rhs); \
378 friend auto operator op (const any&, const any&) -> any; \
380 #define DEFINE_COMPARISON_OPERATOR(op) \
381 template <typename T, \
382 typename = typename std::enable_if<!std::is_same<T,any>::value && \
383 !std::is_same<T,const char *>::value>::type> \
384 inline friend auto operator op (const any& lhs, T rhs) -> bool { \
385 return static_cast<typename std::add_lvalue_reference<typename std::add_const<T>::type >::type>(lhs) op rhs; \
387 template <typename T, \
388 typename = typename std::enable_if<!std::is_same<T,any>::value && \
389 !std::is_same<T,const char *>::value>::type> \
390 inline friend auto operator op (T lhs, const any& rhs) -> bool { \
391 return lhs op static_cast<typename std::add_lvalue_reference<typename std::add_const<T>::type >::type>(rhs); \
393 inline friend auto operator op (const any& lhs, const char * rhs) -> bool { \
394 return static_cast<const string&>(lhs) op rhs; \
396 inline friend auto operator op (const char * lhs, const any& rhs) -> bool { \
397 return lhs op static_cast<const string&>(rhs); \
399 friend auto operator op (const any&, const any&) -> bool; \
401 DEFINE_COMPARISON_OPERATOR(==)
402 DEFINE_COMPARISON_OPERATOR(!=)
403 DEFINE_COMPARISON_OPERATOR(<)
404 DEFINE_COMPARISON_OPERATOR(<=)
405 DEFINE_COMPARISON_OPERATOR(>)
406 DEFINE_COMPARISON_OPERATOR(>=)
414 inline friend auto operator+(const any& lhs, const char * rhs) -> string {
415 return static_cast<const string&>(lhs) + rhs;
417 inline friend auto operator+(const char * lhs, const any& rhs) -> string {
418 return lhs + static_cast<const string&>(rhs);
421 friend auto operator-(const any&) -> any; // unary negate
426 template <typename T, typename U=void>
430 struct TagHelper<string> {
431 static constexpr any::Tag tag = any::Tag::String;
435 struct TagHelper<const char *> {
436 static constexpr any::Tag tag = any::Tag::String;
440 struct TagHelper<any::dict<N>> {
441 static constexpr any::Tag tag = any::Tag::Dictionary;
445 struct TagHelper<any::data<N>> {
446 static constexpr any::Tag tag = any::Tag::Data;
450 struct TagHelper<any::array> {
451 static constexpr any::Tag tag = any::Tag::Array;
455 struct TagHelper<any::record> {
456 static constexpr any::Tag tag = any::Tag::Record;
459 template <typename T>
460 struct TagHelper<T> {
461 static constexpr any::Tag tag = any::Tag::Pointer;
466 typename = typename std::enable_if<std::is_class<T>::value>::type>
467inline auto cast_managed(const any& a) -> T& {
468 return *static_cast<T*>(a.extractPointer(IF_DEBUG(Private::TagHelper<T>::tag)));
471// TODO: Deprecated - use static_cast
473 typename = typename std::enable_if<!std::is_class<T>::value>::type>
474inline auto cast(const any& a) -> T {
475 return static_cast<T>(a);
478// TODO: Deprecated - use cast_managed
480 typename = typename std::enable_if<std::is_class<T>::value>::type>
481inline auto cast(const any& a) -> T& {
482 return cast_managed<T>(a);
486 template <size_t N, typename T>
487 inline auto get(const T& a) ->
488 typename std::enable_if<!std::is_same<any, T>::value, const any&>::type {
493 inline auto get(const any& a) -> const any& {
494 return cast_managed<any::dict<N+1>>(a)[N].second;
498 inline auto get(const Private::Symbol key, const any::dict<N>& a) -> const any& {
499 static_assert(N > 0, "dict size must be greater than zero");
500 typename std::remove_reference<decltype(a)>::type::size_type i = 0;
502 if (a[i].first == key) {
505 } while (a[++i].first != nullptr);
506 assert(false && "dict key not found");
507 static const any invalid_key(nullptr);
511 inline auto get(const Private::Symbol key, const any& a) -> const any& {
512 return get(key, cast_managed<any::dict<unknown_size>>(a));
515 #define P(N) any::dict_pair&& arg ## N
516 #define T(N) any::dict<N+1>
517 #define E(N) std::forward<decltype(arg ## N)>(arg ## N)
518 #define M(...) {{ __VA_ARGS__, { nullptr, nullptr } }}
520 inline auto make(P(1)) -> T(1) {
523 inline auto make(P(1), P(2)) -> T(2) {
524 return T(2) M(E(1), E(2));
526 inline auto make(P(1), P(2), P(3)) -> T(3) {
527 return T(3) M(E(1), E(2), E(3));
529 inline auto make(P(1), P(2), P(3), P(4)) -> T(4) {
530 return T(4) M(E(1), E(2), E(3), E(4));
532 inline auto make(P(1), P(2), P(3), P(4), P(5)) -> T(5) {
533 return T(5) M(E(1), E(2), E(3), E(4), E(5));
535 inline auto make(P(1), P(2), P(3), P(4), P(5), P(6)) -> T(6) {
536 return T(6) M(E(1), E(2), E(3), E(4), E(5), E(6));
538 inline auto make(P(1), P(2), P(3), P(4), P(5), P(6), P(7)) -> T(7) {
539 return T(7) M(E(1), E(2), E(3), E(4), E(5), E(6), E(7));
541 inline auto make(P(1), P(2), P(3), P(4), P(5), P(6), P(7), P(8)) -> T(8) {
542 return T(8) M(E(1), E(2), E(3), E(4), E(5), E(6), E(7), E(8));
552 template <size_t N, typename T>
553 inline auto get(const T& a) ->
554 typename std::enable_if<!std::is_same<any, T>::value, const any&>::type {
559 inline auto get(const any& a) -> const any& {
560 return cast_managed<any::data<N+1>>(a)[N];
563 template <typename T>
564 inline auto ctor(const T& a) -> int {
569} // namespace PureScript
572#undef WITH_ALLOCATOR_PAIR
573#undef IS_POINTER_TYPE
574#undef DEFINE_OPERATOR
575#undef DEFINE_COMPARISON_OPERATOR
577#endif // PureScript_HH
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list