]>
Commit | Line | Data |
---|---|---|
aa389a19 FCE |
1 | // -*- C++ -*- |
2 | // Copyright (C) 2015 Red Hat Inc. | |
3 | // | |
4 | // This file is part of systemtap, and is free software. You can | |
5 | // redistribute it and/or modify it under the terms of the GNU General | |
6 | // Public License (GPL); either version 2, or (at your option) any | |
7 | // later version. | |
8 | ||
9 | ||
10 | #ifndef STRINGTABLE_H | |
11 | #define STRINGTABLE_H | |
12 | ||
5d46f7cb | 13 | #include <functional> |
aa389a19 | 14 | #include <string> |
3dd76f53 AJ |
15 | #include <cstring> |
16 | ||
421a5349 JS |
17 | // TODO use C++17's std::string_view when possible. It even hashes natively. |
18 | // (some compilers already have std::experimental::string_view) | |
ea63d6ad | 19 | |
3dd76f53 | 20 | #if defined(HAVE_BOOST_UTILITY_STRING_REF_HPP) |
91f252b7 | 21 | #include <boost/version.hpp> |
aa389a19 FCE |
22 | #include <boost/utility/string_ref.hpp> //header with string_ref |
23 | ||
7eae03f8 FCE |
24 | // XXX: experimental tunables |
25 | #define INTERNED_STRING_FIND_MEMMEM 1 /* perf stat indicates a very slight benefit */ | |
26 | #define INTERNED_STRING_CUSTOM_HASH 1 /* maybe an abbreviated hash function for long strings? */ | |
924f8d22 | 27 | #define INTERNED_STRING_INSTRUMENT 0 /* write out hash logs ... super super slow */ |
47d349b1 FCE |
28 | |
29 | struct interned_string: public boost::string_ref | |
30 | { | |
31 | // all these construction operations intern the incoming string | |
3e4547ad | 32 | interned_string(): boost::string_ref() {} |
531de7b4 JS |
33 | interned_string(const char* value): |
34 | boost::string_ref(intern(value)) {} | |
35 | interned_string(const std::string& value): | |
36 | boost::string_ref(intern(value)) {} | |
37 | interned_string& operator = (const std::string& value) | |
38 | { return *this = intern(value); } | |
39 | interned_string& operator = (const char* value) | |
40 | { return *this = intern(value); } | |
91f252b7 AJ |
41 | |
42 | #if BOOST_VERSION < 105400 | |
43 | std::string to_string () const { return std::string(this->data(), this->size()); } | |
44 | ||
45 | // some comparison operators that aren't available in boost 1.53 | |
46 | bool operator == (const char* y) { return compare(boost::string_ref(y)) == 0; } | |
47 | bool operator == (const std::string& y) { return compare(boost::string_ref(y)) == 0; } | |
48 | friend bool operator == (interned_string x, interned_string y) { return x.compare(y) == 0; } | |
49 | friend bool operator == (const char * x, interned_string y) | |
50 | { | |
51 | return y.compare(boost::string_ref(x)) == 0; | |
52 | } | |
53 | friend bool operator == (const std::string& x, interned_string y) | |
54 | { | |
55 | return y.compare(boost::string_ref(x)) == 0; | |
56 | } | |
57 | ||
58 | bool operator != (const char* y) { return compare(boost::string_ref(y)) != 0; } | |
59 | bool operator != (const std::string& y) { return compare(boost::string_ref(y)) != 0; } | |
60 | friend bool operator != (interned_string x, interned_string y) { return x.compare(y) != 0; } | |
61 | friend bool operator != (const char * x, interned_string y) | |
62 | { | |
63 | return y.compare(boost::string_ref(x)) != 0; | |
64 | } | |
65 | friend bool operator != (const std::string& x, interned_string y) | |
66 | { | |
67 | return y.compare(boost::string_ref(x)) != 0; | |
68 | } | |
69 | #endif | |
70 | ||
47d349b1 | 71 | // easy out-conversion operators |
45a63356 | 72 | operator std::string () const { return this->to_string(); } |
3e4547ad | 73 | |
7371cd19 | 74 | // return an efficient substring reference |
07ebb812 FCE |
75 | interned_string substr(size_t pos = 0, size_t len = npos) const |
76 | { | |
7371cd19 | 77 | return boost::string_ref::substr(pos, len); |
07ebb812 | 78 | } |
45a63356 FCE |
79 | |
80 | // boost oversights | |
81 | template <typename F> | |
7eae03f8 | 82 | size_t find (const F& f, size_t start_pos) |
45a63356 | 83 | { |
7371cd19 | 84 | size_t x = this->substr(start_pos).find(f); |
45a63356 FCE |
85 | if (x == boost::string_ref::npos) |
86 | return x; | |
87 | else | |
88 | return x + start_pos; | |
89 | } | |
90 | ||
91 | template <typename F> | |
7eae03f8 | 92 | size_t find (const F& f) const |
45a63356 FCE |
93 | { |
94 | return boost::string_ref::find(f); | |
95 | } | |
7eae03f8 FCE |
96 | |
97 | #if INTERNED_STRING_FIND_MEMMEM | |
98 | size_t find (const boost::string_ref& f) const; | |
99 | size_t find (const std::string& f) const; | |
100 | size_t find (const char *f) const; | |
101 | #endif | |
cccf2f58 JS |
102 | |
103 | size_t find (const interned_string& f) const | |
104 | { | |
105 | return find (static_cast<const boost::string_ref&> (f)); | |
106 | } | |
45a63356 | 107 | |
47d349b1 | 108 | private: |
07ebb812 | 109 | static interned_string intern(const std::string& value); |
7cde9f59 | 110 | static interned_string intern(const char* value); |
2f119072 | 111 | static interned_string intern(char value); |
7371cd19 JS |
112 | |
113 | // This is private so we can be sure of ownership, from our interned string table. | |
114 | interned_string(const boost::string_ref& value): boost::string_ref(value) {} | |
47d349b1 | 115 | }; |
421a5349 JS |
116 | |
117 | namespace std { | |
118 | template<> struct hash<interned_string> { | |
119 | size_t operator() (interned_string s) const | |
120 | { | |
121 | // NB: we'd love to be able to hook up to a blob hashing | |
122 | // function in std::hash, but there isn't one. We don't want | |
123 | // to copy the interned_string into a temporary string just to | |
124 | // hash the thing. | |
125 | // | |
126 | // This code is based on the g++ _Fnv_hash_base ptr/length case. | |
127 | size_t hash = 0; | |
128 | const char* x = s.data(); | |
129 | for (size_t i=s.length(); i>0; i--) | |
130 | hash = (hash * 131) + *x++; | |
131 | return hash; | |
132 | } | |
133 | }; | |
134 | } | |
135 | ||
3dd76f53 | 136 | #else /* !defined(HAVE_BOOST_UTILITY_STRING_REF_HPP) */ |
47d349b1 | 137 | |
3dd76f53 AJ |
138 | struct interned_string : public std::string { |
139 | interned_string(): std::string() {} | |
140 | interned_string(const char* value): std::string (value ? :"") {} | |
141 | interned_string(const std::string& value): std::string(value) {} | |
142 | std::string to_string() const {return (std::string) *this; } | |
143 | void remove_prefix (size_t n) {*this = this->substr(n);} | |
144 | interned_string substr(size_t pos = 0, size_t len = npos) const | |
145 | { | |
146 | return (interned_string)std::string::substr(pos, len); | |
147 | } | |
148 | bool starts_with(const char* value) const | |
149 | { | |
150 | return (this->compare(0, std::strlen(value), value) == 0); | |
151 | } | |
152 | ||
153 | bool starts_with(const std::string& value) const | |
154 | { | |
155 | return (this->compare(0, value.length(), value) == 0); | |
156 | } | |
7371cd19 JS |
157 | |
158 | private: | |
159 | // c_str is not allowed on boost::string_ref, so add a private unimplemented | |
160 | // declaration here to prevent the use of string::c_str accidentally. | |
161 | const char* c_str() const; | |
3dd76f53 | 162 | }; |
47d349b1 | 163 | |
5d46f7cb JS |
164 | namespace std { |
165 | template<> struct hash<interned_string> { | |
421a5349 | 166 | size_t operator() (interned_string const& s) const |
5d46f7cb | 167 | { |
421a5349 JS |
168 | // strings are directly hashable |
169 | return hash<string>()(s); | |
5d46f7cb JS |
170 | } |
171 | }; | |
172 | } | |
aa389a19 | 173 | |
421a5349 JS |
174 | #endif /* defined(HAVE_BOOST_UTILITY_STRING_REF_HPP) */ |
175 | ||
aa389a19 FCE |
176 | #endif // STRINGTABLE_H |
177 | ||
178 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |