diff --git a/CMakeLists.txt b/CMakeLists.txt index 4800adb3..4c481245 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -338,7 +338,7 @@ list ( polynomial.hpp pool.cpp pool.hpp - preprocessor.hpp + "${CMAKE_CURRENT_SOURCE_DIR}/preprocessor.hpp" quaternion.cpp quaternion.hpp raii.hpp diff --git a/algo/sort.hpp b/algo/sort.hpp index 2e9b9258..dad2cbe9 100644 --- a/algo/sort.hpp +++ b/algo/sort.hpp @@ -19,6 +19,7 @@ #define CRUFT_UTIL_ALGO_SORT_HPP #include "../debug.hpp" +#include "../cast.hpp" #include #include @@ -88,7 +89,7 @@ namespace cruft::util::sort { CHECK_LT (*std::max_element (idx_first, idx_last), size); for (decltype(size) i = 0; i < size - 1; ++i) { - while (i != (decltype(size))idx_first[i]) { + while (i != decltype(size){idx_first[i]}) { auto j = idx_first[i]; detail::index_swap (i, j, value, tail..., idx_first); @@ -117,7 +118,7 @@ namespace cruft::util::sort { // assumptions about minimum array sizes and non-wrapping indices later on // this way. if (std::distance (key_first, key_last) <= 1) - return; + return; // generate a list of indices into the key array and sort them so we have, // in effect, a sorted list of pointers. @@ -125,28 +126,30 @@ namespace cruft::util::sort { std::vector indices (size); std::iota (std::begin (indices), std::end (indices), 0); - std::sort (std::begin (indices), + std::sort ( + std::begin (indices), std::end (indices), - [&] (const auto &cruft_util_sort_soa_a, const auto &cruft_util_sort_soa_b) - { - // GCC: we use the ridiculous parameter names to avoid a name aliasing - // bug/warning under gcc 6.3.0; if the client passes a comparator - // lambda that uses the same parameter names then a warning will be - // generated. given 'a' and 'b' aren't unlikely names we try to avoid - // them here. - return comp ( - key_first[cruft_util_sort_soa_a], - key_first[cruft_util_sort_soa_b] - ); - }); + [&] (const auto &cruft_util_sort_soa_a, const auto &cruft_util_sort_soa_b) + { + // GCC: we use the ridiculous parameter names to avoid a name aliasing + // bug/warning under gcc 6.3.0; if the client passes a comparator + // lambda that uses the same parameter names then a warning will be + // generated. given 'a' and 'b' aren't unlikely names we try to avoid + // them here. + return comp ( + key_first[cruft_util_sort_soa_a], + key_first[cruft_util_sort_soa_b] + ); + } + ); // convert from a sorted list of pointers to a mapping of pointers to // desired final offsets. this is done so we can palm it off to the // reorder function. // TODO: avoid the need for this inverse array. decltype (indices) dest (indices.size ()); - for (decltype(size) i = 0; i < (decltype(size))dest.size (); ++i) { - dest[indices[i]] = i; + for (decltype(size) i = 0; i < ::util::cast::sign (dest.size ()); ++i) { + dest[indices[i]] = i; } // reorder all the arrays using the mapping we have discovered. diff --git a/alloc/raw/null.cpp b/alloc/raw/null.cpp index 71a70aab..736bc4b8 100644 --- a/alloc/raw/null.cpp +++ b/alloc/raw/null.cpp @@ -61,8 +61,8 @@ null::deallocate (void *ptr, size_t bytes, size_t align) (void)bytes; (void)align; - // cast to void* to assist some of the printing machinary in the assertion - CHECK_EQ (ptr, (void*)nullptr); + // cast to void* to assist some of the printing machinery in the assertion + CHECK_EQ (ptr, static_cast (nullptr)); } diff --git a/coord/ops.hpp b/coord/ops.hpp index 8498f1e9..3ee60483 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -1332,6 +1332,33 @@ namespace util { } + template < + size_t S, + typename T, + typename K, + typename = std::enable_if_t< + is_coord_v && !is_coord_v + > + > + constexpr auto + select (vector s, K a, T b) + { + return select (s, a, K {b}); + } + + + template < + size_t S, + typename T, + typename = std::enable_if_t> + > + constexpr auto + select (vector s, T a, T b) + { + return select (s, vector {a}, vector {b}); + } + + /////////////////////////////////////////////////////////////////////////// // return the componentwise floor of the coordinate type // diff --git a/endian.hpp b/endian.hpp index e63d7ff9..2aa1ce7e 100644 --- a/endian.hpp +++ b/endian.hpp @@ -19,6 +19,7 @@ #include "types/bits.hpp" +#include #include #include @@ -90,6 +91,41 @@ namespace util { } + template < + typename T, + typename = std::enable_if_t< + std::is_integral_v + > + > + T readle (const void *_data) + { + auto data = reinterpret_cast (_data); + + T value = 0; + + for (size_t i = 0; i < sizeof (value); ++i) + value |= T{data[i]} << (i * 8); + + return value; + } + + + /// read bytes from a supplied data pointer and return an integer using + /// host endian layout. + template < + typename T, + typename = std::enable_if_t< + std::is_integral_v + > + > + T readhe (const std::uint8_t *data) + { + std::aligned_union_t buffer; + memcpy (reinterpret_cast (&buffer), data, sizeof (T)); + return *reinterpret_cast (&buffer); + } + + //------------------------------------------------------------------------- #if defined(WORDS_BIGENDIAN) template constexpr T hton (T v) { return v; } diff --git a/format.cpp.rl b/format.cpp.rl index 73a1312b..5dac5167 100644 --- a/format.cpp.rl +++ b/format.cpp.rl @@ -18,6 +18,10 @@ #include +// We generate some really old style C code via ragel here, so we have to +// disable some noisy warnings (doubly so given -Werror) +#pragma GCC diagnostic ignored "-Wold-style-cast" + namespace util::format { std::ostream& operator<< (std::ostream &os, type_t val) diff --git a/hash/fasthash.cpp b/hash/fasthash.cpp index 46e09270..cc42f1e0 100644 --- a/hash/fasthash.cpp +++ b/hash/fasthash.cpp @@ -16,6 +16,9 @@ #include "fasthash.hpp" +#include "../endian.hpp" +#include "../debug.hpp" + using util::hash::fasthash; @@ -28,20 +31,17 @@ fasthash::operator() (uint64_t seed, const util::view uint64_t result = seed ^ (data.size () * m); - auto cursor = reinterpret_cast (data.begin ()); - auto last = cursor + data.size () / sizeof (*cursor); - for (; cursor < last; ++cursor) { - result ^= mix (*cursor); + auto cursor = data.begin (); + for (auto last = data.end () - data.size () % 8; cursor < last; cursor += 8) { + result ^= mix (readle (cursor)); result *= m; } - size_t remain = data.size () % sizeof (*cursor); + size_t remain = data.size () % 8; if (remain) { - auto tail = reinterpret_cast (cursor); - uint64_t accum = 0; for (size_t i = 0; i < remain; ++i) - accum ^= uint64_t {tail[i]} << i * 8; + accum ^= uint64_t {cursor[i]} << i * 8; result ^= mix (accum); result *= m; diff --git a/hash/murmur/common.cpp b/hash/murmur/common.cpp index 101672bb..f03d44f3 100644 --- a/hash/murmur/common.cpp +++ b/hash/murmur/common.cpp @@ -114,22 +114,22 @@ namespace util::hash::murmur { switch(len & 15) { - case 15: result[1] |= ((uint64_t)bytes[14]) << 48; - case 14: result[1] |= ((uint64_t)bytes[13]) << 40; - case 13: result[1] |= ((uint64_t)bytes[12]) << 32; - case 12: result[1] |= ((uint64_t)bytes[11]) << 24; - case 11: result[1] |= ((uint64_t)bytes[10]) << 16; - case 10: result[1] |= ((uint64_t)bytes[ 9]) << 8; - case 9: result[1] |= ((uint64_t)bytes[ 8]) << 0; + case 15: result[1] |= uint64_t{bytes[14]} << 48; + case 14: result[1] |= uint64_t{bytes[13]} << 40; + case 13: result[1] |= uint64_t{bytes[12]} << 32; + case 12: result[1] |= uint64_t{bytes[11]} << 24; + case 11: result[1] |= uint64_t{bytes[10]} << 16; + case 10: result[1] |= uint64_t{bytes[ 9]} << 8; + case 9: result[1] |= uint64_t{bytes[ 8]} << 0; - case 8: result[0] |= ((uint64_t)bytes[ 7]) << 56; - case 7: result[0] |= ((uint64_t)bytes[ 6]) << 48; - case 6: result[0] |= ((uint64_t)bytes[ 5]) << 40; - case 5: result[0] |= ((uint64_t)bytes[ 4]) << 32; - case 4: result[0] |= ((uint64_t)bytes[ 3]) << 24; - case 3: result[0] |= ((uint64_t)bytes[ 2]) << 16; - case 2: result[0] |= ((uint64_t)bytes[ 1]) << 8; - case 1: result[0] |= ((uint64_t)bytes[ 0]) << 0; + case 8: result[0] |= uint64_t{bytes[ 7]} << 56; + case 7: result[0] |= uint64_t{bytes[ 6]} << 48; + case 6: result[0] |= uint64_t{bytes[ 5]} << 40; + case 5: result[0] |= uint64_t{bytes[ 4]} << 32; + case 4: result[0] |= uint64_t{bytes[ 3]} << 24; + case 3: result[0] |= uint64_t{bytes[ 2]} << 16; + case 2: result[0] |= uint64_t{bytes[ 1]} << 8; + case 1: result[0] |= uint64_t{bytes[ 0]} << 0; break; default: diff --git a/hash/murmur/murmur1.cpp b/hash/murmur/murmur1.cpp index 1719097e..d4770746 100644 --- a/hash/murmur/murmur1.cpp +++ b/hash/murmur/murmur1.cpp @@ -18,6 +18,7 @@ #include "common.hpp" #include "../../debug.hpp" +#include "../../endian.hpp" using util::hash::murmur1; @@ -30,14 +31,13 @@ murmur1::operator() (util::view data) const noexcept uint32_t h = m_seed ^ ((data.size () & 0xffffffff) * m); // mix the body - auto cursor = reinterpret_cast (data.data ()); - auto last = cursor + data.size () / sizeof (uint32_t); - for (; cursor < last; ++cursor) - h = mix (h, *cursor); + auto cursor = data.begin (); + for (auto last = data.end () - data.size () % sizeof (uint32_t); cursor < last; cursor += 4) + h = mix (h, util::readhe (cursor)); // mix the tail if (data.size () % sizeof (uint32_t)) - h = mix (h, murmur::tail (reinterpret_cast (cursor), data.size ())); + h = mix (h, murmur::tail (cursor, data.size ())); // finalise h *= m; h ^= h >> 10; diff --git a/hash/siphash.cpp b/hash/siphash.cpp index a15a21fb..d2cd1991 100644 --- a/hash/siphash.cpp +++ b/hash/siphash.cpp @@ -51,15 +51,6 @@ round (uint64_t v[4]) } -/////////////////////////////////////////////////////////////////////////////// -template -ValueT -readle (const void *ptr) -{ - return util::htol (*reinterpret_cast (ptr)); -} - - /////////////////////////////////////////////////////////////////////////////// template siphash::siphash (std::array _key) noexcept: diff --git a/io.cpp b/io.cpp index 71383615..a71d7fc7 100644 --- a/io.cpp +++ b/io.cpp @@ -53,7 +53,7 @@ util::slurp (const std::experimental::filesystem::path &path) std::vector buffer (size); CHECK_GE (size, 0); - size_t remaining = (size_t)size; + size_t remaining = util::cast::sign (size); T *cursor = buffer.data (); while (remaining) { @@ -61,10 +61,10 @@ util::slurp (const std::experimental::filesystem::path &path) ::read (out, cursor, remaining) ); - CHECK_GT ( consumed, 0); - CHECK_LE ((size_t)consumed, remaining); + CHECK_GT (consumed, 0); + CHECK_LE (util::cast::sign (consumed), remaining); - remaining -= (size_t)consumed; + remaining -= util::cast::sign (consumed); cursor += consumed; } diff --git a/io_posix.cpp b/io_posix.cpp index c3b4a46c..a3473d24 100644 --- a/io_posix.cpp +++ b/io_posix.cpp @@ -41,7 +41,7 @@ mapped_file::mapped_file (const ::util::posix::fd &src, int mflags) ::util::posix::error::try_value (fstat (src, &meta)); m_size = util::cast::sign (meta.st_size); - m_data = (uint8_t *)mmap (NULL, m_size, mflags, MAP_SHARED, src, 0); + m_data = static_cast (mmap (nullptr, m_size, mflags, MAP_SHARED, src, 0)); if (m_data == MAP_FAILED) ::util::posix::error::throw_code (); } diff --git a/job/queue.hpp b/job/queue.hpp index dde1817a..9f289709 100644 --- a/job/queue.hpp +++ b/job/queue.hpp @@ -179,7 +179,7 @@ namespace util::job { // GCC: switch to hardware_destructive_interference_size when it // becomes available in libstdc++. Until then we use a sensible // guess. - std::array data; + std::aligned_storage_t<64,alignof(std::max_align_t)> data; std::function function; thread::semaphore references = 0; diff --git a/json/flat.cpp.rl b/json/flat.cpp.rl index 8d03ff30..4884caed 100644 --- a/json/flat.cpp.rl +++ b/json/flat.cpp.rl @@ -26,7 +26,12 @@ #include #include -//----------------------------------------------------------------------------- +// We generate some really old style C code via ragel here, so we have to +// disable some noisy warnings (doubly so given -Werror) +#pragma GCC diagnostic ignored "-Wold-style-cast" + + +/////////////////////////////////////////////////////////////////////////////// %%{ # JSON (rfc7159) machine json; diff --git a/json/schema.cpp b/json/schema.cpp index 35da11dc..0d2cc46a 100644 --- a/json/schema.cpp +++ b/json/schema.cpp @@ -535,6 +535,6 @@ json::schema::validate (json::tree::node &data, const std::experimental::filesystem::path &schema_path) { const util::mapped_file schema_data (schema_path); - auto schema_object = json::tree::parse (util::view{schema_data}.cast ()); + auto schema_object = json::tree::parse (util::view(schema_data).cast ()); validate (data, schema_object->as_object ()); } diff --git a/maths.hpp b/maths.hpp index e2520728..8f30ff36 100644 --- a/maths.hpp +++ b/maths.hpp @@ -294,15 +294,14 @@ namespace util { ///---------------------------------------------------------------------------- /// round T up to the nearest power-of-2 - template - constexpr - std::enable_if_t< - std::is_integral::value, T + template < + typename T, + typename = std::enable_if_t> > + constexpr + auto round_pow2 (T value) { - using return_type = std::enable_if_t::value, T>; - --value; for (unsigned i = 1; i < sizeof (T) * 8; i <<= 1) { @@ -310,7 +309,7 @@ namespace util { } ++value; - return (return_type)value; + return value; } diff --git a/range.cpp b/range.cpp index 1246ac54..40b6ce95 100644 --- a/range.cpp +++ b/range.cpp @@ -20,6 +20,7 @@ #include "debug.hpp" #include "json/tree.hpp" #include "maths.hpp" +#include "random.hpp" #include #include @@ -123,31 +124,15 @@ util::range::operator- (T val) const /////////////////////////////////////////////////////////////////////////////// -namespace util { - template <> - double - range::random (void) const - { - double pos = ::rand () / (double)(RAND_MAX); - return (hi - lo) * pos + lo; - } - - template <> - float - range::random (void) const - { - float pos = ::rand () / (float)(RAND_MAX); - return (hi - lo) * pos + lo; - } -} - - -//----------------------------------------------------------------------------- template T util::range::random (void) const { - return lo + (T)::rand () % (hi - lo); + if constexpr (std::is_floating_point_v) { + return std::uniform_real_distribution (lo, hi) (util::random::generator ()); + } else { + return std::uniform_int_distribution (lo, hi) (util::random::generator ()); + } } diff --git a/test/algo/sort.cpp b/test/algo/sort.cpp index 78f7fdb5..ba9b48b6 100644 --- a/test/algo/sort.cpp +++ b/test/algo/sort.cpp @@ -6,7 +6,7 @@ void -reorder (std::vector &values, std::vector &indices) +reorder (std::vector &values, std::vector &indices) { CHECK_EQ (values.size (), indices.size ()); if (indices.size () <= 1) @@ -14,7 +14,7 @@ reorder (std::vector &values, std::vector &indices) for (size_t i = 0; i < indices.size () - 1; ++i) { // check if this item is in the correct slot - while ((int)i != indices[i]) { + while (i != indices[i]) { auto alt = indices[i]; // swap this item with the one that's occupying its intended slot diff --git a/test/alloc/aligned/direct.cpp b/test/alloc/aligned/direct.cpp index 92ab8b64..c937400d 100644 --- a/test/alloc/aligned/direct.cpp +++ b/test/alloc/aligned/direct.cpp @@ -29,10 +29,10 @@ main (int, char**) // alignment to produce a likely system alignment. eg, 3 + 5 == 8 which is // a power-of-2. uintptr_t result[4] = { - (uintptr_t)alloc.allocate (9), // just over a power of two - (uintptr_t)alloc.allocate (1), // a single byte - (uintptr_t)alloc.allocate (64), // a cache line - (uintptr_t)alloc.allocate (250) // multiple cache lines, but not a power of two + reinterpret_cast(alloc.allocate (9)), // just over a power of two + reinterpret_cast(alloc.allocate (1)), // a single byte + reinterpret_cast(alloc.allocate (64)), // a cache line + reinterpret_cast(alloc.allocate (250)) // multiple cache lines, but not a power of two }; tap.expect ( diff --git a/test/alloc/aligned/foreign.cpp b/test/alloc/aligned/foreign.cpp index 81fec629..16001f32 100644 --- a/test/alloc/aligned/foreign.cpp +++ b/test/alloc/aligned/foreign.cpp @@ -45,8 +45,8 @@ main () }; for (const auto &t: TESTS) { - auto ptr = (uintptr_t)alloc.allocate (t.size); - auto offset = ptr - (uintptr_t)base; + auto ptr = reinterpret_cast (alloc.allocate (t.size)); + auto offset = ptr - reinterpret_cast (base); tap.expect_mod (offset, alignment, "%s", t.message); } diff --git a/test/endian.cpp b/test/endian.cpp index d91f4ad2..d8c20e2c 100644 --- a/test/endian.cpp +++ b/test/endian.cpp @@ -2,6 +2,8 @@ #include "endian.hpp" +#include + /////////////////////////////////////////////////////////////////////////////// int @@ -14,6 +16,12 @@ main (void) tap.expect_eq (a, util::bswap (b), "u32 byteswap"); } + { + static std::uint8_t const bytes[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; + tap.expect_eq (util::readle (bytes), 0xefcdab8967452301, "readle"); + } + + { // try to byte swap the pattern for 1.0f // diff --git a/test/format.cpp b/test/format.cpp index 9b52154c..509d7e27 100644 --- a/test/format.cpp +++ b/test/format.cpp @@ -32,10 +32,10 @@ main (void) CHECK_RENDER ("%.i", "", 0); CHECK_RENDER ("% .i", " ", 0); // zero precision still requires a space - CHECK_RENDER ("%hhi", "1", (signed char)1); - CHECK_RENDER ("%hi", "1", (signed short)1); - CHECK_RENDER ("%li", "1", (signed long)1); - CHECK_RENDER ("%lli", "1", (signed long long)1); + CHECK_RENDER ("%hhi", "1", (signed char){1}); + CHECK_RENDER ("%hi", "1", (signed short){1}); + CHECK_RENDER ("%li", "1", (signed long){1}); + CHECK_RENDER ("%lli", "1", (signed long long){1}); CHECK_RENDER ("%ji", "1", intmax_t{1}); CHECK_RENDER ("%zi", "1", ssize_t{1}); CHECK_RENDER ("%ti", "1", ptrdiff_t{1}); @@ -48,10 +48,10 @@ main (void) CHECK_RENDER ("%-3u", "1 ", 1u); CHECK_RENDER ("%64u", " 1", 1u); - CHECK_RENDER ("%hhu", "1", (unsigned char)1); - CHECK_RENDER ("%hu", "1", (unsigned short)1); - CHECK_RENDER ("%lu", "1", (unsigned long)1); - CHECK_RENDER ("%llu", "1", (unsigned long long)1); + CHECK_RENDER ("%hhu", "1", (unsigned char){1}); + CHECK_RENDER ("%hu", "1", (unsigned short){1}); + CHECK_RENDER ("%lu", "1", (unsigned long){1}); + CHECK_RENDER ("%llu", "1", (unsigned long long){1}); CHECK_RENDER ("%ju", "1", uintmax_t{1}); CHECK_RENDER ("%zu", "0", size_t{0}); CHECK_RENDER ("%zu", "1", size_t{1}); @@ -142,12 +142,12 @@ main (void) CHECK_RENDER ("%!", "userobj", userobj {}); - CHECK_RENDER ("%p", "0x1234567", (void*)0x01234567); - CHECK_RENDER ("%p", "0x1234567", (int*)0x01234567); - CHECK_RENDER ("%p", "0x1234567", (char*)0x01234567); + CHECK_RENDER ("%p", "0x1234567", reinterpret_cast(0x01234567)); + CHECK_RENDER ("%p", "0x1234567", reinterpret_cast (0x01234567)); + CHECK_RENDER ("%p", "0x1234567", reinterpret_cast(0x01234567)); CHECK_RENDER ("%p", "(nil)", nullptr); CHECK_RENDER ("%p", "(nil)", NULL); - CHECK_RENDER ("%!", "0x1234567", (void*)0x01234567); + CHECK_RENDER ("%!", "0x1234567", reinterpret_cast(0x01234567)); CHECK_RENDER ("%%", "%"); CHECK_RENDER ("%10%", "%"); @@ -189,17 +189,17 @@ main (void) CHECK_THROW("%i", conversion_error, 1u); CHECK_THROW("%i", conversion_error, nullptr); - CHECK_THROW("%hhi", length_error, (long long)1); - CHECK_THROW("%lli", length_error, (signed char)1); + CHECK_THROW("%hhi", length_error, (long long){1}); + CHECK_THROW("%lli", length_error, (signed char){1}); CHECK_THROW("%u", conversion_error, 1.); CHECK_THROW("%u", conversion_error, "foo"); - CHECK_THROW("%u", conversion_error, (void*)0); + CHECK_THROW("%u", conversion_error, (void*){0}); CHECK_THROW("%u", conversion_error, 1); CHECK_THROW("%u", conversion_error, nullptr); - CHECK_THROW("%hhu", length_error, (unsigned long long)1); - CHECK_THROW("%llu", length_error, (unsigned char)1); + CHECK_THROW("%hhu", length_error, (unsigned long long){1}); + CHECK_THROW("%llu", length_error, (unsigned char){1}); CHECK_THROW("%f", conversion_error, 1u); CHECK_THROW("%f", conversion_error, "foo"); diff --git a/test/json_types.cpp b/test/json_types.cpp index c18bb2fa..2edeeea5 100644 --- a/test/json_types.cpp +++ b/test/json_types.cpp @@ -54,7 +54,7 @@ main (void) tap.expect (!ref["integer"].is_string (), "integer not is_string"); tap.expect ( util::equal ( - (unsigned)ref["integer"].as_number ().as_uint (), + ref["integer"].as_number ().as_uint (), 1u ), "integer value equality" diff --git a/time/parse8601.cpp.rl b/time/parse8601.cpp.rl index d0141781..78366f0a 100644 --- a/time/parse8601.cpp.rl +++ b/time/parse8601.cpp.rl @@ -22,6 +22,10 @@ #include #include +// We generate some really old style C code via ragel here, so we have to +// disable some noisy warnings (doubly so given -Werror) +#pragma GCC diagnostic ignored "-Wold-style-cast" + /////////////////////////////////////////////////////////////////////////////// %%{ diff --git a/uri.cpp.rl b/uri.cpp.rl index 8ea4c7ff..199e2876 100644 --- a/uri.cpp.rl +++ b/uri.cpp.rl @@ -25,6 +25,10 @@ #include #include +// We generate some really old style C code via ragel here, so we have to +// disable some noisy warnings (doubly so given -Werror) +#pragma GCC diagnostic ignored "-Wold-style-cast" + using util::uri; diff --git a/version.cpp.rl b/version.cpp.rl index 74f8ece8..598543ca 100644 --- a/version.cpp.rl +++ b/version.cpp.rl @@ -25,6 +25,10 @@ #include "debug.hpp" +// We generate some really old style C code via ragel here, so we have to +// disable some noisy warnings (doubly so given -Werror) +#pragma GCC diagnostic ignored "-Wold-style-cast" + using util::version;