11# include <absl/container/flat_hash_map.h>
12# include <absl/container/flat_hash_set.h>
14# include <unordered_map>
15# include <unordered_set>
42 constexpr String() noexcept = default;
51 bool res = s1->size == s2->size;
52 for (
size_t i = 0, e = s1->size; res && i != e; ++i)
53 res &= s1->chars[i] == s2->chars[i];
60 return std::hash<std::string_view>()(std::string_view(s->chars, s->size));
66 friend constexpr H AbslHashValue(H h,
const String*
string)
noexcept {
67 return H::combine(std::move(h), std::string_view(string->chars, string->size));
72 static_assert(
sizeof(String) ==
sizeof(size_t),
"String.chars should be 0");
75 constexpr Sym(uintptr_t ptr) noexcept
79 constexpr Sym() noexcept = default;
83 [[nodiscard]] constexpr
bool empty() const noexcept {
return ptr_ == 0; }
84 [[nodiscard]]
constexpr size_t size() const noexcept {
85 if (
empty())
return 0;
87 return ((
const String*)ptr_)->size;
97 constexpr char front() const noexcept {
return (*
this)[0]; }
98 constexpr char back() const noexcept {
return (*
this)[
size() - 1]; }
106 constexpr auto cend() const noexcept {
return end(); }
107 constexpr auto rbegin() const noexcept {
return std::reverse_iterator(
end()); }
108 constexpr auto rend() const noexcept {
return std::reverse_iterator(
begin()); }
110 constexpr auto crend() const noexcept {
return rend(); }
121 friend constexpr std::strong_ordering
operator<=>(
Sym s,
char c)
noexcept {
return cmp<false>(s, c); }
122 friend constexpr std::strong_ordering
operator<=>(
char c,
Sym s)
noexcept {
return cmp<true>(s, c); }
123 friend constexpr bool operator==(
Sym s,
char c)
noexcept {
return (s.size() == 1) && (s[0] == c); }
124 friend constexpr bool operator==(
char c,
Sym s)
noexcept {
return (s.size() == 1) && (s[0] == c); }
130 requires std::is_convertible_v<T, std::string_view>
132 return lhs.view() <=> std::string_view(rhs);
135 requires std::is_convertible_v<T, std::string_view>
137 return std::string_view(lhs) <=> rhs.view();
141 requires std::is_convertible_v<T, std::string_view>
143 return lhs.view() == std::string_view(rhs);
147 requires std::is_convertible_v<T, std::string_view>
149 return std::string_view(lhs) == rhs.view();
155 [[nodiscard]]
constexpr const char*
c_str() const noexcept {
return view().data(); }
157 [[nodiscard]]
constexpr std::string_view
view() const noexcept {
158 if (
empty())
return {std::bit_cast<const char*>(&ptr_), 0};
161 uintptr_t offset = std::endian::native == std::endian::little ? 1 : 0;
163 auto S = std::bit_cast<const String*>(ptr_);
164 return std::string_view(S->chars, S->size);
166 constexpr operator std::string_view() const noexcept {
return view(); }
171 constexpr std::string
str() const noexcept {
return std::string(
view()); }
172 constexpr explicit operator std::string() const noexcept {
return str(); }
173 constexpr explicit operator bool() const noexcept {
return ptr_; }
178 friend constexpr H AbslHashValue(H h,
Sym sym)
noexcept {
179 return H::combine(std::move(h), sym.ptr_);
182 friend struct ::std::hash<fe::Sym>;
189 size_t operator()(
Sym s)
const noexcept {
return std::hash<uintptr_t>()(s.ptr_); }
190 size_t operator()(std::string_view v)
const noexcept {
return std::hash<std::string_view>()(v); }
196 bool operator()(
Sym a, std::string_view b)
const noexcept {
return a.view() == b; }
197 bool operator()(std::string_view a,
Sym b)
const noexcept {
return a == b.view(); }
203 static constexpr std::strong_ordering cmp(
Sym s,
char c)
noexcept {
204 const auto n = s.size();
205 if (n == 0)
return Rev ? std::strong_ordering::greater : std::strong_ordering::less;
207 auto cmp = s[0] <=> c;
208 if (cmp != 0)
return cmp;
210 return (n == 1) ? std::strong_ordering::equal
211 : (Rev ? std::strong_ordering::less : std::strong_ordering::greater);
225struct std::hash<
fe::Sym> {
226 size_t operator()(
fe::Sym sym)
const noexcept {
return std::hash<uintptr_t>()(sym.ptr_); }
238using SymMap = absl::flat_hash_map<Sym, V, Sym::Hash, Sym::Eq>;
239using SymSet = absl::flat_hash_set<Sym, Sym::Hash, Sym::Eq>;
242using SymMap = std::unordered_map<Sym, V, Sym::Hash, Sym::Eq>;
243using SymSet = std::unordered_set<Sym, Sym::Hash, Sym::Eq>;
260 : pool_(container_.allocator<const
String*>()) {}
272 if (s.empty())
return Sym();
273 auto size = s.size();
276 uintptr_t ptr = size;
279 if constexpr (std::endian::native == std::endian::little)
280 for (uintptr_t i = 0, shift = 8; i != size; ++i, shift += 8)
281 ptr |= (uintptr_t(s[i]) << shift);
284 ptr |= (uintptr_t(s[i]) << shift);
288 auto state = strings_.
state();
290 new (ptr)
String(s.size());
291 *std::copy(s.begin(), s.end(), ptr->chars) =
'\0';
292 auto [i, ins] = pool_.emplace(ptr);
293 if (ins)
return Sym(std::bit_cast<uintptr_t>(ptr));
295 return Sym(std::bit_cast<uintptr_t>(*i));
297 Sym sym(
const std::string& s) {
return sym((std::string_view)s); }
299 constexpr Sym sym(
const char* s) {
return s ==
nullptr ?
Sym() :
sym(std::string_view(s)); }
306 swap(p1.strings_, p2.strings_ );
308 swap(p1.container_, p2.container_);
310 swap(p1.pool_, p2.pool_ );
317 absl::flat_hash_set<const String*, absl::Hash<const String*>, String::Equal> pool_;
320 std::unordered_set<const String*, String::Hash, String::Equal, Arena::Allocator<const String*>> pool_;
324static_assert(std::is_trivially_copyable_v<Sym>);
325static_assert(
sizeof(uintptr_t) ==
sizeof(
void*),
"uintptr_t must match pointer size");
326static_assert(std::has_unique_object_representations_v<uintptr_t>);
327static_assert(std::endian::native == std::endian::little || std::endian::native == std::endian::big,
328 "mixed endianess not supported");
An arena pre-allocates so-called pages of size Arena::page_size_.
constexpr void deallocate(size_t num_bytes) noexcept
Removes num_bytes again.
constexpr void * allocate(size_t num_bytes, size_t align)
Get n bytes of fresh memory.
State state() const noexcept
Hash set where all strings - wrapped in Symbol - live in.
Sym sym(std::string_view s)
SymPool & operator=(SymPool)=delete
SymPool(const SymPool &)=delete
Sym sym(const std::string &s)
SymPool(SymPool &&other) noexcept
constexpr Sym sym(const char *s)
s is a null-terminated C-string.
friend void swap(SymPool &p1, SymPool &p2) noexcept
A Symbol just wraps a pointer to Sym::String, so pass Sym itself around as value.
friend constexpr std::strong_ordering operator<=>(char c, Sym s) noexcept
friend constexpr auto operator<=>(Sym s1, Sym s2) noexcept
constexpr auto rend() const noexcept
constexpr auto begin() const noexcept
constexpr char front() const noexcept
constexpr std::string_view operator*() const noexcept
constexpr bool empty() const noexcept
static constexpr size_t Short_String_Mask
static constexpr size_t Short_String_Bytes
constexpr auto cend() const noexcept
friend constexpr bool operator==(char c, Sym s) noexcept
constexpr size_t size() const noexcept
constexpr Sym() noexcept=default
constexpr char back() const noexcept
friend constexpr auto operator<=>(Sym lhs, const T &rhs) noexcept
friend std::ostream & operator<<(std::ostream &o, Sym sym)
friend constexpr bool operator==(Sym s1, Sym s2) noexcept
friend constexpr bool operator==(const T &lhs, Sym rhs) noexcept
constexpr auto crbegin() const noexcept
constexpr char operator[](size_t i) const noexcept
friend constexpr bool operator==(Sym s, char c) noexcept
constexpr auto crend() const noexcept
constexpr auto rbegin() const noexcept
constexpr std::string str() const noexcept
This involves a copy.
constexpr const char * c_str() const noexcept
friend constexpr auto operator<=>(const T &lhs, Sym rhs) noexcept
constexpr auto cbegin() const noexcept
constexpr auto end() const noexcept
friend constexpr bool operator==(Sym lhs, const T &rhs) noexcept
constexpr std::string_view view() const noexcept
friend constexpr std::strong_ordering operator<=>(Sym s, char c) noexcept
std::unordered_map< Sym, V, Sym::Hash, Sym::Eq > SymMap
std::unordered_set< Sym, Sym::Hash, Sym::Eq > SymSet
bool operator()(Sym a, Sym b) const noexcept
bool operator()(std::string_view a, Sym b) const noexcept
bool operator()(Sym a, std::string_view b) const noexcept
size_t operator()(std::string_view v) const noexcept
size_t operator()(Sym s) const noexcept
constexpr bool operator()(const String *s1, const String *s2) const noexcept
size_t operator()(const String *s) const noexcept
constexpr String() noexcept=default