72#define BFN_ASSOC_OP_DEF(name, OP) \
73 friend bool operator OP(const name &lhs, const name &rhs) { \
74 return static_cast<const ABase &>(lhs) OP static_cast<const ABase &>(rhs); \
99struct _is_stable<cstring> : std::false_type { };
104template <
typename T1,
typename T2>
106 : std::integral_constant<bool, _is_stable<T1>::value && is_stable<T2>::value> {};
111template <
typename TH,
typename... Ts>
113 : std::integral_constant<bool, is_stable<TH>::value && _is_stable<std::tuple<Ts...>>::value> {};
115template <
typename... Ts>
123template <
typename Base, Iterable Itble,
typename =
void>
126 using hasher =
typename Base::hasher;
127 using key_equal =
typename Base::key_equal;
135 static constexpr bool iterable = Itble == Iterable::Yes;
140template <
typename Base, Iterable Itble>
144 using key_type =
typename Base::key_type;
145 using key_compare =
typename Base::key_compare;
146 using value_compare =
typename Base::value_compare;
151 using DefaultCompare = std::less<key_type>;
152 using DefaultTransparentCompare = std::less<void>;
156 Itble == Iterable::Yes ||
157 (Itble == Iterable::Auto &&
159 ((!std::is_same<key_compare, DefaultCompare>::value &&
160 !std::is_same<key_compare, DefaultTransparentCompare>::value)
168template <
typename Base, Iterable Itble>
173 using key_type =
typename Base::key_type;
174 using value_type =
typename Base::value_type;
175 using size_type =
typename Base::size_type;
176 using difference_type =
typename Base::difference_type;
177 using allocator_type =
typename Base::allocator_type;
178 using reference =
typename Base::reference;
179 using const_reference =
typename Base::const_reference;
180 using pointer =
typename Base::pointer;
181 using const_pointer =
typename Base::const_pointer;
182 using iterator =
typename Base::iterator;
183 using const_iterator =
typename Base::const_iterator;
184 using reverse_iterator =
typename Base::reverse_iterator;
185 using const_reverse_iterator =
typename Base::const_reverse_iterator;
190 using ImmBase::ImmBase;
192 using Base::operator=;
193 using Base::get_allocator;
195 iterator begin()
noexcept {
196 this->_ensure_iterable();
197 return Base::begin();
199 const_iterator begin()
const noexcept {
200 this->_ensure_iterable();
201 return Base::begin();
203 const_iterator cbegin()
const noexcept {
204 this->_ensure_iterable();
205 return Base::cbegin();
208 iterator unstable_begin()
noexcept {
return Base::begin(); }
209 const_iterator unstable_begin()
const noexcept {
return Base::begin(); }
210 const_iterator unstable_cbegin()
const noexcept {
return Base::cbegin(); }
215 reverse_iterator rbegin()
noexcept {
216 this->_ensure_iterable();
217 return Base::rbegin();
219 const_reverse_iterator rbegin()
const noexcept {
220 this->_ensure_iterable();
221 return Base::rbegin();
223 const_reverse_iterator crbegin()
const noexcept {
224 this->_ensure_iterable();
225 return Base::crbegin();
232 using Base::max_size;
237 using Base::emplace_hint;
245 std::pair<iterator, iterator> equal_range(
const key_type &key) {
246 this->_ensure_iterable();
247 return Base::equal_range(key);
249 std::pair<const iterator, const_iterator> equal_range(
const key_type &key)
const {
250 this->_ensure_iterable();
251 return Base::equal_range(key);
254 iterator lower_bound(
const key_type &key) {
255 this->_ensure_iterable();
256 return Base::lower_bound(key);
258 const_iterator lower_bound(
const key_type &key)
const {
259 this->_ensure_iterable();
260 return Base::lower_bound(key);
263 iterator upper_bound(
const key_type &key) {
264 this->_ensure_iterable();
265 return Base::upper_bound(key);
267 const_iterator upper_bound(
const key_type &key)
const {
268 this->_ensure_iterable();
269 return Base::upper_bound(key);
273 bool contains(
const key_type &key)
const {
return find(key) != end(); }
275 using Base::key_comp;
276 using Base::value_comp;
279 void _ensure_iterable()
const {
281 "To ensure the compiler is deterministic and preserves behaviour when "
282 "source values are renamed it is not possible to iterate over maps of "
283 "pointer and string types. Either use `ordered_map` to iterate in the "
284 "insertion order, or specify a comparator that uses some ordering that is "
285 "guaranteed to be stable accross runs and with renaming in the source file. "
286 "If you know for sure it is safe to iterate in string order in this case "
287 "(e.g. map of constant strings or other strings that do not depend on "
288 "the source code, you can use `iterable_map` instead of `map`. ");
297template <
typename Key,
typename T,
typename Compare = std::less<Key>,
298 typename Allocator = std::allocator<std::pair<const Key, T>>,
299 Iterable Itble = Iterable::Auto>
301 using ABase = std::map<Key, T, Compare, Allocator>;
305 using mapped_type =
typename Base::mapped_type;
311 map(std::initializer_list<typename Base::value_type> init,
const Compare &comp = Compare(),
312 const Allocator &alloc = Allocator())
313 :
Base(init, comp, alloc) {}
319 using ABase::operator=;
322 using ABase::operator[];
324 void swap(
map &other) { ABase::swap(other); }
326 using ABase::extract;
327 using ABase::insert_or_assign;
329 using ABase::try_emplace;
331 BFN_ASSOC_OP_DEF(
map, ==)
332 BFN_ASSOC_OP_DEF(
map, !=)
333 BFN_ASSOC_OP_DEF(
map, <)
334 BFN_ASSOC_OP_DEF(
map, >)
335 BFN_ASSOC_OP_DEF(
map, <=)
336 BFN_ASSOC_OP_DEF(
map, >=)
345 return static_cast<const ABase &
>(*this);
353template <
typename Key,
typename Compare = std::less<Key>,
typename Allocator = std::allocator<Key>,
354 Iterable Itble = Iterable::Auto>
356 using ABase = std::set<Key, Compare, Allocator>;
365 set(std::initializer_list<typename Base::value_type> init,
const Compare &comp = Compare(),
366 const Allocator &alloc = Allocator())
367 :
Base(init, comp, alloc) {}
373 using ABase::operator=;
376 void swap(
set &other) { Base::swap(other); }
378 BFN_ASSOC_OP_DEF(
set, ==)
379 BFN_ASSOC_OP_DEF(
set, !=)
380 BFN_ASSOC_OP_DEF(
set, <)
381 BFN_ASSOC_OP_DEF(
set, >)
382 BFN_ASSOC_OP_DEF(
set, <=)
383 BFN_ASSOC_OP_DEF(
set, >=)
392 return static_cast<const Base &
>(*this);
400template <
typename Key,
typename T,
typename Hash = boost::hash<Key>,
401 typename Equal = std::equal_to<Key>,
402 typename Allocator = std::allocator<std::pair<const Key, T>>>
403class hash_map :
private std::unordered_map<Key, T, Hash, Equal, Allocator> {
404 using ABase = std::unordered_map<Key, T, Hash, Equal, Allocator>;
407 using mapped_type =
typename ABase::mapped_type;
410 using ABase::operator=;
413 using ABase::operator[];
419 using ABase::max_size;
423 using ABase::emplace;
424 using ABase::emplace_hint;
425 using ABase::extract;
427 using ABase::insert_or_assign;
429 using ABase::try_emplace;
440 void swap(
hash_map &other)
noexcept { ABase::swap(other); }
454template <
typename T,
typename Hash = boost::hash<T>,
typename Equal = std::equal_to<T>,
455 typename Allocator = std::allocator<T>>
456class hash_set :
private std::unordered_set<T, Hash, Equal, Allocator> {
457 using ABase = std::unordered_set<T, Hash, Equal, Allocator>;
462 using ABase::operator=;
468 using ABase::max_size;
472 using ABase::emplace;
473 using ABase::emplace_hint;
484 void swap(
hash_set &other)
noexcept { ABase::swap(other); }
494template <
typename Key,
typename T,
typename Compare = std::less<Key>,
495 typename Allocator = std::allocator<std::pair<const Key, T>>>
496using iterable_map = map<Key, T, Compare, Allocator, Iterable::Yes>;
498template <
typename Key,
typename T,
typename Compare = std::less<Key>,
499 typename Allocator = std::allocator<std::pair<const Key, T>>>
500using non_iterable_map = map<Key, T, Compare, Allocator, Iterable::No>;
502template <
typename Key,
typename T,
typename Compare = std::less<Key>,
503 typename Allocator = std::allocator<std::pair<const Key, T>>>
506template <
typename Key,
typename Compare = std::less<Key>,
typename Allocator = std::allocator<Key>>
507using iterable_set = set<Key, Compare, Allocator, Iterable::Yes>;
509template <
typename Key,
typename Compare = std::less<Key>,
typename Allocator = std::allocator<Key>>
510using non_iterable_set = set<Key, Compare, Allocator, Iterable::No>;
512template <
typename Key,
typename Compare = std::less<Key>,
typename Allocator = std::allocator<Key>>
518template <
class K,
class T,
class V,
class Comp,
class Alloc, Iterable It>
519inline V get(
const map<K, V, Comp, Alloc, It> &m, T key, V def = V()) {
520 return get(m.unstable_iterable(), key, def);
523template <
class K,
class T,
class V,
class Comp,
class Alloc, Iterable It>
524inline V *getref(map<K, V, Comp, Alloc, It> &m, T key) {
525 return getref(m.unstable_iterable(), key);
528template <
class K,
class T,
class V,
class Comp,
class Alloc, Iterable It>
529inline const V *getref(
const map<K, V, Comp, Alloc, It> &m, T key) {
530 return getref(m.unstable_iterable(), key);
533template <
class K,
class T,
class V,
class Comp,
class Alloc, Iterable It>
534inline V get(
const map<K, V, Comp, Alloc, It> *m, T key, V def = V()) {
535 return m ? get(*m, key, def) : def;
538template <
class K,
class T,
class V,
class Comp,
class Alloc, Iterable It>
539inline V *getref(map<K, V, Comp, Alloc, It> *m, T key) {
540 return m ? getref(*m, key) : 0;
543template <
class K,
class T,
class V,
class Comp,
class Alloc, Iterable It>
544inline const V *getref(
const map<K, V, Comp, Alloc, It> *m, T key) {
545 return m ? getref(*m, key) : 0;
549std::ostream &operator<<(std::ostream &out,
const assoc::set<T> &set) {