1 /*
2  * This file is part of liblcf. Copyright (c) 2021 liblcf authors.
3  * https://github.com/EasyRPG/liblcf - https://easyrpg.org
4  *
5  * liblcf is Free/Libre Open Source Software, released under the MIT License.
6  * For the full copyright and license information, please view the COPYING
7  * file that was distributed with this source code.
8  */
9 
10 #ifndef LCF_ENUM_TAGS_H
11 #define LCF_ENUM_TAGS_H
12 
13 #include <type_traits>
14 #include <iterator>
15 #include <cstddef>
16 #include <array>
17 #include <cstring>
18 
19 namespace lcf {
20 
21 template <typename E, size_t N>
22 class EnumTags {
23 	public:
24 		static constexpr size_t num_tags = N;
25 		using int_type = typename std::make_signed<typename std::underlying_type<E>::type>::type;
26 		using iterator = char const * const *;
27 		using reverse_iterator = std::reverse_iterator<iterator>;
28 
29         template <size_t... LN>
EnumTags(const char (&...literals)[LN])30 		explicit constexpr EnumTags(const char (&...literals)[LN]) : _tags{{literals...}} {}
31 
tag(E etag)32 		constexpr const char* tag(E etag) const { return tag(int_type(etag)); }
tag(int_type idx)33 		constexpr const char* tag(int_type idx) const { return _tags[idx]; }
34 
35 		constexpr const char* operator[](E etag) const { return tag(etag); }
36 		constexpr const char* operator[](int_type idx) const { return tag(idx); }
37 
38 		bool etag(const char* tag, E& result) const;
39 		E etagOr(const char* tag, E other) const;
40 		int_type idx(const char* tag) const;
41 
tags()42 		const std::array<const char*, num_tags>& tags() const { return _tags; }
43 
begin()44 		constexpr iterator begin() const { return iterator(_tags.data()); }
end()45 		constexpr iterator end() const { return iterator(_tags.data() + size()); }
46 
cbegin()47 		constexpr iterator cbegin() const { return begin(); }
cend()48 		constexpr iterator cend() const { return end(); }
49 
rbegin()50 		reverse_iterator rbegin() const { return reverse_iterator(end()); }
rend()51 		reverse_iterator rend() const { return reverse_iterator(begin()); }
52 
size()53 		static constexpr size_t size() { return num_tags; }
54 
55 	private:
56 		const std::array<const char*, num_tags> _tags;
57 };
58 
59 template <typename E, size_t... N>
makeEnumTags(const char (&...literals)[N])60 constexpr EnumTags<E,sizeof...(N)> makeEnumTags(const char (&...literals)[N]) {
61 	return EnumTags<E,sizeof...(N)>(literals...);
62 }
63 
64 template <typename E, size_t N>
idx(const char * tag)65 inline typename EnumTags<E, N>::int_type EnumTags<E, N>::idx(const char* tag) const {
66 	for (size_t i = 0; i < _tags.size(); ++i) {
67 		if (std::strcmp(_tags[i], tag) == 0) {
68 			return i;
69 		}
70 	}
71 	return -1;
72 }
73 
74 template <typename E, size_t N>
etag(const char * tag,E & result)75 inline bool EnumTags<E, N>::etag(const char* tag, E& result) const {
76 	auto i = idx(tag);
77 	if (i < 0) {
78 		return false;
79 	}
80 	result = E(i);
81 	return true;
82 }
83 
84 template <typename E, size_t N>
etagOr(const char * tag,E other)85 inline E EnumTags<E, N>::etagOr(const char* tag, E other) const {
86 	auto i = idx(tag);
87 	return (i >= 0) ? E(i) : other;
88 }
89 
90 } //namespace lcf
91 
92 #endif
93