mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-30 22:47:16 +08:00
mdbx++: add to_hex/to_base58/to_base64::output(std::ostream&)
without using temporary objects/buffers/strings.
Change-Id: Ideffd0e7f450307e14d780dcdeb2458c1c7e4c18
This commit is contained in:
parent
b139d8165b
commit
b5b0a9a284
23
mdbx.h++
23
mdbx.h++
@ -1146,6 +1146,11 @@ struct LIBMDBX_API to_hex {
|
||||
/// \throws std::length_error if given buffer is too small.
|
||||
char *write_bytes(char *dest, size_t dest_size) const;
|
||||
|
||||
/// \brief Output hexadecimal dump of passed slice to the std::ostream.
|
||||
/// \throws std::ios_base::failure corresponding to std::ostream::write()
|
||||
/// behaviour.
|
||||
::std::ostream &output(::std::ostream &out) const;
|
||||
|
||||
/// \brief Checks whether a passed slice is empty,
|
||||
/// and therefore there will be no output bytes.
|
||||
bool is_empty() const noexcept { return source.empty(); }
|
||||
@ -1195,6 +1200,12 @@ struct LIBMDBX_API to_base58 {
|
||||
/// \throws std::length_error if given buffer is too small.
|
||||
char *write_bytes(char *dest, size_t dest_size) const;
|
||||
|
||||
/// \brief Output [Base58](https://en.wikipedia.org/wiki/Base58)
|
||||
/// dump of passed slice to the std::ostream.
|
||||
/// \throws std::ios_base::failure corresponding to std::ostream::write()
|
||||
/// behaviour.
|
||||
::std::ostream &output(::std::ostream &out) const;
|
||||
|
||||
/// \brief Checks whether a passed slice is empty,
|
||||
/// and therefore there will be no output bytes.
|
||||
bool is_empty() const noexcept { return source.empty(); }
|
||||
@ -1243,6 +1254,12 @@ struct LIBMDBX_API to_base64 {
|
||||
/// \throws std::length_error if given buffer is too small.
|
||||
char *write_bytes(char *dest, size_t dest_size) const;
|
||||
|
||||
/// \brief Output [Base64](https://en.wikipedia.org/wiki/Base64)
|
||||
/// dump of passed slice to the std::ostream.
|
||||
/// \throws std::ios_base::failure corresponding to std::ostream::write()
|
||||
/// behaviour.
|
||||
::std::ostream &output(::std::ostream &out) const;
|
||||
|
||||
/// \brief Checks whether a passed slice is empty,
|
||||
/// and therefore there will be no output bytes.
|
||||
bool is_empty() const noexcept { return source.empty(); }
|
||||
@ -1253,15 +1270,15 @@ struct LIBMDBX_API to_base64 {
|
||||
};
|
||||
|
||||
inline ::std::ostream &operator<<(::std::ostream &out, const to_hex &wrapper) {
|
||||
return out << wrapper.as_string();
|
||||
return wrapper.output(out);
|
||||
}
|
||||
inline ::std::ostream &operator<<(::std::ostream &out,
|
||||
const to_base58 &wrapper) {
|
||||
return out << wrapper.as_string();
|
||||
return wrapper.output(out);
|
||||
}
|
||||
inline ::std::ostream &operator<<(::std::ostream &out,
|
||||
const to_base64 &wrapper) {
|
||||
return out << wrapper.as_string();
|
||||
return wrapper.output(out);
|
||||
}
|
||||
|
||||
/// \brief Hexadecimal decoder which satisfy \ref SliceTranscoder concept.
|
||||
|
119
src/mdbx.c++
119
src/mdbx.c++
@ -14,6 +14,7 @@
|
||||
#include "defs.h"
|
||||
#include "internals.h"
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cctype> // for isxdigit(), etc
|
||||
#include <system_error>
|
||||
@ -559,6 +560,28 @@ char *to_hex::write_bytes(char *__restrict dest, size_t dest_size) const {
|
||||
return dest;
|
||||
}
|
||||
|
||||
::std::ostream &to_hex::output(::std::ostream &out) const {
|
||||
if (MDBX_LIKELY(!is_empty()))
|
||||
MDBX_CXX20_LIKELY {
|
||||
::std::ostream::sentry sentry(out);
|
||||
auto src = source.byte_ptr();
|
||||
const char alphabase = (uppercase ? 'A' : 'a') - 10;
|
||||
unsigned width = 0;
|
||||
for (const auto end = source.end_byte_ptr(); src != end; ++src) {
|
||||
if (wrap_width && width >= wrap_width) {
|
||||
out << ::std::endl;
|
||||
width = 0;
|
||||
}
|
||||
const int8_t hi = *src >> 4;
|
||||
const int8_t lo = *src & 15;
|
||||
out.put(char(alphabase + hi + (((hi - 10) >> 7) & -7)));
|
||||
out.put(char(alphabase + lo + (((lo - 10) >> 7) & -7)));
|
||||
width += 2;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
char *from_hex::write_bytes(char *__restrict dest, size_t dest_size) const {
|
||||
if (MDBX_UNLIKELY(source.length() % 2 && !ignore_spaces))
|
||||
MDBX_CXX20_UNLIKELY throw std::domain_error(
|
||||
@ -719,6 +742,65 @@ char *to_base58::write_bytes(char *__restrict dest, size_t dest_size) const {
|
||||
return dest;
|
||||
}
|
||||
|
||||
::std::ostream &to_base58::output(::std::ostream &out) const {
|
||||
if (MDBX_LIKELY(!is_empty()))
|
||||
MDBX_CXX20_LIKELY {
|
||||
::std::ostream::sentry sentry(out);
|
||||
auto src = source.byte_ptr();
|
||||
size_t left = source.length();
|
||||
unsigned width = 0;
|
||||
std::array<char, 11> buf;
|
||||
|
||||
while (MDBX_LIKELY(left > 7)) {
|
||||
uint64_t v;
|
||||
std::memcpy(&v, src, 8);
|
||||
src += 8;
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
v = bswap64(v);
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#else
|
||||
#error "FIXME: Unsupported byte order"
|
||||
#endif /* __BYTE_ORDER__ */
|
||||
buf[10] = b58_8to11(v);
|
||||
buf[9] = b58_8to11(v);
|
||||
buf[8] = b58_8to11(v);
|
||||
buf[7] = b58_8to11(v);
|
||||
buf[6] = b58_8to11(v);
|
||||
buf[5] = b58_8to11(v);
|
||||
buf[4] = b58_8to11(v);
|
||||
buf[3] = b58_8to11(v);
|
||||
buf[2] = b58_8to11(v);
|
||||
buf[1] = b58_8to11(v);
|
||||
buf[0] = b58_8to11(v);
|
||||
assert(v == 0);
|
||||
out.write(buf.begin(), 11);
|
||||
left -= 8;
|
||||
if (wrap_width && (width += 11) >= wrap_width && left) {
|
||||
out << ::std::endl;
|
||||
width = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (left) {
|
||||
uint64_t v = 0;
|
||||
unsigned parrots = 31;
|
||||
do {
|
||||
v = (v << 8) + *src++;
|
||||
parrots += 43;
|
||||
} while (--left);
|
||||
|
||||
auto ptr = buf.end();
|
||||
do {
|
||||
*--ptr = b58_8to11(v);
|
||||
parrots -= 32;
|
||||
} while (parrots > 31);
|
||||
assert(v == 0);
|
||||
out.write(&*ptr, buf.end() - ptr);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const signed char b58_map[256] = {
|
||||
// 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
OO, IL, IL, IL, IL, IL, IL, IL, IL, SP, SP, SP, SP, SP, IL, IL, // 00
|
||||
@ -890,6 +972,43 @@ char *to_base64::write_bytes(char *__restrict dest, size_t dest_size) const {
|
||||
}
|
||||
}
|
||||
|
||||
::std::ostream &to_base64::output(::std::ostream &out) const {
|
||||
if (MDBX_LIKELY(!is_empty()))
|
||||
MDBX_CXX20_LIKELY {
|
||||
::std::ostream::sentry sentry(out);
|
||||
auto src = source.byte_ptr();
|
||||
size_t left = source.length();
|
||||
unsigned width = 0;
|
||||
std::array<char, 4> buf;
|
||||
|
||||
while (true) {
|
||||
switch (left) {
|
||||
default:
|
||||
MDBX_CXX20_LIKELY left -= 3;
|
||||
b64_3to4(src[0], src[1], src[2], buf.begin());
|
||||
src += 3;
|
||||
out.write(buf.begin(), 4);
|
||||
if (wrap_width && (width += 4) >= wrap_width && left) {
|
||||
out << ::std::endl;
|
||||
width = 0;
|
||||
}
|
||||
continue;
|
||||
case 2:
|
||||
b64_3to4(src[0], src[1], 0, buf.begin());
|
||||
buf[3] = '=';
|
||||
return out.write(buf.begin(), 4);
|
||||
case 1:
|
||||
b64_3to4(src[0], 0, 0, buf.begin());
|
||||
buf[2] = buf[3] = '=';
|
||||
return out.write(buf.begin(), 4);
|
||||
case 0:
|
||||
return out;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static const signed char b64_map[256] = {
|
||||
// 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
OO, IL, IL, IL, IL, IL, IL, IL, IL, SP, SP, SP, SP, SP, IL, IL, // 00
|
||||
|
Loading…
x
Reference in New Issue
Block a user