dasmig-core 1.2.0
Shared random engine, distributions and data tiers for the dasmig generator libraries
Loading...
Searching...
No Matches
seed_signature.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2020-2026 Diego Dasso Migotto
3
4#ifndef DASMIG_CORE_SEED_SIGNATURE_HPP
5#define DASMIG_CORE_SEED_SIGNATURE_HPP
6
7#include "json.hpp"
8
9#include <array>
10#include <charconv>
11#include <cstddef>
12#include <cstdint>
13#include <memory>
14#include <optional>
15#include <stdexcept>
16#include <string>
17#include <string_view>
18#include <system_error>
19
20/// @file seed_signature.hpp
21/// @brief The replay format of every generated result.
22/// @author Diego Dasso Migotto (diegomigotto at hotmail dot com)
23
24namespace dasmig::core
25{
26
27/// @brief What a result needs to be generated again: its call seed and the
28/// data it was generated from.
29///
30/// `data` is the layered_table::data_hash() (or a combination of several)
31/// of the data loaded when the result was made; 0 means "not recorded". A
32/// seed replays the same result only against the same data, so a replay can
33/// compare `data` and report a mismatch instead of returning a different
34/// result silently.
35///
36/// The text form is `<seed>-<data>`, each 16 lowercase hex digits, for
37/// example `00000000000004d2-9ae16a3b2f90404f`. In JSON both parts are
38/// strings, because JavaScript numbers cannot hold every 64-bit value.
40{
41 std::uint64_t seed{0}; ///< The call seed.
42 std::uint64_t data{0}; ///< Hash of the data used; 0 when not recorded.
43
44 /// @brief The text form.
45 /// @return `<seed>-<data>` in 16-digit lowercase hex.
46 [[nodiscard]] std::string to_string() const
47 {
48 return hex(seed) + "-" + hex(data);
49 }
50
51 /// @brief Parse the text form. A lone seed (16 hex digits) is accepted
52 /// with data 0.
53 /// @param text `<seed>-<data>` or `<seed>`.
54 /// @return The signature.
55 /// @throws std::invalid_argument If @p text is not in that form.
56 [[nodiscard]] static seed_signature parse(std::string_view text)
57 {
58 const auto dash = text.find('-');
59 const auto seed = parse_hex(text.substr(0, dash));
60 const auto data = dash == std::string_view::npos
61 ? std::optional<std::uint64_t>{0}
62 : parse_hex(text.substr(dash + 1));
63 if (!seed || !data)
64 {
65 throw std::invalid_argument("seed_signature: expected 16 hex digits, "
66 "optionally followed by '-' and 16 more");
67 }
68 return {.seed = *seed, .data = *data};
69 }
70
71 /// @brief Write as a JSON object `{"seed":"…","data":"…"}`.
72 /// @param w Writer positioned where a value is allowed.
73 void to_json(json_writer& w) const
74 {
75 w.begin_object().field("seed", hex(seed)).field("data", hex(data)).end_object();
76 }
77
78 /// @brief Signatures are equal when seed and data are equal.
79 friend constexpr bool operator==(const seed_signature&, const seed_signature&) noexcept = default;
80
81 private:
82 static std::string hex(std::uint64_t v)
83 {
84 constexpr std::string_view digits = "0123456789abcdef";
85 std::string out(16, '0');
86 for (std::size_t i = 16; i-- > 0;)
87 {
88 out[i] = digits[v & 0xFU];
89 v >>= 4U;
90 }
91 return out;
92 }
93
94 static std::optional<std::uint64_t> parse_hex(std::string_view text)
95 {
96 if (text.size() != 16) return std::nullopt;
97 for (const char c : text)
98 {
99 const bool digit = c >= '0' && c <= '9';
100 const bool lower_hex = c >= 'a' && c <= 'f';
101 if (!digit && !lower_hex) return std::nullopt;
102 }
103 std::uint64_t v = 0;
104 const auto res = std::from_chars(std::to_address(text.begin()), std::to_address(text.end()), v, 16);
105 if (res.ec != std::errc{}) return std::nullopt;
106 return v;
107 }
108};
109
110} // namespace dasmig::core
111
112#endif // DASMIG_CORE_SEED_SIGNATURE_HPP
Builds one JSON document.
Definition json.hpp:49
json_writer & begin_object()
Open an object.
Definition json.hpp:61
json_writer & field(std::string_view name, const V &v)
Write a key and its value.
Definition json.hpp:209
json_writer & end_object()
Close the innermost object.
Definition json.hpp:73
A minimal, dependency-free JSON writer for to_json().
What a result needs to be generated again: its call seed and the data it was generated from.
friend constexpr bool operator==(const seed_signature &, const seed_signature &) noexcept=default
Signatures are equal when seed and data are equal.
void to_json(json_writer &w) const
Write as a JSON object {"seed":"…","data":"…"}.
std::uint64_t seed
The call seed.
std::uint64_t data
Hash of the data used; 0 when not recorded.
static seed_signature parse(std::string_view text)
Parse the text form. A lone seed (16 hex digits) is accepted with data 0.
std::string to_string() const
The text form.