// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. #pragma once #define HAVE_IRCD_UTIL_TYPOGRAPHY_H namespace ircd { inline namespace util { // // Overloading macros // /// Macro to arrange a function overload scheme based on the following /// convention: An available `name` is chosen, from this name a strong type /// is created by appending `_t`. The name itself becomes a static constexpr /// instance of this `name_t`. Functions can be declared with an argument /// accepting `name_t`, and called by passing `name` /// /// IRCD_OVERLOAD(foo) // declare overload /// void function(int, foo_t) {} // overloaded version /// void function(int) { function(0, foo); } // calls overloaded version /// function(0); // calls regular version /// #define IRCD_OVERLOAD(NAME) \ static constexpr struct NAME##_t {} NAME {}; /// Imports an overload scheme from elsewhere without redeclaring the type_t. #define IRCD_USING_OVERLOAD(ALIAS, ORIGIN) \ static constexpr const auto &ALIAS{ORIGIN} // // Typedef macros // /// Creates a type `NAME` from original type `TYPE` by inheriting from `TYPE` /// and passing through construction to `TYPE`. These implicit conversions /// we consider to be a "weak" typedef #define IRCD_WEAK_TYPEDEF(TYPE, NAME) \ struct NAME \ :TYPE \ { \ using TYPE::TYPE; \ }; /// Creates a type `NAME` by wrapping instance of `TYPE` as a member and /// providing explicit conversions to `TYPE` and aggregate construction only. We /// consider this a "strong" typedef which is useful for wrapping POD types /// for overloaded functions, etc. #define IRCD_STRONG_TYPEDEF(TYPE, NAME) \ struct NAME \ { \ TYPE val; \ \ explicit operator const TYPE &() const { return val; } \ explicit operator TYPE &() { return val; } \ }; /// Convenience for weak typedef statements #define IRCD_WEAK_T(TYPE) \ IRCD_WEAK_TYPEDEF(TYPE, IRCD_UNIQUE(weak_t)) /// Convenience for strong typedef statements /// ex: using foo_t = IRCD_STRONG_T(int) #define IRCD_STRONG_T(TYPE) \ IRCD_STRONG_TYPEDEF(TYPE, IRCD_UNIQUE(strong_t)) // // Debug sizeof structure at compile time // /// Output the sizeof a structure at compile time. /// This stops the compiler with an error (good) containing the size of the target /// in the message. /// /// example: struct foo {}; IRCD_TEST_SIZEOF(foo) /// #define IRCD_TEST_SIZEOF(name) \ ircd::util::_TEST_SIZEOF_ _test_; /// Internal use only template struct _TEST_SIZEOF_; // // signed sizeof // template constexpr ssize_t ssizeof(T&&) { return sizeof(T); } template constexpr ssize_t ssizeof() { return sizeof(T); } // // Test if type is forward declared or complete // template struct is_complete :std::false_type {}; template struct is_complete :std::true_type {}; // // Test if type is a specialization of a template // template class> struct is_specialization_of :std::false_type {}; template class T, class... args> struct is_specialization_of, T> :std::true_type {}; // // Convenience signedness cast template // template using enable_if_s2u = std::enable_if::value, typename std::make_unsigned::type>; template [[using gnu: always_inline, gnu_inline, artificial]] extern inline typename enable_if_s2u::type * sign_cast(T *const t) { using type = typename std::make_unsigned::type; return reinterpret_cast(t); } template using enable_if_u2s = std::enable_if::value, typename std::make_signed::type>; template [[using gnu: always_inline, gnu_inline, artificial]] extern inline typename enable_if_u2s::type * sign_cast(T *const t) { using type = typename std::make_signed::type; return reinterpret_cast(t); } // // Convenience const_cast deduction template // template [[using gnu: always_inline, gnu_inline, artificial]] extern inline typename std::remove_const::type & mutable_cast(T &t) { using type = typename std::remove_const::type; return const_cast(t); } template [[using gnu: always_inline, gnu_inline, artificial]] extern inline typename std::remove_const::type * mutable_cast(T *const t) { using type = typename std::remove_const::type; return const_cast(t); } // // Convenience involatile cast template // template [[using gnu: always_inline, gnu_inline, artificial]] extern inline typename std::remove_volatile::type & involatile_cast(T &t) { using type = typename std::remove_volatile::type; return const_cast(t); } template [[using gnu: always_inline, gnu_inline, artificial]] extern inline typename std::remove_volatile::type * involatile_cast(T *const t) { using type = typename std::remove_volatile::type; return const_cast(t); } // // Test if type is shared_from_this // /// Tests if type inherits from std::enable_shared_from_this<> template constexpr typename std::enable_if::value, bool>::type is_shared_from_this() { return std::is_base_of, T>(); } /// Unconditional failure for fwd-declared incomplete types, which /// obviously don't inherit from std::enable_shared_from_this<> template constexpr typename std::enable_if::value, bool>::type is_shared_from_this() { return false; } // // Misc type testing boilerplates // template constexpr bool is_bool() { using type = typename std::remove_reference::type; return std::is_same::value; } template constexpr bool is_number() { using type = typename std::remove_reference::type; return std::is_arithmetic::value; } template constexpr bool is_floating() { using type = typename std::remove_reference::type; return is_number() && std::is_floating_point(); } template constexpr bool is_integer() { return is_number() && !is_floating(); } template constexpr bool is_pod() { return std::is_standard_layout::value && std::is_trivial::value; } // // Convenience constexprs for iterators // template constexpr auto is_iterator() { return std::is_base_of::value_type, It>::value; } template constexpr auto is_forward_iterator() { return std::is_base_of::iterator_category>::value; } template constexpr auto is_input_iterator() { return std::is_base_of::iterator_category>::value; } // // Completing std::remove_pointer<> // template struct remove_all_pointers { using type = T; }; template struct remove_all_pointers { using type = typename remove_all_pointers::type; }; /// Convenience loop to test std::is* on a character sequence template ssize_t ctype(const char *const &begin, const char *const &end) { for(const char *it(begin); it != end; ++it) if(test(static_cast(*it)) != 0) return std::distance(begin, it); return -1; } /// ctype test for a const_buffer. Returns the character position where the /// test fails. Returns -1 on success. The test is a function specified in /// the template simply as `ctype(const_buffer{"hi"});` which /// should fail because const_buffer's over a string literal see the trailing /// null character. template ssize_t ctype(const const_buffer &s) { return ctype(begin(s), end(s)); } /// Boolean alternative for ctype(const_buffer) template bool all_of(const const_buffer &s) { return std::all_of(begin(s), end(s), [](const char &c) { return test(c) != 0; }); } /// Boolean alternative for ctype(const_buffer) template bool none_of(const const_buffer &s) { return std::all_of(begin(s), end(s), [](const char &c) { return test(c) == 0; }); } /// Zero testing functor (work in progress) /// struct is_zero { template typename std::enable_if < is_bool(), bool>::type test(const bool &value) const { return !value; } template typename std::enable_if < is_integer() && !is_bool(), bool>::type test(const size_t &value) const { return value == 0; } template typename std::enable_if < is_floating() && !is_bool(), bool>::type test(const double &value) const { return !(value > 0.0 || value < 0.0); } template bool operator()(T&& t) const { return test(std::forward(t)); } }; } // namespace util } // namespace ircd