git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
C++: string optimizations
3711c76Andy Arvanitis
pcc/include/purescript.cc+111−67
@@ -19,18 +19,19 @@ namespace PureScript {
19#define COPY_DATA(src) \
19#define COPY_DATA(src) \
20 type = src.type; \
20 type = src.type; \
21 switch (type) { \
21 switch (type) { \
22− case Type::Integer: i = src.i; break; \
22+ case Type::Integer: i = src.i; break; \
23− case Type::Double: d = src.d; break; \
23+ case Type::Double: d = src.d; break; \
24− case Type::Character: c = src.c; break; \
24+ case Type::Character: c = src.c; break; \
25− case Type::Boolean: b = src.b; break; \
25+ case Type::Boolean: b = src.b; break; \
26+ case Type::StringLiteral: r = src.r; break; \
26− case Type::String: new (&s) shared<string> (src.s); break; \
27+ case Type::String: new (&s) shared<std::string>(src.s); break; \
27− case Type::Map: new (&m) shared<map> (src.m); break; \
28+ case Type::Map: new (&m) shared<map>(src.m); break; \
28− case Type::Vector: new (&v) shared<vector> (src.v); break; \
29+ case Type::Vector: new (&v) shared<vector>(src.v); break; \
29− case Type::Function: f = src.f; break; \
30+ case Type::Function: f = src.f; break; \
30− case Type::Closure: new (&l) shared<closure> (src.l); break; \
31+ case Type::Closure: new (&l) shared<closure>(src.l); break; \
31− case Type::EffFunction: new (&e) shared<eff_fn> (src.e); break; \
32+ case Type::EffFunction: new (&e) shared<eff_fn>(src.e); break; \
32− case Type::Thunk: t = src.t; break; \
33+ case Type::Thunk: t = src.t; break; \
33− case Type::Pointer: new (&p) shared<void> (src.p); break; \
34+ case Type::Pointer: new (&p) shared<void>(src.p); break; \
34 \
35 \
35 default: assert(false && "Unsupported type in copy"); \
36 default: assert(false && "Unsupported type in copy"); \
36 }
37 }
@@ -38,18 +39,19 @@ namespace PureScript {
38#define MOVE_DATA(src) \
39#define MOVE_DATA(src) \
39 type = src.type; \
40 type = src.type; \
40 switch (type) { \
41 switch (type) { \
41− case Type::Integer: i = src.i; break; \
42+ case Type::Integer: i = src.i; break; \
42− case Type::Double: d = src.d; break; \
43+ case Type::Double: d = src.d; break; \
43− case Type::Character: c = src.c; break; \
44+ case Type::Character: c = src.c; break; \
44− case Type::Boolean: b = src.b; break; \
45+ case Type::Boolean: b = src.b; break; \
46+ case Type::StringLiteral: r = src.r; break; \
45− case Type::String: new (&s) shared<string> (std::move(src.s)); break; \
47+ case Type::String: new (&s) shared<std::string>(std::move(src.s)); break; \
46− case Type::Map: new (&m) shared<map> (std::move(src.m)); break; \
48+ case Type::Map: new (&m) shared<map>(std::move(src.m)); break; \
47− case Type::Vector: new (&v) shared<vector> (std::move(src.v)); break; \
49+ case Type::Vector: new (&v) shared<vector>(std::move(src.v)); break; \
48− case Type::Function: f = src.f; break; \
50+ case Type::Function: f = src.f; break; \
49− case Type::Closure: new (&l) shared<closure> (std::move(src.l)); break; \
51+ case Type::Closure: new (&l) shared<closure>(std::move(src.l)); break; \
50− case Type::EffFunction: new (&e) shared<eff_fn> (std::move(src.e)); break; \
52+ case Type::EffFunction: new (&e) shared<eff_fn>(std::move(src.e)); break; \
51− case Type::Thunk: t = src.t; break; \
53+ case Type::Thunk: t = src.t; break; \
52− case Type::Pointer: new (&p) shared<void> (std::move(src.p)); break; \
54+ case Type::Pointer: new (&p) shared<void>(std::move(src.p)); break; \
53 \
55 \
54 default: assert(false && "Unsupported type in move"); \
56 default: assert(false && "Unsupported type in move"); \
55 }
57 }
@@ -81,18 +83,19 @@ auto any::operator=(any&& rhs) noexcept -> any& {
81any::~any() {
83any::~any() {
82 // std::cout << "destroy" << std::endl;
84 // std::cout << "destroy" << std::endl;
83 switch (type) {
85 switch (type) {
84− case Type::Integer: ; break;
86+ case Type::Integer: ; break;
85− case Type::Double: ; break;
87+ case Type::Double: ; break;
86− case Type::Character: ; break;
88+ case Type::Character: ; break;
87− case Type::Boolean: ; break;
89+ case Type::Boolean: ; break;
90+ case Type::StringLiteral: ; break;
88− case Type::String: s.~shared<string>(); break;
91+ case Type::String: s.~shared<std::string>(); break;
89− case Type::Map: m.~shared<map>(); break;
92+ case Type::Map: m.~shared<map>(); break;
90− case Type::Vector: v.~shared<vector>(); break;
93+ case Type::Vector: v.~shared<vector>(); break;
91− case Type::Function: ; break;
94+ case Type::Function: ; break;
92− case Type::Closure: l.~shared<closure>(); break;
95+ case Type::Closure: l.~shared<closure>(); break;
93− case Type::EffFunction: e.~shared<eff_fn>(); break;
96+ case Type::EffFunction: e.~shared<eff_fn>(); break;
94− case Type::Thunk: ; break;
97+ case Type::Thunk: ; break;
95− case Type::Pointer: p.~shared<void>(); break;
98+ case Type::Pointer: p.~shared<void>(); break;
96
99
97 default: assert(false && "Unsupported type in destructor");
100 default: assert(false && "Unsupported type in destructor");
98 }
101 }
@@ -139,16 +142,15 @@ auto any::cast() const -> typename std::enable_if<std::is_same<T, bool>::value,
139template auto any::cast<bool>() const -> bool;
142template auto any::cast<bool>() const -> bool;
140
143
141template <typename T>
144template <typename T>
142−auto any::cast() const -> typename std::enable_if<std::is_same<T, string>::value, const T&>::type {
145+auto any::cast() const -> typename std::enable_if<std::is_same<T, string>::value, T>::type {
143− RETURN_VALUE(Type::String, s, *)
146+ const any& val = extractValue(*this);
147+ if (val.type == Type::StringLiteral) {
148+ return val.r;
144−}
149+ }
145−template auto any::cast<string>() const -> const string&;
150+ assert(val.type == Type::String);
146−
151+ return val.s->c_str();
147−template <typename T>
148−auto any::cast() const -> typename std::enable_if<std::is_same<T, const char*>::value, const T>::type {
149− RETURN_VALUE(Type::String, s->c_str(),)
150}
152}
151−template auto any::cast<const char*>() const -> const char* const;
153+template auto any::cast<string>() const -> string;
152
154
153template <typename T>
155template <typename T>
154auto any::cast() const -> typename std::enable_if<std::is_same<T, map>::value, const T&>::type {
156auto any::cast() const -> typename std::enable_if<std::is_same<T, map>::value, const T&>::type {
@@ -219,8 +221,12 @@ any::operator bool() const {
219 RETURN_VALUE(Type::Boolean, b,)
221 RETURN_VALUE(Type::Boolean, b,)
220}
222}
221
223
222−any::operator const string&() const {
224+any::operator string() const {
223− RETURN_VALUE(Type::String, s, *)
225+ return cast<string>();
226+}
227+
228+any::operator std::string() const {
229+ return cast<string>();
224}
230}
225
231
226any::operator const map&() const {
232any::operator const map&() const {
@@ -275,25 +281,49 @@ auto operator op (ty lhs, const any& rhs) -> rty { \
275 return lhs op rhs.cast<typename std::remove_const<std::remove_reference<ty>::type>::type>(); \
281 return lhs op rhs.cast<typename std::remove_const<std::remove_reference<ty>::type>::type>(); \
276}
282}
277
283
284+#define DEFINE_CSTR_EQUALS_OPERATOR() \
285+ auto operator==(const any& lhs_, const char * rhs) -> bool { \
286+ const any& lhs = any::extractValue(lhs_); \
287+ assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
288+ if (lhs.type == any::Type::StringLiteral) { \
289+ return (lhs.r == rhs) || (strcmp(lhs.r, rhs) == 0); \
290+ } \
291+ return strcmp(lhs.s->c_str(), rhs) == 0; \
292+ } \
293+ auto operator==(const char * lhs, const any& rhs_) -> bool { \
294+ const any& rhs = any::extractValue(rhs_); \
295+ assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
296+ if (rhs.type == any::Type::StringLiteral) { \
297+ return (lhs == rhs.r) || (strcmp(lhs, rhs) == 0); \
298+ } \
299+ return strcmp(lhs, rhs.s->c_str()) == 0; \
300+ }
301+
278#define DEFINE_CSTR_COMPARISON_OPERATOR(op) \
302#define DEFINE_CSTR_COMPARISON_OPERATOR(op) \
279 auto operator op (const any& lhs, const char * rhs) -> bool { \
303 auto operator op (const any& lhs, const char * rhs) -> bool { \
280− return lhs.cast<string>() op rhs; \
304+ return strcmp(lhs.cast<string>(), rhs) op 0; \
281 } \
305 } \
282 auto operator op (const char * lhs, const any& rhs) -> bool { \
306 auto operator op (const char * lhs, const any& rhs) -> bool { \
283− return lhs op rhs.cast<string>(); \
307+ return strcmp(lhs, rhs.cast<string>()) op 0; \
284 }
308 }
285
309
286#define DEFINE_COMPARISON_OPERATOR(op) \
310#define DEFINE_COMPARISON_OPERATOR(op) \
287 auto operator op (const any& lhs_, const any& rhs_) -> bool { \
311 auto operator op (const any& lhs_, const any& rhs_) -> bool { \
288 const any& lhs = any::extractValue(lhs_); \
312 const any& lhs = any::extractValue(lhs_); \
289 const any& rhs = any::extractValue(rhs_); \
313 const any& rhs = any::extractValue(rhs_); \
290− assert(lhs.type == rhs.type); \
291 switch (lhs.type) { \
314 switch (lhs.type) { \
292− case any::Type::Integer: return lhs.i op rhs.i; \
315+ case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i op rhs.i; \
293− case any::Type::Double: return lhs.d op rhs.d; \
316+ case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d op rhs.d; \
294− case any::Type::Character: return lhs.c op rhs.c; \
317+ case any::Type::Character: assert(lhs.type == any::Type::Character); return lhs.c op rhs.c; \
295− case any::Type::Boolean: return lhs.b op rhs.b; \
318+ case any::Type::Boolean: assert(lhs.type == any::Type::Boolean); return lhs.b op rhs.b; \
296− case any::Type::String: return (*lhs.s) op (*rhs.s); \
319+ case any::Type::StringLiteral: \
320+ assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
321+ assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
322+ return strcmp(lhs.r, rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
323+ case any::Type::String: \
324+ assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
325+ assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
326+ return strcmp(lhs.s->c_str(), rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
297 case any::Type::Pointer: return lhs.p op rhs.p; \
327 case any::Type::Pointer: return lhs.p op rhs.p; \
298 default: assert(false && "Unsupported type for operator " #op); \
328 default: assert(false && "Unsupported type for operator " #op); \
299 } \
329 } \
@@ -303,8 +333,6 @@ auto operator op (ty lhs, const any& rhs) -> rty { \
303 DEFINE_OPERATOR(op, double, bool) \
333 DEFINE_OPERATOR(op, double, bool) \
304 DEFINE_OPERATOR(op, char, bool) \
334 DEFINE_OPERATOR(op, char, bool) \
305 DEFINE_OPERATOR(op, bool, bool) \
335 DEFINE_OPERATOR(op, bool, bool) \
306− DEFINE_OPERATOR(op, const string&, bool) \
307− DEFINE_CSTR_COMPARISON_OPERATOR(op)
308
336
309//-----------------------------------------------------------------------------
337//-----------------------------------------------------------------------------
310// Operator definitions
338// Operator definitions
@@ -317,15 +345,28 @@ DEFINE_COMPARISON_OPERATOR(<=)
317DEFINE_COMPARISON_OPERATOR(>)
345DEFINE_COMPARISON_OPERATOR(>)
318DEFINE_COMPARISON_OPERATOR(>=)
346DEFINE_COMPARISON_OPERATOR(>=)
319
347
348+DEFINE_CSTR_EQUALS_OPERATOR()
349+DEFINE_CSTR_COMPARISON_OPERATOR(!=)
350+DEFINE_CSTR_COMPARISON_OPERATOR(<)
351+DEFINE_CSTR_COMPARISON_OPERATOR(<=)
352+DEFINE_CSTR_COMPARISON_OPERATOR(>)
353+DEFINE_CSTR_COMPARISON_OPERATOR(>=)
354+
320auto operator+(const any& lhs_, const any& rhs_) -> any {
355auto operator+(const any& lhs_, const any& rhs_) -> any {
321 const any& lhs = any::extractValue(lhs_);
356 const any& lhs = any::extractValue(lhs_);
322 const any& rhs = any::extractValue(rhs_);
357 const any& rhs = any::extractValue(rhs_);
323− assert(lhs.type == rhs.type);
324 switch (lhs.type) {
358 switch (lhs.type) {
325− case any::Type::Integer: return lhs.i + rhs.i;
359+ case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i + rhs.i;
326− case any::Type::Double: return lhs.d + rhs.d;
360+ case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d + rhs.d;
327− case any::Type::Character: return any(char(lhs.c + rhs.c));
361+ case any::Type::Character: assert(lhs.type == any::Type::Character); return any(char(lhs.c + rhs.c));
328− case any::Type::String: return (*lhs.s) + (*rhs.s);
362+ case any::Type::StringLiteral:
363+ assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
364+ assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
365+ return rhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs.r : lhs.r + *rhs.s;
366+ case any::Type::String:
367+ assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
368+ assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
369+ return rhs.type == any::Type::StringLiteral ? *lhs.s + rhs.r : *lhs.s + *rhs.s;
329 default: assert(false && "Unsupported type for '+' operator");
370 default: assert(false && "Unsupported type for '+' operator");
330 }
371 }
331 return nullptr;
372 return nullptr;
@@ -334,14 +375,17 @@ auto operator+(const any& lhs_, const any& rhs_) -> any {
334DEFINE_OPERATOR(+, long, long)
375DEFINE_OPERATOR(+, long, long)
335DEFINE_OPERATOR(+, double, double)
376DEFINE_OPERATOR(+, double, double)
336DEFINE_OPERATOR(+, char, char)
377DEFINE_OPERATOR(+, char, char)
337−DEFINE_OPERATOR(+, const string&, string)
338
378
339−auto operator+(const any& lhs, const char * rhs) -> string {
379+auto operator+(const any& lhs_, const char * rhs) -> std::string {
380+ const any& lhs = any::extractValue(lhs_);
381+ assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
340− return lhs.cast<string>() + rhs;
382+ return lhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs : *lhs.s + rhs;
341}
383}
342
384
343−auto operator+(const char * lhs, const any& rhs) -> string {
385+auto operator+(const char * lhs, const any& rhs_) -> std::string {
344− return lhs + rhs.cast<string>();
386+ const any& rhs = any::extractValue(rhs_);
387+ assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
388+ return rhs.type == any::Type::StringLiteral ? lhs + std::string(rhs.r) : lhs + *rhs.s;
345}
389}
346
390
347auto operator-(const any& lhs_, const any& rhs_) -> any {
391auto operator-(const any& lhs_, const any& rhs_) -> any {
pcc/include/purescript.hh+34−29
@@ -42,12 +42,12 @@
42 DECLARE_OPERATOR(op, long, bool) \
42 DECLARE_OPERATOR(op, long, bool) \
43 DECLARE_OPERATOR(op, double, bool) \
43 DECLARE_OPERATOR(op, double, bool) \
44 DECLARE_OPERATOR(op, char, bool) \
44 DECLARE_OPERATOR(op, char, bool) \
45− DECLARE_OPERATOR(op, const string&, bool) \
46 DECLARE_OPERATOR(op, const char *, bool)
45 DECLARE_OPERATOR(op, const char *, bool)
47
46
47+
48namespace PureScript {
48namespace PureScript {
49
49
50−using string = std::string;
50+using string = const char *;
51using runtime_error = std::runtime_error;
51using runtime_error = std::runtime_error;
52using nullptr_t = std::nullptr_t;
52using nullptr_t = std::nullptr_t;
53
53
@@ -58,12 +58,13 @@ const bool undefined = false;
58class any {
58class any {
59
59
60 public:
60 public:
61− enum class Type {
61+ enum class Type : int8_t {
62 Unknown,
62 Unknown,
63 Integer,
63 Integer,
64 Double,
64 Double,
65 Character,
65 Character,
66 Boolean,
66 Boolean,
67+ StringLiteral,
67 String,
68 String,
68 Map,
69 Map,
69 Vector,
70 Vector,
@@ -80,12 +81,12 @@ class any {
80 };
81 };
81 static constexpr as_thunk unthunk = as_thunk{};
82 static constexpr as_thunk unthunk = as_thunk{};
82
83
83− using map = std::unordered_map<const map_key_t, const any, map_key_t::hasher, map_key_t::equal>;
84+ using map = std::unordered_map<const map_key_t, const any, map_key_t::hasher, map_key_t::equal>;
84− using vector = std::vector<any>;
85+ using vector = std::vector<any>;
85 using fn = auto (*)(const any&) -> any;
86 using fn = auto (*)(const any&) -> any;
86 using closure = std::function<any(const any&)>;
87 using closure = std::function<any(const any&)>;
87− using eff_fn = std::function<any()>;
88+ using eff_fn = std::function<any()>;
88− using thunk = auto (*)(const as_thunk) -> const any&;
89+ using thunk = auto (*)(const as_thunk) -> const any&;
89
90
90 template <typename T>
91 template <typename T>
91 using shared = std::shared_ptr<T>;
92 using shared = std::shared_ptr<T>;
@@ -97,18 +98,19 @@ class any {
97
98
98 private:
99 private:
99 union {
100 union {
100− mutable long i;
101+ mutable long i;
101− mutable double d;
102+ mutable double d;
102− mutable char c;
103+ mutable char c;
103− mutable bool b;
104+ mutable bool b;
105+ mutable string r;
104− mutable shared<string> s;
106+ mutable shared<std::string> s;
105− mutable shared<map> m;
107+ mutable shared<map> m;
106− mutable shared<vector> v;
108+ mutable shared<vector> v;
107− mutable fn f;
109+ mutable fn f;
108− mutable shared<closure> l;
110+ mutable shared<closure> l;
109− mutable shared<eff_fn> e;
111+ mutable shared<eff_fn> e;
110− mutable thunk t;
112+ mutable thunk t;
111− mutable shared<void> p;
113+ mutable shared<void> p;
112 };
114 };
113
115
114 public:
116 public:
@@ -122,9 +124,15 @@ class any {
122 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
124 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
123 any(const T val) : type(Type::Boolean), b(val) {}
125 any(const T val) : type(Type::Boolean), b(val) {}
124
126
125− any(const string& val) : type(Type::String), s(make_shared<string>(val)) {}
127+ template <size_t N>
126− any(string&& val) noexcept : type(Type::String), s(make_shared<string>(std::move(val))) {}
127− any(const char val[]) : type(Type::String), s(make_shared<string>(val)) {}
128+ any(const char (&val)[N]) : type(Type::StringLiteral), r(val) {}
129+ any(char * val) : type(Type::String), s(make_shared<std::string>(val)) {}
130+
131+ any(const std::string& val) : type(Type::String), s(make_shared<std::string>(val)) {}
132+ any(std::string&& val) : type(Type::String), s(make_shared<std::string>(std::move(val))) {}
133+
134+ any(const shared<std::string>& val) : type(Type::String), s(val) {}
135+ any(shared<std::string>&& val) noexcept : type(Type::String), s(std::move(val)) {}
128
136
129 any(const map& val) : type(Type::Map), m(make_shared<map>(val)) {}
137 any(const map& val) : type(Type::Map), m(make_shared<map>(val)) {}
130 any(map&& val) noexcept : type(Type::Map), m(make_shared<map>(std::move(val))) {}
138 any(map&& val) noexcept : type(Type::Map), m(make_shared<map>(std::move(val))) {}
@@ -182,10 +190,7 @@ class any {
182 auto cast() const -> typename std::enable_if<std::is_same<T, bool>::value, T>::type;
190 auto cast() const -> typename std::enable_if<std::is_same<T, bool>::value, T>::type;
183
191
184 template <typename T>
192 template <typename T>
185− auto cast() const -> typename std::enable_if<std::is_same<T, string>::value, const T&>::type;
193+ auto cast() const -> typename std::enable_if<std::is_same<T, string>::value, T>::type;
186−
187− template <typename T>
188− auto cast() const -> typename std::enable_if<std::is_same<T, const char*>::value, const T>::type;
189
194
190 template <typename T>
195 template <typename T>
191 auto cast() const -> typename std::enable_if<std::is_same<T, map>::value, const T&>::type;
196 auto cast() const -> typename std::enable_if<std::is_same<T, map>::value, const T&>::type;
@@ -208,7 +213,8 @@ class any {
208 operator double() const;
213 operator double() const;
209 operator bool() const;
214 operator bool() const;
210
215
211− operator const string&() const;
216+ operator string() const;
217+ operator std::string() const;
212 operator const map&() const;
218 operator const map&() const;
213 operator const vector&() const;
219 operator const vector&() const;
214
220
@@ -232,8 +238,7 @@ class any {
232 DECLARE_OPERATOR(+, long, long)
238 DECLARE_OPERATOR(+, long, long)
233 DECLARE_OPERATOR(+, double, double)
239 DECLARE_OPERATOR(+, double, double)
234 DECLARE_OPERATOR(+, char, char)
240 DECLARE_OPERATOR(+, char, char)
235− DECLARE_OPERATOR(+, const string&, string)
241+ DECLARE_OPERATOR(+, const char *, std::string)
236− DECLARE_OPERATOR(+, const char *, string)
237
242
238 friend auto operator-(const any&, const any&) -> any;
243 friend auto operator-(const any&, const any&) -> any;
239
244
src/Language/PureScript/Pretty/Cpp.hs+7
@@ -214,6 +214,13 @@ literals = mkPattern' match
214 , return $ if null cpps then "" else "\n"
214 , return $ if null cpps then "" else "\n"
215 , prettyStatements cpps
215 , prettyStatements cpps
216 ]
216 ]
217+ match (CppReturn value@(CppStringLiteral _)) = fmap concat $ sequence
218+ [ return "return "
219+ , return . runType $ CppAny []
220+ , return "("
221+ , prettyPrintCpp' value
222+ , return ")"
223+ ]
217 match (CppReturn value) = fmap concat $ sequence
224 match (CppReturn value) = fmap concat $ sequence
218 [ return "return "
225 [ return "return "
219 , prettyPrintCpp' value
226 , prettyPrintCpp' value