Uuid.cpp: Universally-unique identifiers.

This commit is contained in:
ZmnSCPxj jxPCSnmZ 2020-09-27 19:16:57 +08:00
parent 89702da676
commit 63fd273c02
4 changed files with 172 additions and 2 deletions

View file

@ -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
View 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
View 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
View 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;
}