header_utils
Loading...
Searching...
No Matches
symbol.h
1
4
5#pragma once
6
7#include "min-cpp-version/cpp20.h"
8#include <string>
9#include <string_view>
10#include <set>
11
12namespace ghassanpl
13{
21
23 template <typename SYMBOL_PROVIDER>
24 struct symbol_base
25 {
26 using symbol_provider = SYMBOL_PROVIDER;
27 using internal_value_type = typename symbol_provider::internal_value_type;
28 using hash_type = typename symbol_provider::hash_type;
29
30 internal_value_type value = symbol_provider::empty_value();
31
32 template <typename T>
33 requires std::constructible_from<std::string_view, T> && (!std::same_as<std::remove_cvref_t<T>, symbol_base>)
34 symbol_base(T&& val) : value{ symbol_provider::insert(std::forward<T>(val)) } { }
35
36 template <typename T>
37 requires std::constructible_from<std::string_view, T> && (!std::same_as<std::remove_cvref_t<T>, symbol_base>)
38 symbol_base& operator=(T&& val) noexcept { value = symbol_provider::insert(std::forward<T>(val)); return *this; }
39
40 symbol_base() noexcept = default;
41
42 symbol_base(symbol_base const& other) noexcept = default;
43 symbol_base(symbol_base&& other) noexcept = default;
44 symbol_base& operator=(symbol_base const& other) noexcept = default;
45 symbol_base& operator=(symbol_base&& other) noexcept = default;
46
47 [[nodiscard]] hash_type get_hash() const noexcept { return symbol_provider::hash_for(value); }
48 [[nodiscard]] std::string_view get_string() const noexcept { return symbol_provider::string_for(value); }
49 [[nodiscard]] explicit operator std::string_view() const noexcept { return symbol_provider::string_for(value); }
50 [[nodiscard]] explicit operator std::string() const noexcept { return std::string{ get_string() }; }
51 [[nodiscard]] auto to_string() const noexcept { return std::string{ get_string() }; }
52
54 [[nodiscard]] auto operator->() const noexcept
55 requires requires { { std::to_address(value) } -> meets<std::is_pointer>; }
56 { return std::to_address(value); }
57
58 [[nodiscard]] bool operator==(symbol_base const& other) const noexcept { return value == other.value || symbol_provider::compare(value, other.value) == 0; }
59 [[nodiscard]] auto operator<=>(symbol_base const& other) const noexcept { return symbol_provider::compare(value, other.value); }
60
61 [[nodiscard]] friend bool operator==(std::string_view a, symbol_base const& b) noexcept { return a == b.get_string(); }
62 [[nodiscard]] friend auto operator<=>(std::string_view a, symbol_base const& b) noexcept { return a <=> b.get_string(); }
63
64 //[[nodiscard]] auto begin() const noexcept { return get_string().begin(); }
65 //[[nodiscard]] auto end() const noexcept { return get_string().end(); }
66 [[nodiscard]] bool empty() const noexcept { return value == symbol_provider::empty_value(); }
67 [[nodiscard]] size_t size() const noexcept { return get_string().size(); }
68 friend std::ostream& operator<<(std::ostream& o, const symbol_base& ptr)
69 {
70 o << ptr.get_string();
71 return o;
72 }
73 };
74
76 template <typename T>
77 concept symbol_provider =
78 std::is_class_v<T>
79 && requires {
81 typename T::internal_value_type;
82
84 typename T::hash_type;
85
87 { T::empty_value() } noexcept -> std::same_as<typename T::internal_value_type>;
88
90 { T::insert(std::string_view{}) } -> std::same_as<typename T::internal_value_type>;
91
93 { T::string_for(typename T::internal_value_type{}) } noexcept -> std::same_as<std::string_view>;
94
96 { T::hash_for(typename T::internal_value_type{}) } noexcept -> std::same_as<typename T::hash_type>;
97
99 { T::compare(typename T::internal_value_type{}, typename T::internal_value_type{}) } noexcept -> std::same_as<std::strong_ordering>;
100 }
101 && std::three_way_comparable<typename T::internal_value_type>
102 && std::regular<typename T::internal_value_type>
103 ;
104
106}
107
108template <typename SYMBOL_PROVIDER>
109struct std::hash<ghassanpl::symbol_base<SYMBOL_PROVIDER>> {
110 size_t operator()(const ghassanpl::symbol_base<SYMBOL_PROVIDER>& x) const noexcept { return x.get_hash(); }
111};
112
113namespace ghassanpl
114{
115
121 template <typename TAG = void>
122 struct default_symbol_provider_t
123 {
124 static default_symbol_provider_t& instance() noexcept
125 {
126 static default_symbol_provider_t inst;
127 return inst;
128 }
129
130 using internal_value_type = std::string const*;
131 using hash_type = size_t;
132 [[nodiscard]] static internal_value_type empty_value() noexcept { return instance().m_empty_string; }
133 [[nodiscard]] static internal_value_type insert(std::string_view val)
134 {
135 if (val.empty())
136 return empty_value();
137
138 auto& values = instance().m_values;
139 if (auto v = values.find(val); v == values.end())
140 return &*values.insert(std::string{ val }).first;
141 else
142 return &*v;
143 }
144 [[nodiscard]] static std::string_view string_for(internal_value_type val) noexcept { return val ? std::string_view{ *val } : std::string_view{}; }
145 [[nodiscard]] static hash_type hash_for(internal_value_type val) noexcept { return std::hash<const void*>{}(val); }
146
147 [[nodiscard]] static std::strong_ordering compare(internal_value_type a, internal_value_type b) noexcept {
148 return (a == b) ? std::strong_ordering::equal : (*a <=> *b);
149 }
150
151 // Utility functions
152
153 void clear() noexcept
154 {
156 auto e = m_values.extract(std::string{});
157 m_values.clear();
158 m_values.insert(std::move(e));
159 }
160
161 [[nodiscard]] size_t size() const noexcept { return m_values.size(); }
162 [[nodiscard]] size_t count() const noexcept { return size(); }
163
164 [[nodiscard]] auto const& values() const noexcept { return m_values; }
165 [[nodiscard]] auto empty_string() const noexcept { return m_empty_string; }
166
167 protected:
168
169 std::set<std::string, std::less<>> m_values{ std::string{} };
170 std::string const* m_empty_string = &*m_values.begin();
171
172 default_symbol_provider_t() = default;
173 default_symbol_provider_t(default_symbol_provider_t const&) = delete;
174 default_symbol_provider_t& operator=(default_symbol_provider_t const&) = delete;
175 };
176
180
184}
185
The requirements for a symbol provider.
Definition symbol.h:77
symbol_base< default_symbol_provider > symbol
A symbol type suitable for most single-threaded uses.
Definition symbol.h:183
default_symbol_provider_t< void > default_symbol_provider
A basic symbol_provider suitable for most single-threaded uses.
Definition symbol.h:179
Primary namespace for everything in this library.
Definition align+rec2.h:10
The default symbol provider usable for most symbol implementations.
Definition symbol.h:123
The base class for all symbols.
Definition symbol.h:25
auto operator->() const noexcept
Only available if the internal value type is a pointer.
Definition symbol.h:54