Added type_hash<T>(): Creates a (mostly) unique SHA256 hash at compile time for a given type. The hash is given static storage duration, no other executable bloat is kept.
XXX: Added new dependency: `sha256_literal`. (TODO: Grab this, manage dependencies somehow..) Added id.hh: `uuid` and related types & helpers. Fortune for readpass's current commit: Future small blessing − 末小吉master
parent
09d29eba24
commit
18a854e480
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
namespace id {
|
||||
struct uuid {
|
||||
//TODO: constexpr uuid_v4 impl
|
||||
|
||||
constexpr uuid v4() noexcept {
|
||||
//TODO: Generate new UUID at compile time?
|
||||
}
|
||||
};
|
||||
struct unique_ref {
|
||||
uuid id;
|
||||
|
||||
constexpr friend auto operator<=>(unique_ref const& a, unique_ref const& b) noexcept = default;
|
||||
};
|
||||
struct unique {
|
||||
constexpr unique() noexcept
|
||||
: m_id(uuid::v4()) {}
|
||||
constexpr unique(const unique&) noexcept
|
||||
: unique() {}
|
||||
constexpr unique(unique&&) noexcept = default;
|
||||
constexpr unique& operator=(unique&&) noexcept = default;
|
||||
constexpr unique& operator=(unique const& b) noexcept
|
||||
{ if(this != std::addressof(b)) m_id = uuid::v4(); return *this; }
|
||||
constexpr virtual ~unique() = default;
|
||||
|
||||
template<std::derived_from<unique> T, std::derived_from<unique> U>
|
||||
constexpr friend bool operator==(T const& a, U const& b) noexcept { return static_cast<unique const&>(a) == static_cast<unique const&>(b); }
|
||||
template<std::derived_from<unique> T, std::derived_from<unique> U>
|
||||
constexpr friend bool operator!=(T const& a, U const& b) noexcept { return !(a == b); }
|
||||
|
||||
constexpr friend bool operator==(unique const& a, unique const& b) noexcept { return a.unique_id() == b.unique_id(); }
|
||||
constexpr friend bool operator!=(unique const& a, unique const& b) noexcept { return a.unique_id() != b.unique_id(); }
|
||||
|
||||
constexpr unique_ref unique_id() const noexcept { return { m_id }; }
|
||||
protected:
|
||||
constexpr uuid& raw_id() noexcept { return m_id; }
|
||||
constexpr uuid const& raw_id() const noexcept { return m_id; }
|
||||
|
||||
constexpr explicit unique(std::convertible_to<uuid> auto&& id)
|
||||
: m_id(std::move(id)) {}
|
||||
private:
|
||||
uuid m_id;
|
||||
};
|
||||
}
|
@ -1,3 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
//TODO: A very basic typeid: Using the constexpr __PRETTY_FUNCTION__ array slicing trick we used for `exopt::util::type_name<T>()`, we can extract the unmangled, de-aliased type name T, we can then hash that at comptime, and give it static storage: Therefore __PRETTY_FUNCTION__ will not be given storage, but the resulting (far smaller, but still *almost* unique to each type name) hash, will be.
|
||||
#include <sha256_literal.h>
|
||||
|
||||
#include "util.hh"
|
||||
|
||||
namespace types {
|
||||
// A very basic typeid: Using the constexpr __PRETTY_FUNCTION__ array slicing trick we used for `exopt::util::type_name<T>()`, we can extract the unmangled, de-aliased type name T, we can then hash that at comptime, and give it static storage: Therefore __PRETTY_FUNCTION__ will not be given storage, but the resulting (far smaller, but still *almost* unique to each type name) hash, will be.
|
||||
|
||||
using util::type_name;
|
||||
|
||||
template<typename T>
|
||||
struct type_hash_of {
|
||||
// Give *only* the computed hash static storage duration, not the type name.
|
||||
constexpr static inline auto value = sha256::compute(util::type_name_literal<T>());
|
||||
};
|
||||
|
||||
/// Returns a (semi) unique SHA256 hash representing the type `T`.
|
||||
///
|
||||
/// NOTE: This hash is given static storage duration, but nothing else used to calculate it is. Therefore executable bloat is not a concern for values obtained from this function.
|
||||
template<typename T>
|
||||
constexpr const auto& type_hash() noexcept {
|
||||
constexpr const auto& value = type_hash_of<T>::value;
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr inline auto& type_hash_v = type_hash_of<T>::value;
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <pointer_traits>
|
||||
#include <array>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace util {
|
||||
[[gnu::const, gnu::always_inline]]
|
||||
constexpr ptrdiff_t ptr_diff(const auto *p1, const auto *p2) noexcept
|
||||
{
|
||||
auto a1 = std::to_address(p1);
|
||||
auto a2 = std::to_address(p2);
|
||||
return ptrdiff_t(a1 < a2 ? a2 - a1 : a1 - a2);
|
||||
}
|
||||
[[gnu::const, gnu::always_inline]]
|
||||
constexpr ptrdiff_t ptr_diff(intptr_t p1, intptr_t p2) noexcept
|
||||
{
|
||||
return ptrdiff_t(p1 < p2 ? p2 - p1 : p1 - p2);
|
||||
}
|
||||
|
||||
|
||||
template<size_t... Idx>
|
||||
constexpr auto substring_literal(const auto& str, std::index_sequence<Idx...>) noexcept
|
||||
requires(requires(size_t n) {
|
||||
{ str[n] } noexcept -> std::convertible_to<char>;
|
||||
})
|
||||
{
|
||||
return std::array{ str[Idx]..., '\n' };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr auto type_name_literal() noexcept
|
||||
{
|
||||
constexpr std::string_view prefix {
|
||||
#if defined(__clang__)
|
||||
"[T = "
|
||||
#elif defined(__GNUC__)
|
||||
"with T = "
|
||||
#else
|
||||
// Fuck MSVC, don't care.
|
||||
#error Unsupported compiler
|
||||
#endif
|
||||
};
|
||||
constexpr std::string_view suffix {"]"};
|
||||
constexpr std::string_view function {__PRETTY_FUNCTION__};
|
||||
|
||||
constexpr auto start = function.find(prefix) + prefix.size();
|
||||
constexpr auto end = function.rfind(suffix);
|
||||
|
||||
static_assert(start < end);
|
||||
|
||||
constexpr std::string_view name = function.substr(start, (end - start));
|
||||
return substring_literal(name, std::make_index_sequence<name.size()>{});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct [[gnu::visibility("internal")]] type_name_of {
|
||||
constexpr static inline auto value = type_name_literal<T>();
|
||||
|
||||
[[gnu::const]]
|
||||
consteval operator std::string_view() const noexcept {
|
||||
constexpr auto& v = value;
|
||||
return std::string_view { v.data(), v.size() };
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr auto type_name() noexcept -> std::string_view
|
||||
{
|
||||
constexpr auto& value = type_name_of<T>::value;
|
||||
return std::string_view { value.data(), value.size() };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr inline auto type_name_v = type_name<T>();
|
||||
|
||||
|
||||
}
|
Loading…
Reference in new issue