• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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