LibSWOC++ 1.5.14
Solid Wall of C++
Loading...
Searching...
No Matches
Lexicon.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright Network Geographics 2014
7
8#pragma once
9
10#include <string_view>
11#include <initializer_list>
12#include <tuple>
13#include <functional>
14#include <array>
15#include <variant>
16#include <ctype.h>
17
18#include "swoc/swoc_version.h"
20#include "swoc/MemArena.h"
21#include "swoc/bwf_base.h"
22#include "swoc/ext/HashFNV.h"
23
24namespace swoc { inline namespace SWOC_VERSION_NS {
25namespace detail {
35template <typename... Args>
36std::string
37what(std::string_view const &fmt, Args &&...args) {
38 std::string zret;
39 return swoc::bwprint_v(zret, fmt, std::forward_as_tuple(args...));
40}
41
42// Exported because inner classes in template classes cannot be used in partial specialization
43// which is required for tuple support. This should be removed next time there is a API changing
44// release because tuple access is being deprecated.
45template <typename E> struct lexicon_pair_type {
46 E _value;
47 TextView _name;
48
52 lexicon_pair_type(E value, TextView name) : _value(value), _name(name) {}
53};
54
55} // namespace detail
56
59template <typename E>
60size_t
62 static constexpr std::hash<E> hasher;
63 return hasher(e);
64}
65
88template <typename E> class Lexicon {
89 using self_type = Lexicon;
90
91protected:
92 struct Item;
93
94public:
98
99 // Deprecated - use the member names now.
101 static constexpr auto VALUE_IDX = 0;
103 static constexpr auto NAME_IDX = 1;
104
114 using UnknownValueHandler = std::function<TextView(E)>;
115
122 using UnknownNameHandler = std::function<E(TextView)>;
123
128 using Default = std::variant<std::monostate, E, TextView, UnknownNameHandler, UnknownValueHandler>;
129
132 struct Definition {
133 const E &value;
134 std::initializer_list<TextView> const &names;
135 };
136
138 Lexicon();
139
140 using with = std::initializer_list<Pair> const &;
141 using with_multi = std::initializer_list<Definition> const &;
142
158 explicit Lexicon(with_multi items, Default handler_1 = Default{}, Default handler_2 = Default{});
159
173 explicit Lexicon(with items, Default handler_1 = Default{}, Default handler_2 = Default{});
174
185 explicit Lexicon(Default handler_1, Default handler_2 = Default{});
186
187 Lexicon(self_type &&that) = default;
188
194 TextView operator[](E const &value) const;
195
201 E operator[](TextView const &name) const;
202
206 template <typename... Args> self_type &define(E value, Args &&...names);
207
208 // These are really for consistency with constructors, they're not expected to be commonly used.
211 self_type &define(E value, const std::initializer_list<TextView> &names);
212
218 self_type &define(const Pair &pair);
219
230 self_type &define(const Definition &init);
231
251 self_type &set_default(Default const &handler);
252
254 size_t count() const;
255
256protected:
259 using self_type = base_iterator;
260
261 public:
262 using value_type = const Pair;
263 using pointer = value_type *;
265 using difference_type = ptrdiff_t;
266 using iterator_category = std::bidirectional_iterator_tag;
268 base_iterator() = default;
270 reference operator*() const;
272 pointer operator->() const;
274 bool operator==(self_type const &that) const;
276 bool operator!=(self_type const &that) const;
277
278 protected:
279 explicit base_iterator(Item const *item) : _item(item) {}
280
281 const Item *_item{nullptr};
282 };
283
284public:
289 using super_type = base_iterator;
290 using self_type = value_iterator;
291
292 public:
293 using value_type = typename super_type::value_type;
294 using pointer = typename super_type::pointer;
295 using reference = typename super_type::reference;
296
298 value_iterator() = default;
299
301 value_iterator(self_type const &that) = default;
302
304 value_iterator(self_type &&that) = default;
305
307 self_type &operator=(self_type const &that) = default;
308
310 self_type &operator++();
311
313 self_type operator++(int);
314
316 self_type &operator--();
317
319 self_type operator--(int);
320
321 protected:
322 value_iterator(const Item *item) : super_type(item){};
323
324 friend Lexicon;
325 };
326
328 private:
329 using self_type = name_iterator;
330 using super_type = base_iterator;
331
332 public:
334 name_iterator() = default;
335
337 name_iterator(self_type const &that) = default;
338
340 name_iterator(self_type &&that) = default;
341
343 self_type &operator=(self_type const &that) = default;
344
346 self_type &operator++();
347
349 self_type operator++(int);
350
352 self_type &operator--();
353
355 self_type operator--(int);
356
357 protected:
358 name_iterator(const Item *item) : super_type(item){};
359
360 friend Lexicon;
361 };
362
368
370 const_iterator begin() const;
371
373 const_iterator end() const;
374
377 begin_names() const {
378 return {_by_name.begin()};
379 }
380
381 name_iterator
382 end_names() const {
383 return {_by_name.end()};
384 }
385
387 // Helper struct to return to enable container iteration for names.
388 struct ByNameHelper {
389 self_type const &_lexicon;
390 ByNameHelper(self_type const &self) : _lexicon(self) {}
391 name_iterator
392 begin() const {
393 return _lexicon.begin_names();
394 }
395 name_iterator
396 end() const {
397 return _lexicon.end_names();
398 }
399 };
401
413 ByNameHelper
414 by_names() const {
415 return {*this};
416 }
417
418protected:
420 using NameDefault = std::variant<std::monostate, std::string_view, UnknownValueHandler>;
422 using ValueDefault = std::variant<std::monostate, E, UnknownNameHandler>;
423
427
429 std::string_view
430 operator()(std::monostate const &) const {
431 throw std::domain_error("Lexicon: invalid enumeration value");
432 }
433
435 std::string_view
436 operator()(TextView const &name) const {
437 return name;
438 }
439
441 std::string_view
442 operator()(UnknownValueHandler const &handler) const {
443 return handler(_value);
444 }
445 };
446
449 std::string_view _name;
450
452 E
453 operator()(std::monostate const &) const {
454 throw std::domain_error(detail::what("Lexicon: Unknown name \"{}\"", _name).data());
455 }
456
458 E
459 operator()(E const &value) const {
460 return value;
461 }
462
464 E
465 operator()(UnknownNameHandler const &handler) const {
466 return handler(_name);
467 }
468 };
469
472 struct Item {
479 Item(E value, TextView name);
480
482
484 // Intrusive list linkage support.
485 struct NameLinkage {
486 Item *_next{nullptr};
487 Item *_prev{nullptr};
488
489 static Item *&next_ptr(Item *);
490 static Item *&prev_ptr(Item *);
491 static std::string_view key_of(Item *);
492 static uint32_t hash_of(std::string_view s);
493 static bool equal(std::string_view const &lhs, std::string_view const &rhs);
494 } _name_link;
495
496 // Intrusive linkage for value lookup.
497 struct ValueLinkage {
498 Item *_next{nullptr};
499 Item *_prev{nullptr};
500
501 static Item *&next_ptr(Item *);
502 static Item *&prev_ptr(Item *);
503 static E key_of(Item *);
504 static size_t hash_of(E);
505 static bool equal(E lhs, E rhs);
506 } _value_link;
508 };
509
511 TextView localize(TextView const &name);
512
521};
522
523// ==============
524// Implementation
525
526// ----
527// Item
528
529template <typename E> Lexicon<E>::Item::Item(E value, TextView name) : _payload{value, name} {}
530
532template <typename E>
533auto
535 return item->_name_link._next;
536}
537
538template <typename E>
539auto
540Lexicon<E>::Item::NameLinkage::prev_ptr(Item *item) -> Item *& {
541 return item->_name_link._prev;
542}
543
544template <typename E>
545auto
546Lexicon<E>::Item::ValueLinkage::next_ptr(Item *item) -> Item *& {
547 return item->_value_link._next;
548}
549
550template <typename E>
551auto
553 return item->_value_link._prev;
554}
555
556template <typename E>
557std::string_view
559 return item->_payload._name;
560}
561
562template <typename E>
563E
565 return item->_payload._value;
566}
567
568template <typename E>
569uint32_t
570Lexicon<E>::Item::NameLinkage::hash_of(std::string_view s) {
571 return Hash32FNV1a().hash_immediate(transform_view_of(&::toupper, s));
572}
573
574template <typename E>
575size_t
577 return Lexicon_Hash<E>(value);
578}
579
580template <typename E>
581bool
582Lexicon<E>::Item::NameLinkage::equal(std::string_view const &lhs, std::string_view const &rhs) {
583 return 0 == strcasecmp(lhs, rhs);
584}
585
586template <typename E>
587bool
589 return lhs == rhs;
590}
592
593// -------
594// Lexicon
595
596template <typename E> Lexicon<E>::Lexicon() {}
597
598template <typename E> Lexicon<E>::Lexicon(with_multi items, Default handler_1, Default handler_2) {
599 for (auto const &item : items) {
600 this->define(item.value, item.names);
601 }
602
603 for (auto &&h : {handler_1, handler_2}) {
604 this->set_default(h);
605 }
606}
607
608template <typename E> Lexicon<E>::Lexicon(with items, Default handler_1, Default handler_2) {
609 for (auto const &item : items) {
610 this->define(item);
611 }
612
613 for (auto &&h : {handler_1, handler_2}) {
614 this->set_default(h);
615 }
616}
617
618template <typename E> Lexicon<E>::Lexicon(Default handler_1, Default handler_2) {
619 for (auto &&h : {handler_1, handler_2}) {
620 this->set_default(h);
621 }
622}
623
624template <typename E>
627 auto span = _arena.alloc_span<char>(name.size());
628 memcpy(span, name);
629 return {span.data(), span.size()};
630}
631
632template <typename E>
634Lexicon<E>::operator[](E const &value) const {
635 if (auto spot = _by_value.find(value); spot != _by_value.end()) {
636 return spot->_payload._name;
637 }
638 return std::visit(NameDefaultVisitor{value}, _name_default);
639}
640
641template <typename E>
642E
644 if (auto spot = _by_name.find(name); spot != _by_name.end()) {
645 return spot->_payload._value;
646 }
647 return std::visit(ValueDefaultVisitor{name}, _value_default);
648}
649
650template <typename E>
651auto
652Lexicon<E>::define(E value, const std::initializer_list<TextView> &names) -> self_type & {
653 if (names.size() < 1) {
654 throw std::invalid_argument("A defined value must have at least a primary name");
655 }
656 for (auto const &name : names) {
657 if (_by_name.find(name) != _by_name.end()) {
658 throw std::invalid_argument(detail::what("Duplicate name '{}' in Lexicon", name));
659 }
660 auto i = _arena.make<Item>(value, this->localize(name));
661 _by_name.insert(i);
662 // Only put primary names in the value table.
663 if (_by_value.find(value) == _by_value.end()) {
664 _by_value.insert(i);
665 }
666 }
667 return *this;
668}
669
670template <typename E>
671template <typename... Args>
672auto
673Lexicon<E>::define(E value, Args &&...names) -> self_type & {
674 static_assert(sizeof...(Args) > 0, "A defined value must have at least a primary name");
675 return this->define(value, {std::forward<Args>(names)...});
676}
677
678template <typename E>
679auto
680Lexicon<E>::define(const Pair &pair) -> self_type & {
681 return this->define(pair._value, pair._name);
682}
683
684template <typename E>
685auto
686Lexicon<E>::define(const Definition &init) -> self_type & {
687 return this->define(init.value, init.names);
688}
689
690template <typename E>
691auto
692Lexicon<E>::set_default(Default const &handler) -> self_type & {
693 switch (handler.index()) {
694 case 0:
695 break;
696 case 1:
697 _value_default = std::get<1>(handler);
698 break;
699 case 3:
700 _value_default = std::get<3>(handler);
701 break;
702 case 2:
703 _name_default = std::get<2>(handler);
704 break;
705 case 4:
706 _name_default = std::get<4>(handler);
707 break;
708 }
709 return *this;
710}
711
712template <typename E>
713size_t
715 return _by_value.count();
716}
717
718template <typename E>
719auto
721 return const_iterator{static_cast<const Item *>(_by_value.begin())};
722}
723
724template <typename E>
725auto
727 return {};
728}
729
730// Iterators
731
732template <typename E>
733auto
735 return _item->_payload;
736}
737
738template <typename E>
739auto
741 return &(_item->_payload);
742}
743
744template <typename E>
745bool
746Lexicon<E>::base_iterator::operator==(self_type const &that) const {
747 return _item == that._item;
748}
749
750template <typename E>
751bool
752Lexicon<E>::base_iterator::operator!=(self_type const &that) const {
753 return _item != that._item;
754}
755
756template <typename E>
757auto
759 super_type::_item = super_type::_item->_value_link._next;
760 return *this;
761}
762
763template <typename E>
764auto
766 self_type tmp{*this};
767 ++*this;
768 return tmp;
769}
770
771template <typename E>
772auto
774 super_type::_item = super_type::_item->_value_link->_prev;
775 return *this;
776}
777
778template <typename E>
779auto
781 self_type tmp;
782 ++*this;
783 return tmp;
784}
785
786template <typename E>
787auto
789 super_type::_item = super_type::_item->_name_link._next;
790 return *this;
791}
792
793template <typename E>
794auto
796 self_type tmp{*this};
797 ++*this;
798 return tmp;
799}
800
801template <typename E>
802auto
804 super_type::_item = super_type::_item->_name_link->_prev;
805 return *this;
806}
807
808template <typename E>
809auto
811 self_type tmp;
812 ++*this;
813 return tmp;
814}
815
816template <typename E>
818bwformat(BufferWriter &w, bwf::Spec const &spec, Lexicon<E> const &lex) {
819 bool sep_p = false;
820 if (spec._type == 's' || spec._type == 'S') {
821 for (auto &&[value, name] : lex) {
822 if (sep_p) {
823 w.write(',');
824 }
825 bwformat(w, spec, name);
826 sep_p = true;
827 }
828 } else if (spec.has_numeric_type()) {
829 for (auto &&[value, name] : lex) {
830 if (sep_p) {
831 w.write(',');
832 }
833 bwformat(w, spec, unsigned(value));
834 sep_p = true;
835 }
836 } else {
837 for (auto &&[value, name] : lex) {
838 if (sep_p) {
839 w.write(',');
840 }
841 w.print("[{},{}]", name, unsigned(value));
842 sep_p = true;
843 }
844 }
845 return w;
846}
847
848}} // namespace swoc::SWOC_VERSION_NS
849
850namespace std {
851
852template <size_t IDX, typename E> class tuple_element<IDX, swoc::detail::lexicon_pair_type<E>> {
853 static_assert("swoc::Lexicon::Pair tuple index out of range");
854};
855
856template <typename E> class tuple_element<0, swoc::detail::lexicon_pair_type<E>> {
857public:
858 using type = E;
859};
860
861template <typename E> class tuple_element<1, swoc::detail::lexicon_pair_type<E>> {
862public:
863 using type = swoc::TextView;
864};
865
866template <size_t IDX, typename E>
867auto
868get(swoc::detail::lexicon_pair_type<E> const &p) -> typename std::tuple_element<IDX, swoc::detail::lexicon_pair_type<E>>::type {
869 if constexpr (IDX == 0) {
870 return p._value;
871 } else if constexpr (IDX == 1) {
872 return p._name;
873 }
874}
875
876} // namespace std
std::string what(std::string_view const &fmt, Args &&...args)
Definition Lexicon.h:37
BufferWriter & print(const TextView &fmt, Args &&...args)
Definition bwf_base.h:927
virtual BufferWriter & write(char c)=0
bool operator!=(self_type const &that) const
Inequality.
Definition Lexicon.h:752
bool operator==(self_type const &that) const
Equality.
Definition Lexicon.h:746
value_type * pointer
Pointer to iteration value.
Definition Lexicon.h:263
value_type & reference
Reference to iteration value.
Definition Lexicon.h:264
reference operator*() const
Dereference.
Definition Lexicon.h:734
ptrdiff_t difference_type
Type of difference between iterators.
Definition Lexicon.h:265
std::bidirectional_iterator_tag iterator_category
Definition Lexicon.h:266
base_iterator()=default
Default constructor (invalid iterator)
const Item * _item
Current location in the container.
Definition Lexicon.h:281
const Pair value_type
Iteration value.
Definition Lexicon.h:262
pointer operator->() const
Dereference.
Definition Lexicon.h:740
self_type & operator=(self_type const &that)=default
Assignment.
name_iterator(self_type &&that)=default
Move constructor.
friend Lexicon
Internal constructor.
Definition Lexicon.h:360
name_iterator()=default
Default constructor.
self_type & operator--()
Decrement.
Definition Lexicon.h:803
name_iterator(self_type const &that)=default
Copy constructor.
self_type & operator++()
Increment.
Definition Lexicon.h:788
self_type & operator=(self_type const &that)=default
Assignment.
self_type & operator--()
Decrement.
Definition Lexicon.h:773
self_type & operator++()
Increment.
Definition Lexicon.h:758
value_iterator(self_type &&that)=default
Move constructor.
friend Lexicon
Internal constructor.
Definition Lexicon.h:324
value_iterator()=default
Default constructor.
value_iterator(self_type const &that)=default
Copy constructor.
std::function< E(TextView)> UnknownNameHandler
Definition Lexicon.h:122
std::variant< std::monostate, E, UnknownNameHandler > ValueDefault
Handle providing a default value.
Definition Lexicon.h:422
detail::lexicon_pair_type< E > Pair
Definition Lexicon.h:97
IntrusiveHashMap< typename Item::NameLinkage > _by_name
Access by name.
Definition Lexicon.h:516
TextView operator[](E const &value) const
Definition Lexicon.h:634
self_type & define(E value, Args &&...names)
TextView localize(TextView const &name)
Copy name in to local storage.
Definition Lexicon.h:626
std::function< TextView(E)> UnknownValueHandler
Definition Lexicon.h:114
const_iterator end() const
Iteration end.
Definition Lexicon.h:726
ByNameHelper by_names() const
Definition Lexicon.h:414
std::variant< std::monostate, std::string_view, UnknownValueHandler > NameDefault
Handle providing a default name.
Definition Lexicon.h:420
name_iterator end_names() const
Iteration over names - every value/name pair.
Definition Lexicon.h:382
const_iterator iterator
Definition Lexicon.h:367
size_t count() const
Get the number of values with definitions.
Definition Lexicon.h:714
NameDefault _name_default
Name to return if no value not found.
Definition Lexicon.h:519
value_iterator const_iterator
Iterator over values (each with a primary name).
Definition Lexicon.h:364
MemArena _arena
Storage for names.
Definition Lexicon.h:514
name_iterator begin_names() const
Iteration over names - every value/name pair.
Definition Lexicon.h:377
Lexicon()
Construct empty instance.
Definition Lexicon.h:596
IntrusiveHashMap< typename Item::ValueLinkage > _by_value
Access by value.
Definition Lexicon.h:518
static constexpr auto NAME_IDX
Index in Pair for name.
Definition Lexicon.h:103
ValueDefault _value_default
Value to return if name not found.
Definition Lexicon.h:520
self_type & set_default(Default const &handler)
Definition Lexicon.h:692
std::variant< std::monostate, E, TextView, UnknownNameHandler, UnknownValueHandler > Default
Definition Lexicon.h:128
const_iterator begin() const
Iteration begin.
Definition Lexicon.h:720
static constexpr auto VALUE_IDX
Index in Pair for the enumeration value.
Definition Lexicon.h:101
STL namespace.
For template deduction guides.
Definition ArenaWriter.cc:9
size_t Lexicon_Hash(E e)
Definition Lexicon.h:61
BufferWriter & bwformat(BufferWriter &w, bwf::Spec const &spec, std::string_view sv)
Definition bw_format.cc:649
std::string & bwprint_v(std::string &s, TextView fmt, std::tuple< Args... > const &args)
Definition bwf_base.h:1156
TransformView< X, V > transform_view_of(X const &xf, V const &src)
Definition TextView.h:1933
int strcasecmp(const std::string_view &lhs, const std::string_view &rhs)
std::initializer_list< TextView > const & names
Primary then secondary names.
Definition Lexicon.h:134
const E & value
Value for definition.
Definition Lexicon.h:133
Pair _payload
Enumeration and name.
Definition Lexicon.h:481
Item(E value, TextView name)
Definition Lexicon.h:529
Visitor functor for handling NameDefault.
Definition Lexicon.h:425
std::string_view operator()(TextView const &name) const
Visitor - literal string.
Definition Lexicon.h:436
E _value
Value to use for default.
Definition Lexicon.h:426
std::string_view operator()(std::monostate const &) const
Visitor - invalid value type.
Definition Lexicon.h:430
std::string_view operator()(UnknownValueHandler const &handler) const
Visitor - string generator.
Definition Lexicon.h:442
Visitor functor for handling ValueDefault.
Definition Lexicon.h:448
E operator()(E const &value) const
Visitor - value.
Definition Lexicon.h:459
E operator()(std::monostate const &) const
Vistor - invalid value.
Definition Lexicon.h:453
E operator()(UnknownNameHandler const &handler) const
Visitor - value generator.
Definition Lexicon.h:465
std::string_view _name
Name of visited pair.
Definition Lexicon.h:449
char _type
Type / radix indicator.
Definition bwf_base.h:69
bool has_numeric_type() const
Check if the type in this is numeric.
Definition bwf_base.h:507
lexicon_pair_type(E value, TextView name)
Definition Lexicon.h:52