Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 1 | /* |
| 2 | * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>. |
||
| 3 | * It is copyright by its individual contributors, as recorded in the |
||
| 4 | * project's Git history. See COPYING.txt at the top level for license |
||
| 5 | * terms and a link to the Git history. |
||
| 6 | */ |
||
| 7 | |||
| 8 | #pragma once |
||
| 9 | |||
| 10 | #include <type_traits> |
||
| 11 | #include <utility> |
||
| 12 | #include "dxxsconf.h" |
||
| 13 | |||
| 14 | template <bool capture_source_location = false> |
||
| 15 | class location_wrapper |
||
| 16 | { |
||
| 17 | public: |
||
| 18 | location_wrapper() = default; |
||
| 19 | /* Allow callers to pass explicit file/line, for signature |
||
| 20 | * compatibility with `location_wrapper<true>`. |
||
| 21 | */ |
||
| 22 | location_wrapper(const char *, unsigned) |
||
| 23 | { |
||
| 24 | } |
||
| 25 | /* This must be a template to be compatible with the `scratch_buffer` |
||
| 26 | * template-typedef in `location_wrapper<true>`. |
||
| 27 | */ |
||
| 28 | template <std::size_t N> |
||
| 29 | using scratch_buffer = std::false_type; |
||
| 30 | template <std::size_t N> |
||
| 31 | static std::pair<char (&)[N], std::integral_constant<std::size_t, N>> insert_location_leader(char (&buffer)[N]) |
||
| 32 | { |
||
| 33 | return {buffer, {}}; |
||
| 34 | } |
||
| 35 | /* Define overloads to preserve const qualification */ |
||
| 36 | static std::pair<char *, std::size_t> prepare_buffer(scratch_buffer<0> &, char *const text, const std::size_t len) |
||
| 37 | { |
||
| 38 | return {text, len}; |
||
| 39 | } |
||
| 40 | static std::pair<const char *, std::size_t> prepare_buffer(scratch_buffer<0> &, const char *const text, const std::size_t len) |
||
| 41 | { |
||
| 42 | return {text, len}; |
||
| 43 | } |
||
| 44 | }; |
||
| 45 | |||
| 46 | #ifdef DXX_HAVE_CXX_BUILTIN_FILE_LINE |
||
| 47 | #include <cstdio> |
||
| 48 | |||
| 49 | template <> |
||
| 50 | class location_wrapper<true> |
||
| 51 | { |
||
| 52 | const char *file; |
||
| 53 | unsigned line; |
||
| 54 | public: |
||
| 55 | template <std::size_t N> |
||
| 56 | using scratch_buffer = char[N]; |
||
| 57 | location_wrapper(const char *const f = __builtin_FILE(), const unsigned l = __builtin_LINE()) : |
||
| 58 | file(f), line(l) |
||
| 59 | { |
||
| 60 | } |
||
| 61 | template <std::size_t N> |
||
| 62 | std::pair<char *, std::size_t> insert_location_leader(char (&buffer)[N]) const |
||
| 63 | { |
||
| 64 | const auto written = std::snprintf(buffer, sizeof(buffer), "%s:%u: ", file, line); |
||
| 65 | return {buffer + written, sizeof(buffer) - written}; |
||
| 66 | } |
||
| 67 | template <std::size_t N> |
||
| 68 | std::pair<const char *, std::size_t> prepare_buffer(char (&buffer)[N], const char *const text, const std::size_t len) const |
||
| 69 | { |
||
| 70 | const auto written = std::snprintf(buffer, sizeof(buffer), "%s:%u: %.*s", file, line, static_cast<int>(len), text); |
||
| 71 | return {buffer, len + written}; |
||
| 72 | } |
||
| 73 | /* Delegate to the const-qualified version, but return a `char *` to |
||
| 74 | * match the non-const input `char *`, to preserve the choice of |
||
| 75 | * overload for the function to receive this result. |
||
| 76 | */ |
||
| 77 | template <std::size_t N> |
||
| 78 | std::pair<char *, std::size_t> prepare_buffer(char (&buffer)[N], char *const text, const std::size_t len) const |
||
| 79 | { |
||
| 80 | return {buffer, prepare_buffer(buffer, const_cast<const char *>(text), len).second}; |
||
| 81 | } |
||
| 82 | }; |
||
| 83 | #endif |
||
| 84 | |||
| 85 | template <typename T, bool capture_source_location = false> |
||
| 86 | class location_value_wrapper : public location_wrapper<capture_source_location> |
||
| 87 | { |
||
| 88 | T value; |
||
| 89 | public: |
||
| 90 | /* Allow callers to pass explicit file/line, for signature |
||
| 91 | * compatibility with `location_value_wrapper<T, true>`. |
||
| 92 | */ |
||
| 93 | #ifndef DXX_HAVE_CXX_BUILTIN_FILE_LINE |
||
| 94 | location_value_wrapper(const T &v) : |
||
| 95 | value(v) |
||
| 96 | { |
||
| 97 | } |
||
| 98 | #endif |
||
| 99 | location_value_wrapper(const T &v, |
||
| 100 | const char *const f |
||
| 101 | #ifdef DXX_HAVE_CXX_BUILTIN_FILE_LINE |
||
| 102 | = __builtin_FILE() |
||
| 103 | #endif |
||
| 104 | , const unsigned l |
||
| 105 | #ifdef DXX_HAVE_CXX_BUILTIN_FILE_LINE |
||
| 106 | = __builtin_LINE() |
||
| 107 | #endif |
||
| 108 | ) : |
||
| 109 | location_wrapper<capture_source_location>(f, l), |
||
| 110 | value(v) |
||
| 111 | { |
||
| 112 | } |
||
| 113 | operator T() const |
||
| 114 | { |
||
| 115 | return value; |
||
| 116 | } |
||
| 117 | }; |