mirror of
https://github.com/ZmnSCPxj/clboss.git
synced 2026-08-13 12:33:20 +02:00
Uuid.cpp: Universally-unique identifiers.
This commit is contained in:
parent
89702da676
commit
63fd273c02
4 changed files with 172 additions and 2 deletions
|
|
@ -286,7 +286,9 @@ libclboss_la_SOURCES = \
|
|||
Util/Str.cpp \
|
||||
Util/Str.hpp \
|
||||
Util/make_unique.hpp \
|
||||
Util/stringify.hpp
|
||||
Util/stringify.hpp \
|
||||
Uuid.cpp \
|
||||
Uuid.hpp
|
||||
|
||||
libclboss_la_LIBADD = \
|
||||
external/bitcoin-ripemd160/libbitcoin-ripemd160.la \
|
||||
|
|
@ -344,5 +346,6 @@ TESTS = \
|
|||
tests/sha256/test_hash \
|
||||
tests/sha256/test_hasher \
|
||||
tests/sqlite3/test_sqlite3 \
|
||||
tests/stats/test_running_mean
|
||||
tests/stats/test_running_mean \
|
||||
tests/test_uuid
|
||||
check_PROGRAMS = $(TESTS)
|
||||
|
|
|
|||
48
Uuid.cpp
Normal file
48
Uuid.cpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#include"Util/Str.hpp"
|
||||
#include"Util/make_unique.hpp"
|
||||
#include"Uuid.hpp"
|
||||
#include<algorithm>
|
||||
#include<sodium/randombytes.h>
|
||||
#include<sodium/utils.h>
|
||||
#include<stdexcept>
|
||||
|
||||
namespace {
|
||||
|
||||
std::uint8_t const zero[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
}
|
||||
|
||||
Uuid Uuid::random() {
|
||||
auto rv = Uuid();
|
||||
rv.pimpl = Util::make_unique<Impl>();
|
||||
randombytes_buf(rv.pimpl->data, sizeof(rv.pimpl->data));
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool Uuid::operator==(Uuid const& o) const {
|
||||
auto a = pimpl ? pimpl->data : zero;
|
||||
auto b = o.pimpl ? o.pimpl->data : zero;
|
||||
return 0 == sodium_memcmp(a, b, 16);
|
||||
}
|
||||
|
||||
Uuid::operator bool() const {
|
||||
if (!pimpl)
|
||||
return false;
|
||||
return 0 != sodium_memcmp(pimpl->data, zero, 16);
|
||||
}
|
||||
|
||||
Uuid::operator std::string() const {
|
||||
if (!pimpl)
|
||||
return "00000000000000000000000000000000";
|
||||
return Util::Str::hexdump(pimpl->data, 16);
|
||||
}
|
||||
Uuid::Uuid(std::string const& s) {
|
||||
pimpl = Util::make_unique<Impl>();
|
||||
auto buf = Util::Str::hexread(s);
|
||||
if (buf.size() != 16)
|
||||
throw std::invalid_argument("Uuid: invalid input string.");
|
||||
std::copy(buf.begin(), buf.end(), pimpl->data);
|
||||
}
|
||||
bool Uuid::valid_string(std::string const& s) {
|
||||
return Util::Str::ishex(s) && s.size() == 32;
|
||||
}
|
||||
82
Uuid.hpp
Normal file
82
Uuid.hpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#ifndef UUID_HPP
|
||||
#define UUID_HPP
|
||||
|
||||
#include<cstdint>
|
||||
#include<iostream>
|
||||
#include<memory>
|
||||
#include<string>
|
||||
#include<utility>
|
||||
|
||||
/** class Uuid
|
||||
*
|
||||
* @brief a unique 128-bit identifier.
|
||||
*
|
||||
* @desc this is ***not*** an RFC4122-standard UUID!
|
||||
* This is just 16 random bytes that we think is
|
||||
* sufficiently unique for this application.
|
||||
*/
|
||||
class Uuid {
|
||||
private:
|
||||
struct Impl {
|
||||
std::uint8_t data[16];
|
||||
};
|
||||
std::shared_ptr<Impl> pimpl;
|
||||
|
||||
public:
|
||||
Uuid() =default;
|
||||
Uuid(Uuid&&) =default;
|
||||
Uuid(Uuid const&) =default;
|
||||
Uuid& operator=(Uuid&&) =default;
|
||||
Uuid& operator=(Uuid const&) =default;
|
||||
~Uuid() =default;
|
||||
|
||||
/* Construct a fresh random UUID that has never
|
||||
* been used before (with high probability). */
|
||||
static Uuid random();
|
||||
|
||||
bool operator==(Uuid const& o) const;
|
||||
bool operator!=(Uuid const& o) const {
|
||||
return !(*this == o);
|
||||
}
|
||||
|
||||
operator bool() const;
|
||||
bool operator!() const {
|
||||
return !bool(*this);
|
||||
}
|
||||
|
||||
explicit operator std::string() const;
|
||||
explicit Uuid(std::string const&);
|
||||
static
|
||||
bool valid_string(std::string const&);
|
||||
|
||||
std::size_t hash() const {
|
||||
if (!pimpl)
|
||||
return 0;
|
||||
return *reinterpret_cast<std::size_t*>(pimpl->data);
|
||||
}
|
||||
};
|
||||
|
||||
inline
|
||||
std::ostream& operator<<(std::ostream& os, Uuid const& i) {
|
||||
return os << std::string(i);
|
||||
}
|
||||
inline
|
||||
std::istream& operator>>(std::istream& is, Uuid& i) {
|
||||
auto s = std::string();
|
||||
is >> s;
|
||||
i = Uuid(s);
|
||||
return is;
|
||||
}
|
||||
|
||||
namespace std {
|
||||
|
||||
template<>
|
||||
struct hash<Uuid> {
|
||||
std::size_t operator()(Uuid const& i) const {
|
||||
return i.hash();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* !defined(UUID_HPP) */
|
||||
37
tests/test_uuid.cpp
Normal file
37
tests/test_uuid.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#undef NDEBUG
|
||||
#include"Uuid.hpp"
|
||||
#include<assert.h>
|
||||
|
||||
int main() {
|
||||
auto a = Uuid();
|
||||
auto b = Uuid();
|
||||
assert(a == b);
|
||||
assert(Uuid() == b);
|
||||
assert(a == Uuid());
|
||||
assert(!a);
|
||||
|
||||
a = Uuid::random();
|
||||
assert(a); /* With very high probability, at least. */
|
||||
assert(a != b);
|
||||
b = a;
|
||||
assert(a == b);
|
||||
assert(std::hash<Uuid>()(a) == std::hash<Uuid>()(b));
|
||||
|
||||
b = (Uuid)(std::string)a;
|
||||
assert(a == b);
|
||||
assert(std::hash<Uuid>()(a) == std::hash<Uuid>()(b));
|
||||
|
||||
a = Uuid("00112233445566778899aabbccddeeff");
|
||||
b = Uuid("00112233445566778899aabbccddeeff");
|
||||
assert(a == b);
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(std::hash<Uuid>()(a) == std::hash<Uuid>()(b));
|
||||
assert(std::string(a) == "00112233445566778899aabbccddeeff");
|
||||
|
||||
b = Uuid("00112233445566778899aabbccddeefe");
|
||||
assert(a != b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue