git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge remote-tracking branch 'pure11/pure11' into native
7be66c1Andy Arvanitis
pcc/runtime/purescript.cc+15−9
@@ -28,7 +28,7 @@ any::EffClosure::~EffClosure() {}
28auto any::operator()(const any& arg) const -> any {
28auto any::operator()(const any& arg) const -> any {
29 const any& variant = unthunkVariant(*this);
29 const any& variant = unthunkVariant(*this);
30 if (variant.tag == Tag::Closure) {
30 if (variant.tag == Tag::Closure) {
31− return (*variant.l)(arg);
31+ return (*static_cast<const Closure*>(POINTER_FROM_MEMBER(variant.p)))(arg);
32 }
32 }
33 assert(variant.tag == Tag::Function);
33 assert(variant.tag == Tag::Function);
34 return (*variant.f)(arg);
34 return (*variant.f)(arg);
@@ -42,7 +42,7 @@ auto any::operator()(const as_thunk) const -> const any& {
42auto any::operator()() const -> any {
42auto any::operator()() const -> any {
43 const any& variant = unthunkVariant(*this);
43 const any& variant = unthunkVariant(*this);
44 if (variant.tag == Tag::EffClosure) {
44 if (variant.tag == Tag::EffClosure) {
45− return (*variant.k)();
45+ return (*static_cast<const EffClosure*>(POINTER_FROM_MEMBER(variant.p)))();
46 }
46 }
47 assert(variant.tag == Tag::EffFunction);
47 assert(variant.tag == Tag::EffFunction);
48 return (*variant.e)();
48 return (*variant.e)();
@@ -77,19 +77,19 @@ any::operator size_t() const {
77}
77}
78
78
79any::operator const string&() const {
79any::operator const string&() const {
80− RETURN_VALUE(Tag::String, s, *)
80+ return *static_cast<const string*>(extractPointer(IF_DEBUG(Tag::String)));
81}
81}
82
82
83any::operator const char *() const {
83any::operator const char *() const {
84− RETURN_VALUE(Tag::String, s->c_str(),)
84+ return static_cast<const string*>(extractPointer(IF_DEBUG(Tag::String)))->c_str();
85}
85}
86
86
87any::operator const array&() const {
87any::operator const array&() const {
88− RETURN_VALUE(Tag::Array, a, *)
88+ return *static_cast<const array*>(extractPointer(IF_DEBUG(Tag::Array)));
89}
89}
90
90
91any::operator const record&() const {
91any::operator const record&() const {
92− RETURN_VALUE(Tag::Record, r, *)
92+ return *static_cast<const record*>(extractPointer(IF_DEBUG(Tag::Record)));
93}
93}
94
94
95auto any::extractPointer(IF_DEBUG(const any::Tag t)) const -> void* {
95auto any::extractPointer(IF_DEBUG(const any::Tag t)) const -> void* {
@@ -129,7 +129,11 @@ auto any::contains(const Private::Symbol key) const -> bool {
129 return false;
129 return false;
130}
130}
131
131
132+auto any::cstr_cmp::operator ()(const char * a, const char * b) const -> bool {
133+ return a == b ? false : std::strcmp(a, b) < 0;
134+}
135+
132−auto any::at(const std::string& key) const -> const any& {
136+auto any::at(const char * key) const -> const any& {
133 return static_cast<const record&>(*this).at(key);
137 return static_cast<const record&>(*this).at(key);
134}
138}
135
139
@@ -145,7 +149,8 @@ auto any::at(const std::string& key) const -> const any& {
145 case any::Tag::Double: return lhs.d op static_cast<decltype(any::d)>(rhs); \
149 case any::Tag::Double: return lhs.d op static_cast<decltype(any::d)>(rhs); \
146 case any::Tag::Character: return lhs.c op static_cast<decltype(any::c)>(rhs); \
150 case any::Tag::Character: return lhs.c op static_cast<decltype(any::c)>(rhs); \
147 case any::Tag::Boolean: return lhs.b op static_cast<decltype(any::b)>(rhs); \
151 case any::Tag::Boolean: return lhs.b op static_cast<decltype(any::b)>(rhs); \
152+ case any::Tag::String: return *static_cast<const string*>(POINTER_FROM_MEMBER(lhs.p)) \
148− case any::Tag::String: return *lhs.s op static_cast<const string&>(rhs); \
153+ op static_cast<const string&>(rhs); \
149 case any::Tag::RawPointer: return lhs.v op cast<decltype(any::v)>(rhs); \
154 case any::Tag::RawPointer: return lhs.v op cast<decltype(any::v)>(rhs); \
150 case any::Tag::Pointer: return lhs.p op any::unthunkVariant(rhs).p; \
155 case any::Tag::Pointer: return lhs.p op any::unthunkVariant(rhs).p; \
151 default: assert(false && "Unsupported tag for operator " #op); \
156 default: assert(false && "Unsupported tag for operator " #op); \
@@ -170,7 +175,8 @@ auto operator+(const any& lhs_, const any& rhs) -> any {
170 case any::Tag::Integer: return lhs.i + static_cast<decltype(any::i)>(rhs);
175 case any::Tag::Integer: return lhs.i + static_cast<decltype(any::i)>(rhs);
171 case any::Tag::Double: return lhs.d + static_cast<decltype(any::d)>(rhs);
176 case any::Tag::Double: return lhs.d + static_cast<decltype(any::d)>(rhs);
172 case any::Tag::Character: return decltype(any::c){lhs.c + static_cast<decltype(any::c)>(rhs)};
177 case any::Tag::Character: return decltype(any::c){lhs.c + static_cast<decltype(any::c)>(rhs)};
178+ case any::Tag::String: return *static_cast<const string*>(POINTER_FROM_MEMBER(lhs.p))
173− case any::Tag::String: return *lhs.s + static_cast<const string&>(rhs);
179+ + static_cast<const string&>(rhs);
174 default: assert(false && "Unsupported tag for '+' operator");
180 default: assert(false && "Unsupported tag for '+' operator");
175 }
181 }
176 return nullptr;
182 return nullptr;
pcc/runtime/purescript.hh+95−98
@@ -36,7 +36,7 @@
36#include <string>
36#include <string>
37#include <array>
37#include <array>
38#include <deque>
38#include <deque>
39−#include <unordered_map>
39+#include <map>
40#include <utility>
40#include <utility>
41#include <stdexcept>
41#include <stdexcept>
42#include <iso646.h> // mostly for MS Visual Studio compiler
42#include <iso646.h> // mostly for MS Visual Studio compiler
@@ -80,9 +80,13 @@ static constexpr size_t unknown_size = 64;
80//
80//
81class any {
81class any {
82
82
83+ private:
84+ static constexpr auto _managed_ = 0x10;
85+
83 public:
86 public:
84 enum class Tag {
87 enum class Tag {
88+ Unknown,
85− Thunk = 0x10,
89+ Thunk,
86 Integer,
90 Integer,
87 Double,
91 Double,
88 Character,
92 Character,
@@ -90,26 +94,31 @@ class any {
90 Function,
94 Function,
91 EffFunction,
95 EffFunction,
92 RawPointer,
96 RawPointer,
93− String,
97+ String = _managed_,
94− Map,
98+ Dictionary,
95 Data,
99 Data,
96 Array,
100 Array,
97 Record,
101 Record,
98 Closure,
102 Closure,
99 EffClosure,
103 EffClosure,
100− Pointer
104+ Pointer,
105+ Invalid
101 };
106 };
102
107
103 private:
108 private:
104 mutable Tag tag;
109 mutable Tag tag;
105
110
111+ inline static auto isManaged(const Tag tag) -> decltype(_managed_) {
112+ return static_cast<decltype(_managed_)>(tag) & _managed_;
113+ }
114+ static_assert(static_cast<decltype(_managed_)>(Tag::Invalid) & _managed_, "outside of range");
115+
106 public:
116 public:
107 struct as_thunk {
117 struct as_thunk {
108 };
118 };
109 static constexpr as_thunk unthunk = as_thunk{};
119 static constexpr as_thunk unthunk = as_thunk{};
110
120
111 using dict_pair = std::pair<const Private::Symbol, const any>;
121 using dict_pair = std::pair<const Private::Symbol, const any>;
112−
113 template <size_t N>
122 template <size_t N>
114 using dict = std::array<const dict_pair, N>;
123 using dict = std::array<const dict_pair, N>;
115
124
@@ -117,7 +126,14 @@ class any {
117 using data = std::array<const any, N>;
126 using data = std::array<const any, N>;
118
127
119 using array = std::deque<any WITH_ALLOCATOR(any)>;
128 using array = std::deque<any WITH_ALLOCATOR(any)>;
129+
130+ struct cstr_cmp {
131+ auto operator ()(const char *, const char *) const -> bool;
132+ };
133+ using record = std::map<const char *,
134+ any,
135+ cstr_cmp
120− using record = std::unordered_map<std::string, any WITH_ALLOCATOR_PAIR(std::string, any)>;
136+ WITH_ALLOCATOR_PAIR(const char *, any)>;
121
137
122 using fn = auto (*)(const any&) -> any;
138 using fn = auto (*)(const any&) -> any;
123 using eff_fn = auto (*)() -> any;
139 using eff_fn = auto (*)() -> any;
@@ -158,20 +174,16 @@ class any {
158
174
159 private:
175 private:
160 union {
176 union {
161− mutable thunk t;
177+ mutable thunk t;
162− mutable int i;
178+ mutable int i;
163− mutable double d;
179+ mutable double d;
164− mutable char32_t c;
180+ mutable char32_t c;
165− mutable bool b;
181+ mutable bool b;
166− mutable fn f;
182+ mutable fn f;
167− mutable eff_fn e;
183+ mutable eff_fn e;
168− mutable void * v;
184+ mutable void * v;
169− mutable managed<string> s;
185+ mutable uint64_t u;
170− mutable managed<array> a;
171− mutable managed<record> r;
172− mutable managed<Closure> l;
173− mutable managed<EffClosure> k;
186+ mutable managed<void> p;
174− mutable managed<void> p;
175 };
187 };
176
188
177 public:
189 public:
@@ -188,24 +200,24 @@ class any {
188 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
200 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
189 any(const T val) noexcept : tag(Tag::Boolean), b(val) {}
201 any(const T val) noexcept : tag(Tag::Boolean), b(val) {}
190
202
191− any(const char * val) : tag(Tag::String), s(make_managed_and_finalized<string>(val)) {}
203+ any(const char * val) : tag(Tag::String), p(make_managed_and_finalized<string>(val)) {}
192− any(const string& val) : tag(Tag::String), s(make_managed_and_finalized<string>(val)) {}
204+ any(const string& val) : tag(Tag::String), p(make_managed_and_finalized<string>(val)) {}
193− any(string&& val) noexcept : tag(Tag::String), s(make_managed_and_finalized<string>(std::move(val))) {}
205+ any(string&& val) noexcept : tag(Tag::String), p(make_managed_and_finalized<string>(std::move(val))) {}
194
206
195− any(const managed<string>& val) noexcept : tag(Tag::String), s(val) {}
207+ any(const managed<string>& val) noexcept : tag(Tag::String), p(val) {}
196− any(managed<string>&& val) noexcept : tag(Tag::String), s(std::move(val)) {}
208+ any(managed<string>&& val) noexcept : tag(Tag::String), p(std::move(val)) {}
197
209
198 template <size_t N>
210 template <size_t N>
199− any(dict<N>&& val) noexcept : tag(Tag::Map), p(make_managed<dict<N>>(std::move(val))) {}
211+ any(dict<N>&& val) noexcept : tag(Tag::Dictionary), p(make_managed<dict<N>>(std::move(val))) {}
200
212
201 template <size_t N>
213 template <size_t N>
202 any(data<N>&& val) noexcept : tag(Tag::Data), p(make_managed<data<N>>(std::move(val))) {}
214 any(data<N>&& val) noexcept : tag(Tag::Data), p(make_managed<data<N>>(std::move(val))) {}
203
215
204− any(const array& val) : tag(Tag::Array), a(make_managed<array>(val)) {}
216+ any(const array& val) : tag(Tag::Array), p(make_managed<array>(val)) {}
205− any(array&& val) noexcept : tag(Tag::Array), a(make_managed<array>(std::move(val))) {}
217+ any(array&& val) noexcept : tag(Tag::Array), p(make_managed<array>(std::move(val))) {}
206
218
207− any(const record& val) : tag(Tag::Record), r(make_managed<record>(val)) {}
219+ any(const record& val) : tag(Tag::Record), p(make_managed<record>(val)) {}
208− any(record&& val) noexcept : tag(Tag::Record), r(make_managed<record>(std::move(val))) {}
220+ any(record&& val) noexcept : tag(Tag::Record), p(make_managed<record>(std::move(val))) {}
209
221
210 template <typename T>
222 template <typename T>
211 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0) noexcept
223 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0) noexcept
@@ -214,7 +226,7 @@ class any {
214 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
226 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
215 !std::is_convertible<T,fn>::value>::type>
227 !std::is_convertible<T,fn>::value>::type>
216 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
228 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
217− : tag(Tag::Closure), l(make_managed<Closure_<T>>(val)) {}
229+ : tag(Tag::Closure), p(make_managed<Closure_<T>>(val)) {}
218
230
219 template <typename T>
231 template <typename T>
220 any(const T& val, typename std::enable_if<std::is_convertible<T,eff_fn>::value>::type* = 0) noexcept
232 any(const T& val, typename std::enable_if<std::is_convertible<T,eff_fn>::value>::type* = 0) noexcept
@@ -224,7 +236,7 @@ class any {
224 typename = typename std::enable_if<!std::is_same<any,T>::value &&
236 typename = typename std::enable_if<!std::is_same<any,T>::value &&
225 !std::is_convertible<T,eff_fn>::value>::type>
237 !std::is_convertible<T,eff_fn>::value>::type>
226 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
238 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
227− : tag(Tag::EffClosure), k(make_managed<EffClosure_<T>>(val)) {}
239+ : tag(Tag::EffClosure), p(make_managed<EffClosure_<T>>(val)) {}
228
240
229 template <typename T>
241 template <typename T>
230 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0) noexcept
242 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0) noexcept
@@ -249,80 +261,56 @@ class any {
249
261
250#if !defined(USE_GC)
262#if !defined(USE_GC)
251 private:
263 private:
252− template <typename T,
264+ auto destruct() const noexcept -> void {
253− typename U,
265+ if (isManaged(tag)) {
254− typename = typename std::enable_if<!std::is_reference<T>::value>::type>
266+ p.~managed<void>();
255− static constexpr auto move_if_rvalue(U&& u) noexcept -> U&& {
256− return static_cast<U&&>(u);
257− }
267+ }
258−
259− template <typename T,
260− typename U,
261− typename = typename std::enable_if<std::is_reference<T>::value>::type>
262− static constexpr auto move_if_rvalue(U& u) noexcept -> U& {
263− return static_cast<U&>(u);
264 }
268 }
265
269
266− template <typename T>
270+ static_assert(sizeof(u) >= sizeof(t), "size assumption");
271+ static_assert(sizeof(u) >= sizeof(i), "size assumption");
272+ static_assert(sizeof(u) >= sizeof(d), "size assumption");
273+ static_assert(sizeof(u) >= sizeof(c), "size assumption");
274+ static_assert(sizeof(u) >= sizeof(b), "size assumption");
275+ static_assert(sizeof(u) >= sizeof(f), "size assumption");
276+ static_assert(sizeof(u) >= sizeof(e), "size assumption");
277+ static_assert(sizeof(u) >= sizeof(v), "size assumption");
278+
267− auto assign(T&& other) const noexcept -> void {
279+ auto copyAssign(const any& other) const noexcept -> void {
268− switch (other.tag) {
280+ if (isManaged(other.tag)) {
269− case Tag::Thunk: t = other.t; break;
281+ new (&p) managed<void>(other.p);
270− case Tag::Integer: i = other.i; break;
282+ } else {
271− case Tag::Double: d = other.d; break;
283+ u = other.u;
272− case Tag::Character: c = other.c; break;
273− case Tag::Boolean: b = other.b; break;
274− case Tag::Function: f = other.f; break;
275− case Tag::EffFunction: e = other.e; break;
276− case Tag::RawPointer: v = other.v; break;
277−
278− case Tag::String: new (&s) managed<string>(move_if_rvalue<T>(other.s)); break;
279− case Tag::Array: new (&a) managed<array>(move_if_rvalue<T>(other.a)); break;
280− case Tag::Record: new (&r) managed<record>(move_if_rvalue<T>(other.r)); break;
281− case Tag::Closure: new (&l) managed<Closure>(move_if_rvalue<T>(other.l)); break;
282− case Tag::EffClosure: new (&k) managed<EffClosure>(move_if_rvalue<T>(other.k)); break;
283− case Tag::Map:
284− case Tag::Data:
285− case Tag::Pointer: new (&p) managed<void>(move_if_rvalue<T>(other.p)); break;
286−
287− default: assert(false && "Bad 'any' tag"); break;
288 }
284 }
289 }
285 }
290−
286+ auto moveAssign(any& other) const noexcept -> void {
291− auto destruct() -> void {
287+ if (isManaged(other.tag)) {
292− switch (tag) {
288+ new (&p) managed<void>(std::move(other.p));
293− case Tag::String: s.~managed<string>(); break;
289+ } else {
294− case Tag::Array: a.~managed<array>(); break;
290+ u = other.u;
295− case Tag::Record: r.~managed<record>(); break;
296− case Tag::Closure: l.~managed<Closure>(); break;
297− case Tag::EffClosure: k.~managed<EffClosure>(); break;
298− case Tag::Map:
299− case Tag::Data:
300− case Tag::Pointer: p.~managed<void>(); break;
301−
302− default: break;
303 }
291 }
304 }
292 }
305
293
306 public:
294 public:
307 any(const any& other) noexcept : tag(other.tag) {
295 any(const any& other) noexcept : tag(other.tag) {
308− assign(other);
296+ copyAssign(other);
309 }
297 }
310
298
311 any(any&& other) noexcept : tag(other.tag) {
299 any(any&& other) noexcept : tag(other.tag) {
312− assign(std::move(other));
300+ moveAssign(other);
313 }
301 }
314
302
315 auto operator=(const any& rhs) noexcept -> any& {
303 auto operator=(const any& rhs) noexcept -> any& {
316 destruct();
304 destruct();
317 tag = rhs.tag;
305 tag = rhs.tag;
318− assign(rhs);
306+ copyAssign(rhs);
319 return *this;
307 return *this;
320 }
308 }
321
309
322 auto operator=(any&& rhs) noexcept -> any& {
310 auto operator=(any&& rhs) noexcept -> any& {
323 destruct();
311 destruct();
324 tag = rhs.tag;
312 tag = rhs.tag;
325− assign(std::move(rhs));
313+ moveAssign(rhs);
326 return *this;
314 return *this;
327 }
315 }
328
316
@@ -350,7 +338,7 @@ class any {
350 operator const record&() const;
338 operator const record&() const;
351
339
352 auto operator[](const size_t) const -> const any&;
340 auto operator[](const size_t) const -> const any&;
353− auto at(const std::string&) const -> const any&;
341+ auto at(const char *) const -> const any&;
354 auto size() const -> size_t;
342 auto size() const -> size_t;
355 auto empty() const -> bool;
343 auto empty() const -> bool;
356 auto contains(const Private::Symbol) const -> bool;
344 auto contains(const Private::Symbol) const -> bool;
@@ -429,9 +417,19 @@ namespace Private {
429 template <typename T, typename U=void>
417 template <typename T, typename U=void>
430 struct TagHelper {};
418 struct TagHelper {};
431
419
420+ template <>
421+ struct TagHelper<string> {
422+ static constexpr any::Tag tag = any::Tag::String;
423+ };
424+
425+ template <>
426+ struct TagHelper<const char *> {
427+ static constexpr any::Tag tag = any::Tag::String;
428+ };
429+
432 template <size_t N>
430 template <size_t N>
433 struct TagHelper<any::dict<N>> {
431 struct TagHelper<any::dict<N>> {
434− static constexpr any::Tag tag = any::Tag::Map;
432+ static constexpr any::Tag tag = any::Tag::Dictionary;
435 };
433 };
436
434
437 template <size_t N>
435 template <size_t N>
@@ -439,6 +437,16 @@ namespace Private {
439 static constexpr any::Tag tag = any::Tag::Data;
437 static constexpr any::Tag tag = any::Tag::Data;
440 };
438 };
441
439
440+ template <>
441+ struct TagHelper<any::array> {
442+ static constexpr any::Tag tag = any::Tag::Array;
443+ };
444+
445+ template <>
446+ struct TagHelper<any::record> {
447+ static constexpr any::Tag tag = any::Tag::Record;
448+ };
449+
442 template <typename T>
450 template <typename T>
443 struct TagHelper<T> {
451 struct TagHelper<T> {
444 static constexpr any::Tag tag = any::Tag::Pointer;
452 static constexpr any::Tag tag = any::Tag::Pointer;
@@ -458,19 +466,8 @@ inline auto cast(const any& a) ->
458 return a;
466 return a;
459}
467}
460
468
461−template <typename T>
462−inline auto cast(const any& a) ->
463− typename std::enable_if<std::is_same<T, string>::value ||
464− std::is_same<T, any::array>::value ||
465− std::is_same<T, any::record>::value, const T&>::type {
466− return a;
467−}
468−
469template <typename T,
469template <typename T,
470− typename = typename std::enable_if<std::is_class<T>::value &&
470+ typename = typename std::enable_if<std::is_class<T>::value>::type>
471− !std::is_same<T,string>::value &&
472− !std::is_same<T,any::array>::value &&
473− !std::is_same<T,any::record>::value>::type>
474inline auto cast(const any& a) -> T& {
471inline auto cast(const any& a) -> T& {
475 return *static_cast<T*>(a.extractPointer(IF_DEBUG(Private::TagHelper<T>::tag)));
472 return *static_cast<T*>(a.extractPointer(IF_DEBUG(Private::TagHelper<T>::tag)));
476}
473}