-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathswitch_str.hpp
94 lines (89 loc) · 2.89 KB
/
switch_str.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// switch_str
// C++17 O(1) switch for strings.
//
// Benefits and features:
// * O(1) cases matching.
// * Faster than `if-elseif-elseif-else`.
// * `break`, `continue`, `return`, `[[fallthrough]]` work as expected.
// * Compile-time errors for repetitive and unlisted cases.
//
// Example of usage:
// ```cpp
// #include <switch_str.hpp>
//
// void test(const std::string_view value) {
// switch_str(value,
// "ERR", "MSH", "OBR", "PID") {
// case_str("ERR"):
// ...
// break;
// case_str("MSH"):
// static_assert(switch_str_meta::cases().size() == 4);
// static_assert(switch_str_meta::cases()[1] == "MSH");
// break;
// case_str("PID"):
// ...
// break;
// case_str("PID"): // Repetition -> compile-time error.
// ...
// break;
// case_str("PV1"): // Unlisted -> compile-time error.
// ...
// break;
// default:
// ...
// break;
// }
// }
// ```
//
// Author: Yurii Blok
// License: BSL-1.0
// https://github.com/yurablok/switch-str
// History:
// v1.1 11-Apr-21 Check for unlisted is now implemented on `static_assert` instead of `case 0`.
// Added `switch_str_meta`.
// v1.0 05-Apr-21 Initial stable.
#pragma once
#include <array>
#include <string_view>
#include <unordered_map>
#ifndef switch_str
#define switch_str(STR, ...) \
switch ( \
struct switch_str_meta { \
static constexpr std::array<std::string_view, \
std::initializer_list<const char*>({ __VA_ARGS__ }).size()> cases() { \
return {{ __VA_ARGS__ }}; \
} \
}; \
[](const std::string_view str) -> uint32_t { \
static const auto m = []() { \
std::unordered_map<std::string_view, uint32_t> mm; \
mm.reserve(switch_str_meta::cases().size()); \
for (uint32_t i = 0; i < static_cast<uint32_t>(switch_str_meta::cases().size()); ++i) { \
mm[switch_str_meta::cases()[i]] = i; \
} \
return mm; \
}(); \
const auto it = m.find(str); \
if (it == m.end()) { \
return static_cast<uint32_t>(switch_str_meta::cases().size()); \
} \
return it->second; \
}(STR) \
)
#define case_str(STR) \
case []() constexpr -> uint32_t { \
constexpr uint32_t idx = []() constexpr -> uint32_t { \
for (uint32_t i = 0; i < static_cast<uint32_t>(switch_str_meta::cases().size()); ++i) { \
if (switch_str_meta::cases()[i] == STR) { \
return i; \
} \
} \
return static_cast<uint32_t>(switch_str_meta::cases().size()); \
}(); \
static_assert(idx != switch_str_meta::cases().size(), "unlisted case"); \
return idx; \
}()
#endif // switch_str