Date: Tue, 14 May 2024 23:52:52 +0100
I'm experimenting with a consteval implementation of the MD5 hash
algorithm. I can write a switch statement with compile-time hashes as
follows:
switch ( md5(some_runtime_value) )
{
case md5("dog"): return 1;
case md5("cat"): return 2;
case md5("cow"): return 3;
}
The consteval implementation of 'md5' deals with a consteval array of
char's -- which is fine when you're hashing strings. It's a little
more complicated if you want to hash one of the following:
int[3]
tuple<int,char,bool>
struct Monkey { int a, b; };
It gets complicated when you want to use std::bit_cast to convert one
of these three types to an std::array<char,N>, because std::bit_cast
doesn't yield a compile-time constant if the source type isn't
trivially copiable. (Most implementations of std::tuple are not
trivially copiable -- not even when all of the internal types are).
__builtin_bit_cast isn't much better. Nor is __builtin_memcpy.
If I want to hash an array of integers, I can use the following
consteval function to turn it into a char array:
template<typename T, std::size_t N> requires std::is_integral_v<T>
constexpr auto FromIntegralArray( T const (&arg)[N] )
{
using std::size_t;
std::array<char, sizeof(arg)> retval{};
for ( size_t i = 0u; i < sizeof(arg); ++i )
{
size_t const a = i / sizeof(T),
b = i % sizeof(T);
retval[i] = arg[a] >> (CHAR_BIT * b);
}
return retval;
}
But then I would need to (try to) write a function that would work
with floating points, tuples, and so on.
So is anyone talking about making bit_cast more versatile? Or even
allowing a consteval memcpy, so we can do this:
template<typename T>
constexpr auto FromIntegralArray( T const &arg )
{
using std::size_t;
std::array<char, sizeof(arg)> retval{};
std::memcpy( &retval.front(), &arg, sizeof retval );
return retval;
}
algorithm. I can write a switch statement with compile-time hashes as
follows:
switch ( md5(some_runtime_value) )
{
case md5("dog"): return 1;
case md5("cat"): return 2;
case md5("cow"): return 3;
}
The consteval implementation of 'md5' deals with a consteval array of
char's -- which is fine when you're hashing strings. It's a little
more complicated if you want to hash one of the following:
int[3]
tuple<int,char,bool>
struct Monkey { int a, b; };
It gets complicated when you want to use std::bit_cast to convert one
of these three types to an std::array<char,N>, because std::bit_cast
doesn't yield a compile-time constant if the source type isn't
trivially copiable. (Most implementations of std::tuple are not
trivially copiable -- not even when all of the internal types are).
__builtin_bit_cast isn't much better. Nor is __builtin_memcpy.
If I want to hash an array of integers, I can use the following
consteval function to turn it into a char array:
template<typename T, std::size_t N> requires std::is_integral_v<T>
constexpr auto FromIntegralArray( T const (&arg)[N] )
{
using std::size_t;
std::array<char, sizeof(arg)> retval{};
for ( size_t i = 0u; i < sizeof(arg); ++i )
{
size_t const a = i / sizeof(T),
b = i % sizeof(T);
retval[i] = arg[a] >> (CHAR_BIT * b);
}
return retval;
}
But then I would need to (try to) write a function that would work
with floating points, tuples, and so on.
So is anyone talking about making bit_cast more versatile? Or even
allowing a consteval memcpy, so we can do this:
template<typename T>
constexpr auto FromIntegralArray( T const &arg )
{
using std::size_t;
std::array<char, sizeof(arg)> retval{};
std::memcpy( &retval.front(), &arg, sizeof retval );
return retval;
}
Received on 2024-05-14 22:53:04