git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
C++: small-map optimization
commitce67f6cd5fe1826e36b955f47121ee00747a2d66 authorAndy Arvanitis <andyarvanitis@gmail.com> dateMon 18 Jan 2016, 18:35 (11 years ago) parent3711c76
5 files changed+46−80
pcc/Make.hs−1 pcc/include/map_key.hh−56 pcc/include/purescript.cc+31−13 pcc/include/purescript.hh+11−6 src/Language/PureScript/Pretty/Cpp.hs+4−4
pcc/Make.hs−1
@@ -122,7 +122,6 @@ buildMakeActions outputDir filePathMap usePrefix =
122122 writeTextFile (outputDir </> "CMakeLists.txt") (fromString cmakeListsTxt)
123123 writeTextFile (supportDir </> "PureScript.hh") $ B.unpack $(embedFile "pcc/include/purescript.hh")
124124 writeTextFile (supportDir </> "PureScript.cc") $ B.unpack $(embedFile "pcc/include/purescript.cc")
125− writeTextFile (supportDir </> "map_key.hh") $ B.unpack $(embedFile "pcc/include/map_key.hh")
126125
127126 let inputPath = dropExtension $ getInputFile mn
128127 hfile = addExtension inputPath "hh"
pcc/include/map_key.hhdeleted−56
@@ -1,56 +0,0 @@
1−///////////////////////////////////////////////////////////////////////////////
2−//
3−// Module : map_key.hh
4−// Copyright : (c) Andy Arvanitis 2015
5−// License : MIT
6−//
7−// Maintainer : Andy Arvanitis <andy.arvanitis@gmail.com>
8−// Stability : experimental
9−// Portability :
10−//
11−// Support for maps using keys with compile-time hashes.
12−//
13−///////////////////////////////////////////////////////////////////////////////
14−//
15−#ifndef PS_MapKey_HH
16−#define PS_MapKey_HH
17−
18−#include <cstring>
19−
20−namespace PureScript {
21−
22− struct map_key_t {
23−
24− const uint64_t hash;
25− const char * const cstr;
26−
27− // Compile-time (fnv-1a) hash function
28− static constexpr auto fnv1a(const char s[], const uint64_t hash = 14695981039346656037UL) -> uint64_t {
29− return !s[0] ? hash : fnv1a(s + 1, (hash ^ static_cast<unsigned char>(s[0])) * 1099511628211UL);
30− }
31−
32− class hasher {
33− public:
34− auto operator() (const map_key_t& key) const -> size_t {
35− return key.hash;
36− }
37− };
38−
39− class equal {
40− public:
41− auto operator() (const map_key_t& key1, const map_key_t& key2) const -> bool {
42− return (key1.cstr == key2.cstr) || strcmp(key1.cstr, key2.cstr) == 0;
43− }
44− };
45− };
46−
47− template <uint64_t H>
48− constexpr auto make_map_key(const char s[]) -> const map_key_t {
49− return map_key_t{H, s};
50− }
51−
52− #define KEY(k) make_map_key<map_key_t::fnv1a(k)>(k)
53−
54−} // namespace PureScript
55−
56−#endif // PS_MapKey_HH
pcc/include/purescript.cc+31−13
@@ -17,7 +17,6 @@
1717namespace PureScript {
1818
1919#define COPY_DATA(src) \
20− type = src.type; \
2120 switch (type) { \
2221 case Type::Integer: i = src.i; break; \
2322 case Type::Double: d = src.d; break; \
@@ -37,7 +36,6 @@ namespace PureScript {
3736 }
3837
3938#define MOVE_DATA(src) \
40− type = src.type; \
4139 switch (type) { \
4240 case Type::Integer: i = src.i; break; \
4341 case Type::Double: d = src.d; break; \
@@ -56,32 +54,34 @@ namespace PureScript {
5654 default: assert(false && "Unsupported type in move"); \
5755 }
5856
59−any::any(const any& other) {
57+any::any(const any& other) : type(other.type) {
6058 COPY_DATA(other);
6159}
6260
63−any::any(any&& other) noexcept {
61+any::any(any&& other) noexcept : type(other.type) {
6462 MOVE_DATA(other);
6563}
6664
6765auto any::operator=(const any& rhs) -> any& {
66+ type = rhs.type;
6867 COPY_DATA(rhs);
6968 return *this;
7069}
7170
7271// Takes ownership -- might need to reconsider this
7372auto any::operator=(any& rhs) noexcept -> any& {
73+ type = rhs.type;
7474 MOVE_DATA(rhs);
7575 return *this;
7676}
7777
7878auto any::operator=(any&& rhs) noexcept -> any& {
79+ type = rhs.type;
7980 MOVE_DATA(rhs);
8081 return *this;
8182}
8283
8384any::~any() {
84− // std::cout << "destroy" << std::endl;
8585 switch (type) {
8686 case Type::Integer: ; break;
8787 case Type::Double: ; break;
@@ -225,10 +225,6 @@ any::operator string() const {
225225 return cast<string>();
226226}
227227
228−any::operator std::string() const {
229− return cast<string>();
230−}
231−
232228any::operator const map&() const {
233229 RETURN_VALUE(Type::Map, m, *)
234230}
@@ -257,16 +253,38 @@ auto any::extractValue(const any& a) -> const any& {
257253 return a;
258254}
259255
260−auto any::operator[](const map_key_t& rhs) const -> const any& {
261− RETURN_VALUE(Type::Map, m->at(rhs),)
256+auto any::operator[](const char rhs[]) const -> const any& {
257+ const any& val = extractValue(*this);
258+ assert(val.type == Type::Map);
259+ for (any::map::const_iterator it = val.m->begin(), end = val.m->end(); it != end; ++it) {
260+ if (it->first == rhs || strcmp(it->first, rhs) == 0) {
261+ return it->second;
262+ }
263+ }
264+ throw runtime_error("map key not found");
262265}
263266
264267auto any::operator[](const vector::size_type rhs) const -> const any& {
265− RETURN_VALUE(Type::Vector, v->at(rhs),)
268+ const any& val = extractValue(*this);
269+ assert(val.type == Type::Vector);
270+ return (*val.v)[rhs];
266271}
267272
268273auto any::operator[](const any& rhs) const -> const any& {
269− RETURN_VALUE(Type::Vector, v->at(rhs.cast<long>()),)
274+ const any& val = extractValue(*this);
275+ assert(val.type == Type::Vector);
276+ return (*val.v)[rhs.cast<long>()];
277+}
278+
279+auto any::contains(const char key[]) const -> bool {
280+ const any& val = extractValue(*this);
281+ assert(val.type == Type::Map);
282+ for (any::map::const_iterator it = val.m->begin(), end = val.m->end(); it != end; ++it) {
283+ if (it->first == key || strcmp(it->first, key) == 0) {
284+ return true;
285+ }
286+ }
287+ return false;
270288}
271289
272290//-----------------------------------------------------------------------------
pcc/include/purescript.hh+11−6
@@ -29,9 +29,8 @@
2929#include <functional>
3030#include <string>
3131#include <vector>
32−#include <unordered_map>
32+#include <utility>
3333#include <stdexcept>
34−#include "map_key.hh"
3534
3635#define DECLARE_OPERATOR(op, ty, rty) \
3736 friend auto operator op (const any&, ty) -> rty; \
@@ -48,9 +47,14 @@
4847namespace PureScript {
4948
5049using string = const char *;
51−using runtime_error = std::runtime_error;
5250using nullptr_t = std::nullptr_t;
5351
52+// Workaround for missing C++11 version in gcc
53+class runtime_error : public std::runtime_error {
54+public:
55+ runtime_error(const char message[]) : std::runtime_error(std::string(message)) {}
56+};
57+
5458const bool undefined = false;
5559
5660// A variant data class designed to provide some features of dynamic typing.
@@ -81,7 +85,7 @@ class any {
8185 };
8286 static constexpr as_thunk unthunk = as_thunk{};
8387
84− using map = std::unordered_map<const map_key_t, const any, map_key_t::hasher, map_key_t::equal>;
88+ using map = std::vector<std::pair<const char * const, const any>>;
8589 using vector = std::vector<any>;
8690 using fn = auto (*)(const any&) -> any;
8791 using closure = std::function<any(const any&)>;
@@ -214,14 +218,15 @@ class any {
214218 operator bool() const;
215219
216220 operator string() const;
217− operator std::string() const;
218221 operator const map&() const;
219222 operator const vector&() const;
220223
221− auto operator[](const map_key_t&) const -> const any&;
224+ auto operator[](const char[]) const -> const any&;
222225 auto operator[](const vector::size_type) const -> const any&;
223226 auto operator[](const any&) const -> const any&;
224227
228+ auto contains(const char[]) const -> bool;
229+
225230 auto extractPointer() const -> void*;
226231
227232 static auto extractValue(const any&) -> const any&;
src/Language/PureScript/Pretty/Cpp.hs+4−4
@@ -75,9 +75,9 @@ literals = mkPattern' match
7575 [ return $ runType mapType ++ "{\n"
7676 , withIndent $ do
7777 cpps <- forM ps $ \(key, value) -> do
78− val <- prettyPrintCpp' value
79− k <- prettyPrintCpp' (CppStringLiteral key)
80− return $ "{ " ++ "KEY" ++ parens k ++ ", " ++ val ++ " }"
78+ value' <- prettyPrintCpp' value
79+ key' <- prettyPrintCpp' (CppStringLiteral key)
80+ return $ "{ " ++ key' ++ ", " ++ value' ++ " }"
8181 indentString <- currentIndent
8282 return $ intercalate ", \n" $ map (indentString ++) cpps
8383 , return "\n"
@@ -306,7 +306,7 @@ indexer = mkPattern' match
306306 match (CppIndexer (CppNumericLiteral (Left index)) val) = return (show index ++ "UL", val)
307307 match (CppIndexer index val) = do
308308 index' <- prettyPrintCpp' index
309− return ("KEY" ++ parens index', val)
309+ return (index', val)
310310 match _ = mzero
311311
312312lam :: Pattern PrinterState Cpp ((String, [(String, Maybe CppType)], Maybe CppType), Cpp)