Spicy
id-base.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <algorithm>
6 #include <initializer_list>
7 #include <string>
8 #include <utility>
9 #include <vector>
10 
11 #include <hilti/base/util.h>
12 
13 namespace hilti::detail {
14 
15 using normalizer_func = std::string (*)(std::string);
16 inline std::string identity_normalizer(std::string s) { return s; }
17 
27 template<class Derived, normalizer_func N = identity_normalizer>
28 class IDBase {
29 public:
30  IDBase() = default;
31  IDBase(const char* s) : _id(N(s)) {}
32  explicit IDBase(std::string s) : _id(N(std::move(s))) {}
33 
35  struct AlreadyNormalized {};
36  IDBase(std::string id, AlreadyNormalized /*unused*/) : _id(std::move(id)) {}
37 
39  template<typename... T, typename enable = std::enable_if_t<(... && std::is_convertible_v<T, std::string>)>>
40  explicit IDBase(const T&... s) : _id((util::join<std::string>({N(s)...}, "::"))) {}
41 
43  IDBase(std::initializer_list<std::string> x)
44  : _id(util::join(util::transform(std::vector(std::move(x)), [](auto i) { return N(i); }), "::")) {}
45 
47  const auto& str() const { return _id; }
48 
50  Derived namespace_() const { return Derived(util::rsplit1(_id, "::").first, AlreadyNormalized()); }
51 
53  Derived local() const { return Derived(util::rsplit1(_id, "::").second, AlreadyNormalized()); }
54 
56  bool empty() const { return _id.empty(); }
57 
59  auto length() const { return util::split(_id, "::").size(); }
60 
68  Derived sub(int i) const {
69  auto x = util::split(_id, "::");
70 
71  if ( i < 0 )
72  i = x.size() + i;
73 
74  return Derived(i >= 0 && static_cast<size_t>(i) < x.size() ? x[i] : "", AlreadyNormalized());
75  }
76 
84  Derived sub(int from, int to) const {
85  return Derived(util::join(util::slice(util::split(_id, "::"), from, to), "::"), AlreadyNormalized());
86  }
87 
94  Derived firstN(int n) const { return Derived(sub(0, -1 - n), AlreadyNormalized()); }
95 
102  Derived lastN(int n) const { return Derived(sub(-1 - n, -1), AlreadyNormalized()); }
103 
110  Derived relativeTo(const Derived& root) const {
111  if ( _id == root._id )
112  return Derived();
113 
114  if ( ! util::startsWith(_id, root._id + "::") )
115  return Derived(root + _id, AlreadyNormalized());
116 
117  return Derived(_id.substr(root._id.size() + 2), AlreadyNormalized());
118  }
119 
121  Derived operator+(const std::string& other) const {
122  Derived n(_id, AlreadyNormalized());
123  n += N(other);
124  return n;
125  }
126 
128  Derived operator+(const Derived& other) const {
129  Derived n(_id, AlreadyNormalized());
130  n += other;
131  return n;
132  }
133 
135  Derived& operator+=(std::string other) {
136  if ( ! other.empty() ) {
137  if ( _id.empty() )
138  _id = N(std::move(other));
139  else
140  _id += "::" + N(std::move(other));
141  }
142 
143  return static_cast<Derived&>(*this);
144  }
145 
147  Derived& operator+=(const Derived& other) {
148  if ( ! other._id.empty() ) {
149  if ( other._id.empty() )
150  _id = other._id;
151  else
152  _id += "::" + other._id;
153  }
154 
155  return static_cast<Derived&>(*this);
156  }
157 
158  bool operator==(const Derived& other) const { return _id == other._id; };
159  bool operator!=(const Derived& other) const { return _id != other._id; };
160  bool operator==(const std::string& other) const { return _id == N(other); }
161  bool operator!=(const std::string& other) const { return _id != N(other); }
162  bool operator<(const Derived& other) const { return _id < other._id; };
163 
164  explicit operator bool() const { return ! empty(); }
165  operator std::string() const { return _id; }
166 
167 private:
168  std::string _id;
169 };
170 
171 } // namespace hilti::detail
Derived & operator+=(const Derived &other)
Definition: id-base.h:147
std::pair< std::string, std::string > rsplit1(std::string s, const std::string &delim=" ")
Definition: util.cc:61
IDBase(std::initializer_list< std::string > x)
Definition: id-base.h:43
Definition: optional.h:79
Derived relativeTo(const Derived &root) const
Definition: id-base.h:110
IDBase(const T &... s)
Definition: id-base.h:40
auto length() const
Definition: id-base.h:59
std::vector< std::string > split(std::string s, const std::string &delim=" ")
Definition: util.cc:34
Derived firstN(int n) const
Definition: id-base.h:94
Derived lastN(int n) const
Definition: id-base.h:102
Derived operator+(const Derived &other) const
Definition: id-base.h:128
Derived sub(int from, int to) const
Definition: id-base.h:84
bool startsWith(const std::string &s, const std::string &prefix)
Definition: util.h:285
std::string join(const T &l, const std::string &delim="")
Definition: util.h:181
Derived namespace_() const
Definition: id-base.h:50
Derived local() const
Definition: id-base.h:53
Derived operator+(const std::string &other) const
Definition: id-base.h:121
Definition: id-base.h:13
Derived sub(int i) const
Definition: id-base.h:68
Definition: id-base.h:28
const auto & str() const
Definition: id-base.h:47
bool empty() const
Definition: id-base.h:56
Derived & operator+=(std::string other)
Definition: id-base.h:135
std::vector< T > slice(const std::vector< T > &v, int begin, int end=-1)
Definition: util.h:154