spent far too much time getting compile time code to work.
This commit is contained in:
parent
aab2dcbd6a
commit
f6db345939
@ -25,11 +25,11 @@ namespace ro {
|
||||
// copy constructor
|
||||
sql(const sql& a) = delete;
|
||||
// move constructor
|
||||
sql(sql&& p) :std::unique_ptr<Icompiled_sql>(p.release()) { }
|
||||
sql(sql&& p) noexcept :std::unique_ptr<Icompiled_sql>(p.release()) { }
|
||||
// copy assignment
|
||||
sql& operator=(const sql) = delete;
|
||||
// Move assignment
|
||||
sql& operator=(sql&& p) {
|
||||
sql& operator=(sql&& p) noexcept {
|
||||
std::unique_ptr<Icompiled_sql>::reset(p.release());
|
||||
}
|
||||
sql(Icompiled_sql* p) :std::unique_ptr<Icompiled_sql>(p) {}
|
||||
|
@ -14,18 +14,54 @@ namespace ro {
|
||||
return id ^ (id >> 32);
|
||||
}
|
||||
|
||||
class charmap :public std::array<char, 0x100> {
|
||||
class charmap {
|
||||
public:
|
||||
std::array< char, 0x100> index{ 0, };
|
||||
charmap() = delete;
|
||||
constexpr charmap(const char* p, const char* q) {
|
||||
constexpr charmap(const char * p, const char * q) {
|
||||
while (unsigned int pu{ static_cast<unsigned char>(*p++) }) {
|
||||
assert((*this)[pu] == 0);
|
||||
(*this)[pu] = *q++;
|
||||
assert(index[pu] == 0);
|
||||
index[pu] = *q++;
|
||||
}
|
||||
assert(*(p - 1) == '\0' && *q == '\0');
|
||||
assert(*(p - 1) == '\0' && *q == '\0');
|
||||
/* when an instance of this class is declared constexpr,
|
||||
an assert does not trigger a run time error,
|
||||
because expression evaluated at compile time.
|
||||
Instead the compiler reports that the expression
|
||||
did not evaluate to a constant,
|
||||
|
||||
The error is confusing, because the error points to
|
||||
the declaration where the initialization was invoked,
|
||||
instead of pointing to the assert.
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
class charmapWithFixup {
|
||||
public:
|
||||
std::array< char, 0x100> index{ 0, };
|
||||
charmapWithFixup() = delete;
|
||||
constexpr charmapWithFixup(const char* p, const char* q) {
|
||||
while (unsigned int pu{ static_cast<unsigned char>(*p++) }) {
|
||||
assert(index[pu] == 0);
|
||||
index[pu] = *q++;
|
||||
}
|
||||
index['I'] = index['l']='0';
|
||||
assert(*(p - 1) == '\0' && *q == '\0');
|
||||
/* when an instance of this class is declared constexpr,
|
||||
an assert does not trigger a run time error,
|
||||
because expression evaluated at compile time.
|
||||
Instead the compiler reports that the expression
|
||||
did not evaluate to a constant,
|
||||
|
||||
The error is confusing, because the error points to
|
||||
the declaration where the initialization was invoked,
|
||||
instead of pointing to the assert.
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//template <> class base58<scalar> : public CompileSizedString<44> {};
|
||||
static_assert(sizeof(base58<point>) == 46, "base58 point strings unexpected size");
|
||||
|
||||
@ -33,17 +69,18 @@ namespace ro {
|
||||
static constexpr char index2MpirBase58[] { "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv" };
|
||||
|
||||
void map_base_from_mpir58(char* p) {
|
||||
static const charmap map(index2MpirBase58, index2cryptoBase58);
|
||||
while (unsigned int pu{ static_cast<unsigned char>(*p) }) {
|
||||
*p++ = map[pu];
|
||||
static constexpr charmap map(index2MpirBase58, index2cryptoBase58);
|
||||
while (uint8_t pu{ static_cast<uint8_t>(*p) }) {
|
||||
*p++ = map.index[pu];
|
||||
}
|
||||
}
|
||||
|
||||
void map_base_to_mpir58(const char* p, char* q, size_t count) {
|
||||
static const charmap map(index2cryptoBase58, index2MpirBase58);
|
||||
static constexpr charmap map(index2cryptoBase58, index2MpirBase58);
|
||||
static_assert(map.index[0xF0] == 0);
|
||||
while (count--) {
|
||||
unsigned int pu{ static_cast<unsigned char>(*p++) };
|
||||
char c{ map[pu] };
|
||||
char c{ map.index[pu] };
|
||||
if (c == '\0') throw NotBase58Exception();
|
||||
*q++ = c;
|
||||
}
|
||||
|
105
slash6.cpp
105
slash6.cpp
@ -15,11 +15,30 @@
|
||||
static constexpr uint8_t index2base64[]{
|
||||
"0123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz!$*+-_"
|
||||
};
|
||||
|
||||
/*
|
||||
control characters are stops
|
||||
! $ * + - permitted The characters "#%&'(),. are stops
|
||||
0-9 permitted The characters :;<=>? are stops
|
||||
A-Z and _ permitted, @ and [\]^ are stops
|
||||
a-z permitted. {|} ~` are stops, as is the mysterious control character 0x7F (del)
|
||||
*/
|
||||
// Unlike regular baseINV, and incompatible with it. Intended to encode stuff small enough
|
||||
// that it might be human typed and human transmitted, therefore maps 'o' and 'O' to '0', 'I' and
|
||||
// 'l' to '1'
|
||||
// uses six url safe additional characters !$*+-_ to bring it up to six bits
|
||||
//
|
||||
// But on reflection, useless, since human typed stuff like this should use Bitcoin's base 58 encoding
|
||||
// So going to switch to regular base64, despite the unreasonably immense amount of work I put into it.
|
||||
|
||||
// Unfortunately, Wireguard, with which I am going to need to interoperate, uses RFC4648, whose
|
||||
// algorithm is fundamentally different - no special treatment for I, O, o, and l, and uses =
|
||||
// to handle the case where you have boundary problems between eight and six bit groups.
|
||||
// They force everything to four character groups, using an = sign to indicate that the
|
||||
// bytes being represented stop before a multiple of three. https://www.base64encode.org
|
||||
|
||||
|
||||
|
||||
|
||||
static_assert(index2base64[63] == '_', "surprise numeral at 63");
|
||||
|
||||
// Being intended for small bits of data, assumes no whitespace within an entity
|
||||
@ -35,41 +54,71 @@ static_assert(index2base64[63] == '_', "surprise numeral at 63");
|
||||
// will return a number of bits less than the size of the input bit buffer, less than the bitcount
|
||||
// it was given.
|
||||
|
||||
// Table to convert ascii to six bit.
|
||||
static constexpr std::array<constexpr uint8_t, 0x100> ascii2six_ar{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //control characters
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //control characters
|
||||
0xff, 0x3a, 0xff, 0xff, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3c, 0x3d, 0xff, 0x3e, 0xff, 0xff, // ! $ * + - permitted The characters "#%&'(),. are stops
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0-9 permitted The characters :;<=>? are stops
|
||||
0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x01, 0x12, 0x13, 0x14, 0x15, 0x16, 0x00,
|
||||
0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0xff, 0xff, 0xff, 0xff, 0x3f, // A-Z and _ permitted, @ and [\]^ are stops
|
||||
0xff, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x01, 0x2d, 0x2e, 0x00,
|
||||
0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, //a-z the characters {|} ~` are stops, as is the mysterious control character 0x7F (del)
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff // utf8 multibyte characters, all stops.
|
||||
};
|
||||
|
||||
// Table to convert ascii to six bit as a good old fashioned non owning naked pointer to const,
|
||||
// whose storage is owned by a const static which exists until the program terminates.
|
||||
static const uint8_t *ascii2six{ &ascii2six_ar[0] };
|
||||
// Compile time execution is C++ is a pain, because expressions are apt to unpredictably lose
|
||||
// their constexpr character for reasons that are far from clear.
|
||||
//
|
||||
// You can declare anything reasonable to be constexpr, and the compiler will not issue an
|
||||
// error message until the code that attempts to use what you have declared constexpr is
|
||||
// invoked from somewhere else "expression does not evaluate to constant"
|
||||
//
|
||||
// an assert in an expression evaluated at compile time does not trigger a run time error,
|
||||
// Instead the compiler reports that the expression did not evaluate to a constant,
|
||||
//
|
||||
// The error is confusing, because the error points to the declaration where the initialization
|
||||
// was invoked,instead of pointing to the assert.
|
||||
|
||||
// To debug code intended to be run at compile time, exercise it at run time with
|
||||
// auto ptr(std::make_unique<Class>());
|
||||
// at run time;
|
||||
|
||||
class charindex {
|
||||
public:
|
||||
std::array< uint8_t, 0x100> index{ 0, };
|
||||
// this non const array will become constexpr and be constructed at compile time
|
||||
// when an instance of this class is created in a constexpr expression.
|
||||
charindex() = delete;
|
||||
constexpr charindex(const uint8_t* p) {
|
||||
uint8_t pu{ 0 };
|
||||
do { index[pu++] = 0xFF; } while (pu);
|
||||
uint8_t i{ 0 };
|
||||
while (pu = static_cast<uint8_t>(p[i])) {
|
||||
index[pu] = i;
|
||||
i++;
|
||||
assert(i != 0); //prevents unending execution,
|
||||
// inside a constexp, generates an "expression does not evaluate to constant"
|
||||
// error at compile time, rather than breaking at run time.
|
||||
}
|
||||
index['o'] = index['O'] = 0;
|
||||
index['l'] = index['I'] = 1;
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr charindex ascii2six_ar(index2base64);
|
||||
|
||||
//
|
||||
//
|
||||
// You really have to write compile time code in templates as a language, which is the totally
|
||||
// obscure and hard to use language apt to generate remarkably voluminous error messages
|
||||
// will little obvious connection to the actual problem, and surprising result that are ver
|
||||
// difficult to predict in advance or understand at all.
|
||||
// In general, the better solution is to have a routine that is called once and only once at the
|
||||
// beginning of the program, which initializes a bunch of static const values, if that solution is
|
||||
// adequate, or to have a preproces routine written in python which generates the required C
|
||||
// files and header files.
|
||||
|
||||
// After this experiment in compile time code, I swear off it.
|
||||
// Table to convert ascii to six bit as a good old fashioned non owning naked pointer to const,
|
||||
// whose storage is owned by a const static which exists until the program terminates.
|
||||
const uint8_t* const ascii2six{ &ascii2six_ar.index[0] };
|
||||
|
||||
void ascii2test() {
|
||||
for (unsigned int i{ 0 }; i < 0x100;i++) {
|
||||
char v = i;
|
||||
unsigned int j = ascii2six[i];
|
||||
char w = index2base64[j];
|
||||
if (j < 64) {
|
||||
assert(v == w || v == 'I' || v == 'l' || v == 'o' || v == 'O');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Decode does not have an input span of encoded characters, but a char *, because it assumes
|
||||
// the string is always terminated by an invalid character, such as the trailing null at the end of
|
||||
|
@ -21,6 +21,8 @@ Namespace testbed is only defined in this cpp file, hence nothing within
|
||||
If it needs to interact with the outside world, should post a message
|
||||
analogously to queue_error_message, which then calls back to a
|
||||
routine in this file.*/
|
||||
void ascii2test();
|
||||
extern const uint8_t* const ascii2six;
|
||||
|
||||
namespace testbed {
|
||||
using ristretto255::hash, ristretto255::hsh, ristretto255::scalar,
|
||||
@ -49,5 +51,6 @@ If using a dialog, exceptions within the dialog will result in an error message
|
||||
|
||||
void testbed() {
|
||||
// queue_error_message("hello world");
|
||||
ascii2test();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user