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 
10 #include <hilti/base/util.h>
11 
12 namespace hilti::detail {
13 
14 using normalizer_func = std::string (*)(std::string);
15 inline std::string identity_normalizer(std::string s) { return s; }
16 
26 template<class Derived, normalizer_func N = identity_normalizer>
27 class IDBase {
28 public:
29  IDBase() = default;
30  IDBase(const char* s) : _id(N(s)) {}
31  explicit IDBase(std::string s) : _id(N(std::move(s))) {}
32 
34  struct AlreadyNormalized {};
35  IDBase(std::string id, AlreadyNormalized /*unused*/) : _id(std::move(id)) {}
36 
38  template<typename... T, typename enable = std::enable_if_t<(... && std::is_convertible_v<T, std::string>)>>
39  explicit IDBase(const T&... s) : _id((util::join<std::string>({N(s)...}, "::"))) {}
40 
42  IDBase(const std::initializer_list<std::string>& x)
43  : _id(util::join(util::transform(x, [](auto i) { return N(i); }), "::")) {}
44 
46  const auto& str() const { return _id; }
47 
49  Derived namespace_() const { return Derived(util::rsplit1(_id, "::").first, AlreadyNormalized()); }
50 
52  Derived local() const { return Derived(util::rsplit1(_id, "::").second, AlreadyNormalized()); }
53 
55  bool empty() const { return _id.empty(); }
56 
64  Derived sub(int i) const {
65  auto x = util::split(_id, "::");
66 
67  if ( i < 0 )
68  i = x.size() + i;
69 
70  return Derived(i >= 0 && static_cast<size_t>(i) < x.size() ? x[i] : "", AlreadyNormalized());
71  }
72 
80  Derived sub(int from, int to) const {
81  return Derived(util::join(util::slice(util::split(_id, "::"), from, to), "::"), AlreadyNormalized());
82  }
83 
90  Derived firstN(int n) const { return Derived(sub(0, -1 - n), AlreadyNormalized()); }
91 
98  Derived lastN(int n) const { return Derived(sub(-1 - n, -1), AlreadyNormalized()); }
99 
106  Derived relativeTo(const Derived& root) const {
107  if ( _id == root._id )
108  return Derived();
109 
110  if ( ! util::startsWith(_id, root._id + "::") )
111  return Derived(root + _id, AlreadyNormalized());
112 
113  return Derived(_id.substr(root._id.size() + 2), AlreadyNormalized());
114  }
115 
117  Derived operator+(const std::string& other) const {
118  Derived n(_id, AlreadyNormalized());
119  n += N(other);
120  return n;
121  }
122 
124  Derived operator+(const Derived& other) const {
125  Derived n(_id, AlreadyNormalized());
126  n += other;
127  return n;
128  }
129 
131  Derived& operator+=(std::string other) {
132  if ( ! other.empty() ) {
133  if ( _id.empty() )
134  _id = N(std::move(other));
135  else
136  _id += "::" + N(std::move(other));
137  }
138 
139  return static_cast<Derived&>(*this);
140  }
141 
143  Derived& operator+=(const Derived& other) {
144  if ( ! other._id.empty() ) {
145  if ( other._id.empty() )
146  _id = other._id;
147  else
148  _id += "::" + other._id;
149  }
150 
151  return static_cast<Derived&>(*this);
152  }
153 
154  bool operator==(const Derived& other) const { return _id == other._id; };
155  bool operator!=(const Derived& other) const { return _id != other._id; };
156  bool operator==(const std::string& other) const { return _id == N(other); }
157  bool operator!=(const std::string& other) const { return _id != N(other); }
158  bool operator<(const Derived& other) const { return _id < other._id; };
159 
160  explicit operator bool() const { return ! empty(); }
161  operator std::string() const { return _id; }
162 
163 private:
164  std::string _id;
165 };
166 
167 } // namespace hilti::detail
Derived & operator+=(const Derived &other)
Definition: id-base.h:143
std::pair< std::string, std::string > rsplit1(std::string s, const std::string &delim=" ")
Definition: util.cc:62
IDBase(const std::initializer_list< std::string > &x)
Definition: id-base.h:42
Derived relativeTo(const Derived &root) const
Definition: id-base.h:106
IDBase(const T &... s)
Definition: id-base.h:39
std::vector< std::string > split(std::string s, const std::string &delim=" ")
Definition: util.cc:35
Derived firstN(int n) const
Definition: id-base.h:90
Derived lastN(int n) const
Definition: id-base.h:98
Derived operator+(const Derived &other) const
Definition: id-base.h:124
Derived sub(int from, int to) const
Definition: id-base.h:80
bool startsWith(const std::string &s, const std::string &prefix)
Definition: util.h:326
std::string join(const T &l, const std::string &delim="")
Definition: util.h:223
Derived namespace_() const
Definition: id-base.h:49
Derived local() const
Definition: id-base.h:52
Derived operator+(const std::string &other) const
Definition: id-base.h:117
Definition: id-base.h:12
Derived sub(int i) const
Definition: id-base.h:64
Definition: id-base.h:27
const auto & str() const
Definition: id-base.h:46
bool empty() const
Definition: id-base.h:55
Derived & operator+=(std::string other)
Definition: id-base.h:131
std::vector< T > slice(const std::vector< T > &v, int begin, int end=-1)
Definition: util.h:196