1 /*
2 * nghttp2 - HTTP/2 C Library
3 *
4 * Copyright (c) 2015 Tatsuhiro Tsujikawa
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #ifndef TEMPLATE_H
26 #define TEMPLATE_H
27
28 #include "nghttp2_config.h"
29
30 #include <cstring>
31 #include <cstdio>
32 #include <cstdlib>
33 #include <memory>
34 #include <array>
35 #include <functional>
36 #include <typeinfo>
37 #include <algorithm>
38 #include <ostream>
39 #include <utility>
40 #include <span>
41 #include <string_view>
42
43 namespace nghttp2 {
44
array_size(T (&)[N])45 template <typename T, size_t N> constexpr size_t array_size(T (&)[N]) {
46 return N;
47 }
48
str_size(T (&)[N])49 template <typename T, size_t N> constexpr size_t str_size(T (&)[N]) {
50 return N - 1;
51 }
52
53 // inspired by <http://blog.korfuri.fr/post/go-defer-in-cpp/>, but our
54 // template can take functions returning other than void.
55 template <typename F, typename... T> struct Defer {
DeferDefer56 Defer(F &&f, T &&...t)
57 : f(std::bind(std::forward<F>(f), std::forward<T>(t)...)) {}
DeferDefer58 Defer(Defer &&o) noexcept : f(std::move(o.f)) {}
~DeferDefer59 ~Defer() { f(); }
60
61 using ResultType = std::invoke_result_t<F, T...>;
62 std::function<ResultType()> f;
63 };
64
defer(F && f,T &&...t)65 template <typename F, typename... T> Defer<F, T...> defer(F &&f, T &&...t) {
66 return Defer<F, T...>(std::forward<F>(f), std::forward<T>(t)...);
67 }
68
test_flags(T t,F flags)69 template <typename T, typename F> bool test_flags(T t, F flags) {
70 return (t & flags) == flags;
71 }
72
73 // doubly linked list of element T*. T must have field T *dlprev and
74 // T *dlnext, which point to previous element and next element in the
75 // list respectively.
76 template <typename T> struct DList {
DListDList77 DList() : head(nullptr), tail(nullptr), len(0) {}
78
79 DList(const DList &) = delete;
80 DList &operator=(const DList &) = delete;
81
DListDList82 DList(DList &&other) noexcept
83 : head{std::exchange(other.head, nullptr)},
84 tail{std::exchange(other.tail, nullptr)},
85 len{std::exchange(other.len, 0)} {}
86
87 DList &operator=(DList &&other) noexcept {
88 if (this == &other) {
89 return *this;
90 }
91 head = std::exchange(other.head, nullptr);
92 tail = std::exchange(other.tail, nullptr);
93 len = std::exchange(other.len, 0);
94
95 return *this;
96 }
97
appendDList98 void append(T *t) {
99 ++len;
100 if (tail) {
101 tail->dlnext = t;
102 t->dlprev = tail;
103 tail = t;
104 return;
105 }
106 head = tail = t;
107 }
108
removeDList109 void remove(T *t) {
110 --len;
111 auto p = t->dlprev;
112 auto n = t->dlnext;
113 if (p) {
114 p->dlnext = n;
115 }
116 if (head == t) {
117 head = n;
118 }
119 if (n) {
120 n->dlprev = p;
121 }
122 if (tail == t) {
123 tail = p;
124 }
125 t->dlprev = t->dlnext = nullptr;
126 }
127
emptyDList128 bool empty() const { return head == nullptr; }
129
sizeDList130 size_t size() const { return len; }
131
132 T *head, *tail;
133 size_t len;
134 };
135
dlist_delete_all(DList<T> & dl)136 template <typename T> void dlist_delete_all(DList<T> &dl) {
137 for (auto e = dl.head; e;) {
138 auto next = e->dlnext;
139 delete e;
140 e = next;
141 }
142 }
143
144 // User-defined literals for K, M, and G (powers of 1024)
145
146 constexpr unsigned long long operator"" _k(unsigned long long k) {
147 return k * 1024;
148 }
149
150 constexpr unsigned long long operator"" _m(unsigned long long m) {
151 return m * 1024 * 1024;
152 }
153
154 constexpr unsigned long long operator"" _g(unsigned long long g) {
155 return g * 1024 * 1024 * 1024;
156 }
157
158 // User-defined literals for time, converted into double in seconds
159
160 // hours
161 constexpr double operator"" _h(unsigned long long h) { return h * 60 * 60; }
162
163 // minutes
164 constexpr double operator"" _min(unsigned long long min) { return min * 60; }
165
166 // seconds
167 constexpr double operator"" _s(unsigned long long s) { return s; }
168
169 // milliseconds
170 constexpr double operator"" _ms(unsigned long long ms) { return ms / 1000.; }
171
172 // Returns a copy of NULL-terminated string [first, last).
173 template <typename InputIt>
strcopy(InputIt first,InputIt last)174 std::unique_ptr<char[]> strcopy(InputIt first, InputIt last) {
175 auto res = std::make_unique<char[]>(last - first + 1);
176 *std::copy(first, last, res.get()) = '\0';
177 return res;
178 }
179
180 // Returns a copy of NULL-terminated string |val|.
strcopy(const char * val)181 inline std::unique_ptr<char[]> strcopy(const char *val) {
182 return strcopy(val, val + strlen(val));
183 }
184
strcopy(const char * val,size_t n)185 inline std::unique_ptr<char[]> strcopy(const char *val, size_t n) {
186 return strcopy(val, val + n);
187 }
188
189 // Returns a copy of val.c_str().
strcopy(const std::string & val)190 inline std::unique_ptr<char[]> strcopy(const std::string &val) {
191 return strcopy(std::begin(val), std::end(val));
192 }
193
strcopy(const std::unique_ptr<char[]> & val)194 inline std::unique_ptr<char[]> strcopy(const std::unique_ptr<char[]> &val) {
195 if (!val) {
196 return nullptr;
197 }
198 return strcopy(val.get());
199 }
200
strcopy(const std::unique_ptr<char[]> & val,size_t n)201 inline std::unique_ptr<char[]> strcopy(const std::unique_ptr<char[]> &val,
202 size_t n) {
203 if (!val) {
204 return nullptr;
205 }
206 return strcopy(val.get(), val.get() + n);
207 }
208
209 // ImmutableString represents string that is immutable unlike
210 // std::string. It has c_str() and size() functions to mimic
211 // std::string. It manages buffer by itself. Just like std::string,
212 // c_str() returns NULL-terminated string, but NULL character may
213 // appear before the final terminal NULL.
214 class ImmutableString {
215 public:
216 using traits_type = std::char_traits<char>;
217 using value_type = traits_type::char_type;
218 using allocator_type = std::allocator<char>;
219 using size_type = std::allocator_traits<allocator_type>::size_type;
220 using difference_type =
221 std::allocator_traits<allocator_type>::difference_type;
222 using const_reference = const value_type &;
223 using const_pointer = const value_type *;
224 using const_iterator = const_pointer;
225 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
226
ImmutableString()227 constexpr ImmutableString() : len(0), base("") {}
ImmutableString(const char * s,size_t slen)228 constexpr ImmutableString(const char *s, size_t slen)
229 : len(slen), base(copystr(s, s + len)) {}
ImmutableString(const char * s)230 constexpr explicit ImmutableString(const char *s)
231 : len(traits_type::length(s)), base(copystr(s, s + len)) {}
ImmutableString(const std::string & s)232 constexpr explicit ImmutableString(const std::string &s)
233 : len(s.size()), base(copystr(std::begin(s), std::end(s))) {}
234 template <typename InputIt>
ImmutableString(InputIt first,InputIt last)235 constexpr ImmutableString(InputIt first, InputIt last)
236 : len(std::distance(first, last)), base(copystr(first, last)) {}
ImmutableString(const ImmutableString & other)237 constexpr ImmutableString(const ImmutableString &other)
238 : len(other.len), base(copystr(std::begin(other), std::end(other))) {}
ImmutableString(ImmutableString && other)239 constexpr ImmutableString(ImmutableString &&other) noexcept
240 : len{std::exchange(other.len, 0)}, base{std::exchange(other.base, "")} {}
~ImmutableString()241 constexpr ~ImmutableString() {
242 if (len) {
243 delete[] base;
244 }
245 }
246
247 constexpr ImmutableString &operator=(const ImmutableString &other) {
248 if (this == &other) {
249 return *this;
250 }
251 if (len) {
252 delete[] base;
253 }
254 len = other.len;
255 base = copystr(std::begin(other), std::end(other));
256 return *this;
257 }
258 constexpr ImmutableString &operator=(ImmutableString &&other) noexcept {
259 if (this == &other) {
260 return *this;
261 }
262 if (len) {
263 delete[] base;
264 }
265 len = std::exchange(other.len, 0);
266 base = std::exchange(other.base, "");
267 return *this;
268 }
269
270 template <size_t N>
from_lit(const char (& s)[N])271 static constexpr ImmutableString from_lit(const char (&s)[N]) {
272 return ImmutableString(s, N - 1);
273 }
274
begin()275 constexpr const_iterator begin() const noexcept { return base; }
cbegin()276 constexpr const_iterator cbegin() const noexcept { return base; }
277
end()278 constexpr const_iterator end() const noexcept { return base + len; }
cend()279 constexpr const_iterator cend() const noexcept { return base + len; }
280
rbegin()281 constexpr const_reverse_iterator rbegin() const noexcept {
282 return const_reverse_iterator{base + len};
283 }
crbegin()284 constexpr const_reverse_iterator crbegin() const noexcept {
285 return const_reverse_iterator{base + len};
286 }
287
rend()288 constexpr const_reverse_iterator rend() const noexcept {
289 return const_reverse_iterator{base};
290 }
crend()291 constexpr const_reverse_iterator crend() const noexcept {
292 return const_reverse_iterator{base};
293 }
294
c_str()295 constexpr const char *c_str() const noexcept { return base; }
size()296 constexpr size_type size() const noexcept { return len; }
empty()297 constexpr bool empty() const noexcept { return len == 0; }
298 constexpr const_reference operator[](size_type pos) const noexcept {
299 return *(base + pos);
300 }
301
302 private:
303 template <typename InputIt>
copystr(InputIt first,InputIt last)304 constexpr const char *copystr(InputIt first, InputIt last) {
305 if (first == last) {
306 return "";
307 }
308 auto res = new char[std::distance(first, last) + 1];
309 *std::copy(first, last, res) = '\0';
310 return res;
311 }
312
313 size_type len;
314 const char *base;
315 };
316
317 inline constexpr bool operator==(const ImmutableString &lhs,
318 const ImmutableString &rhs) {
319 return lhs.size() == rhs.size() &&
320 std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
321 }
322
323 inline constexpr bool operator==(const ImmutableString &lhs,
324 const std::string &rhs) {
325 return lhs.size() == rhs.size() &&
326 std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
327 }
328
329 inline constexpr bool operator==(const ImmutableString &lhs, const char *rhs) {
330 return lhs.size() == std::char_traits<char>::length(rhs) &&
331 std::equal(std::begin(lhs), std::end(lhs), rhs);
332 }
333
334 inline std::ostream &operator<<(std::ostream &o, const ImmutableString &s) {
335 return o.write(s.c_str(), s.size());
336 }
337
338 inline std::string &operator+=(std::string &lhs, const ImmutableString &rhs) {
339 lhs.append(rhs.c_str(), rhs.size());
340 return lhs;
341 }
342
343 // StringRef is a reference to a string owned by something else. So
344 // it behaves like simple string, but it does not own pointer. When
345 // it is default constructed, it has empty string. You can freely
346 // copy or move around this struct, but never free its pointer.
347 class StringRef {
348 public:
349 using traits_type = std::char_traits<char>;
350 using value_type = traits_type::char_type;
351 using allocator_type = std::allocator<char>;
352 using size_type = std::allocator_traits<allocator_type>::size_type;
353 using difference_type =
354 std::allocator_traits<allocator_type>::difference_type;
355 using const_reference = const value_type &;
356 using const_pointer = const value_type *;
357 using const_iterator = const_pointer;
358 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
359
StringRef()360 constexpr StringRef() noexcept : base(""), len(0) {}
361 constexpr StringRef(const StringRef &other) noexcept = default;
362 constexpr StringRef(std::nullptr_t) = delete;
StringRef(const std::string & s)363 constexpr StringRef(const std::string &s) : base(s.c_str()), len(s.size()) {}
StringRef(const std::string_view & s)364 constexpr explicit StringRef(const std::string_view &s)
365 : base(s.data()), len(s.size()) {}
StringRef(const ImmutableString & s)366 constexpr explicit StringRef(const ImmutableString &s)
367 : base(s.c_str()), len(s.size()) {}
StringRef(const char * s)368 constexpr StringRef(const char *s) : base(s), len(traits_type::length(s)) {}
StringRef(const char * s,size_t n)369 constexpr StringRef(const char *s, size_t n) : base(s), len(n) {}
StringRef(const uint8_t * s,size_t n)370 explicit StringRef(const uint8_t *s, size_t n)
371 : base(reinterpret_cast<const char *>(s)), len(n) {}
372 template <std::contiguous_iterator InputIt,
373 typename = std::enable_if_t<
374 std::is_same_v<std::iter_value_t<InputIt>, char>>>
StringRef(InputIt first,InputIt last)375 constexpr StringRef(InputIt first, InputIt last)
376 : base(std::to_address(first)), len(std::distance(first, last)) {}
StringRef(std::span<const char> s)377 constexpr StringRef(std::span<const char> s)
378 : base(s.data()), len(s.size_bytes()) {}
StringRef(std::span<const uint8_t> s)379 explicit StringRef(std::span<const uint8_t> s)
380 : base(reinterpret_cast<const char *>(s.data())), len(s.size_bytes()) {}
from_maybe_nullptr(const char * s)381 static constexpr StringRef from_maybe_nullptr(const char *s) noexcept {
382 if (s == nullptr) {
383 return StringRef();
384 }
385
386 return StringRef(s);
387 }
388
389 constexpr StringRef &operator=(const StringRef &other) noexcept = default;
390
begin()391 constexpr const_iterator begin() const noexcept { return base; }
cbegin()392 constexpr const_iterator cbegin() const noexcept { return base; }
393
end()394 constexpr const_iterator end() const noexcept { return base + len; }
cend()395 constexpr const_iterator cend() const noexcept { return base + len; }
396
rbegin()397 constexpr const_reverse_iterator rbegin() const noexcept {
398 return const_reverse_iterator{base + len};
399 }
crbegin()400 constexpr const_reverse_iterator crbegin() const noexcept {
401 return const_reverse_iterator{base + len};
402 }
403
rend()404 constexpr const_reverse_iterator rend() const noexcept {
405 return const_reverse_iterator{base};
406 }
crend()407 constexpr const_reverse_iterator crend() const noexcept {
408 return const_reverse_iterator{base};
409 }
410
data()411 constexpr const_pointer data() const noexcept { return base; }
size()412 constexpr size_type size() const noexcept { return len; }
empty()413 [[nodiscard]] constexpr bool empty() const noexcept { return len == 0; }
414 constexpr const_reference operator[](size_type pos) const {
415 return *(base + pos);
416 }
417
byte()418 const uint8_t *byte() const {
419 return reinterpret_cast<const uint8_t *>(base);
420 }
421
string_view()422 constexpr operator std::string_view() const noexcept { return {base, len}; }
423
424 static constexpr size_type npos = size_type(-1);
425
426 constexpr StringRef substr(size_type pos = 0, size_type count = npos) const {
427 return {base + pos, std::min(count, len - pos)};
428 }
429
430 private:
431 const char *base;
432 size_type len;
433 };
434
435 inline constexpr bool operator==(const StringRef &lhs,
436 const StringRef &rhs) noexcept {
437 return lhs.size() == rhs.size() &&
438 std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
439 }
440
441 inline constexpr bool operator==(const StringRef &lhs,
442 const ImmutableString &rhs) noexcept {
443 return lhs.size() == rhs.size() &&
444 std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
445 }
446
447 #if !defined(__APPLE__) && !defined(_LIBCPP_VERSION)
448 inline constexpr std::strong_ordering
449 operator<=>(const StringRef &lhs, const StringRef &rhs) noexcept {
450 return std::lexicographical_compare_three_way(std::begin(lhs), std::end(lhs),
451 std::begin(rhs), std::end(rhs));
452 }
453 #else // __APPLE__ || _LIBCPP_VERSION
454 inline constexpr bool operator<(const StringRef &lhs,
455 const StringRef &rhs) noexcept {
456 return std::lexicographical_compare(std::begin(lhs), std::end(lhs),
457 std::begin(rhs), std::end(rhs));
458 }
459 #endif // __APPLE__ || _LIBCPP_VERSION
460
461 inline std::ostream &operator<<(std::ostream &o, const StringRef &s) {
462 return o.write(s.data(), s.size());
463 }
464
465 inline std::string &operator+=(std::string &lhs, const StringRef &rhs) {
466 lhs.append(rhs.data(), rhs.size());
467 return lhs;
468 }
469
470 constexpr StringRef operator""_sr(const char *str, size_t len) noexcept {
471 return {str, len};
472 }
473
474 template <typename T, std::size_t N>
475 [[nodiscard]] std::span<
476 const uint8_t, N == std::dynamic_extent ? std::dynamic_extent : N * sizeof(T)>
as_uint8_span(std::span<T,N> s)477 as_uint8_span(std::span<T, N> s) noexcept {
478 return std::span < const uint8_t,
479 N == std::dynamic_extent
480 ? std::dynamic_extent
481 : N * sizeof(T) >
482 {reinterpret_cast<const uint8_t *>(s.data()), s.size_bytes()};
483 }
484
run_app(std::function<int (int,char **)> app,int argc,char ** argv)485 inline int run_app(std::function<int(int, char **)> app, int argc,
486 char **argv) {
487 try {
488 return app(argc, argv);
489 } catch (const std::bad_alloc &) {
490 fputs("Out of memory\n", stderr);
491 } catch (const std::exception &x) {
492 fprintf(stderr, "Caught %s:\n%s\n", typeid(x).name(), x.what());
493 } catch (...) {
494 fputs("Unknown exception caught\n", stderr);
495 }
496 return EXIT_FAILURE;
497 }
498
499 } // namespace nghttp2
500
501 namespace std {
502 template <> struct hash<nghttp2::StringRef> {
503 std::size_t operator()(const nghttp2::StringRef &s) const noexcept {
504 // 32 bit FNV-1a:
505 // https://tools.ietf.org/html/draft-eastlake-fnv-16#section-6.1.1
506 uint32_t h = 2166136261u;
507 for (auto c : s) {
508 h ^= static_cast<uint8_t>(c);
509 h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24);
510 }
511 return h;
512 }
513 };
514 } // namespace std
515
516 #endif // TEMPLATE_H
517