aboutsummaryrefslogtreecommitdiff
path: root/libbutl/uuid.hxx
blob: 25861d9e662a19d7ec459fe38832df61a41758da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
// file      : libbutl/uuid.hxx -*- C++ -*-
// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#pragma once

#include <array>
#include <string>
#include <cstdint>
#include <functional> // hash

#include <libbutl/export.hxx>
#include <libbutl/version.hxx>

#ifdef _WIN32
struct _GUID; // GUID and UUID.
#endif

namespace butl
{
  // Universally-unique identifier (UUID), RFC4122:
  //
  // https://tools.ietf.org/html/rfc4122

  // The UUID variant (type). Nil UUID is DCE.
  //
  enum class uuid_variant
  {
    ncs,       // NCS backward compatibility.
    dce,       // DCE 1.1/RFC4122.
    microsoft, // Microsoft backward compatibility.
    other      // Currently reserved for possible future definition.
  };

  // The DCE UUID version (sub-type). Nil UUID is random.
  //
  enum class uuid_version
  {
    time     = 1, // Time-based.
    security = 2, // DCE Security with embedded POSIX UIDs.
    md5      = 3, // Name-based with MD5 hashing.
    random   = 4, // Randomly or pseudo-randomly generated.
    sha1     = 5  // Name-based with SHA1 hashing.
  };

  class LIBBUTL_SYMEXPORT uuid_system_generator;

  struct LIBBUTL_SYMEXPORT uuid
  {
    // Normally not accessed directly (see RFC4122 Section 4.1.2).
    //
    std::uint32_t  time_low = 0;
    std::uint16_t  time_mid = 0;
    std::uint16_t  time_hiv = 0;       // hi_and_version
    std::uint8_t   clock_seq_hir = 0;  // hi_and_reserved
    std::uint8_t   clock_seq_low = 0;
    std::uint8_t   node[6] = {0, 0, 0, 0, 0, 0};

    // System UUID generator. See the uuid_generator interface for details.
    //
    // Note: system generator cannot be called during static initialization.
    //
    static uuid_system_generator system_generator;

    static uuid
    generate (bool strong = true);

    // Create a nil UUID (all members are 0).
    //
    uuid () = default;

    bool
    nil () const;

    explicit operator bool () const;

    // Create a UUID from a 16-octet binary representation with the sizes and
    // order of the fields as defined in RFC4122 Section 4.1.2 and with each
    // field encoded with the most significant byte first (also known as
    // big-endian or network byte order).
    //
    using binary_type = std::array<std::uint8_t, 16>;

    explicit
    uuid (const binary_type&);

    void
    assign (const binary_type&);

    binary_type
    binary () const noexcept;

    // Note that this constructor is compatible with libuuid's uuid_t type.
    //
    explicit
    uuid (const std::uint8_t (&)[16]);

    void
    assign (const std::uint8_t (&)[16]);

#ifdef _WIN32
    // Create a UUID from Win32 GUID.
    //
    uuid (const _GUID&);

    void
    assign (const _GUID&);

    template <typename G = _GUID>
    G
    guid () const;
#endif

    // Create a UUID from a 36-character string representation in the
    //
    //   xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    //
    // form which can be in lower or upper case. Throw std::invalid_argument
    // if the representation is invalid.
    //
    // The returned string representation is by default in lower case.
    //
    explicit
    uuid (const std::string&);

    explicit
    uuid (const char*);

    void
    assign (const std::string&);

    void
    assign (const char*);

    std::string
    string (bool upper = false) const;

    std::array<char, 37>
    c_string (bool upper = false) const;

    // UUID variant (type) and version (sub-type).
    //
    using variant_type = uuid_variant;
    using version_type = uuid_version;

    variant_type
    variant () const;

    version_type
    version () const;

    // UUID comparison.
    //
    int
    compare (const uuid&) const;

    // Swapping and moving. On move we make the moved-from instance nil.
    //
    void
    swap (uuid&);

    uuid (uuid&&);
    uuid (const uuid&) = default;

    uuid& operator= (uuid&&);
    uuid& operator= (const uuid&) = default;
  };

  bool operator== (const uuid&, const uuid&);
  bool operator!= (const uuid&, const uuid&);
  bool operator<  (const uuid&, const uuid&);
  bool operator>  (const uuid&, const uuid&);
  bool operator<= (const uuid&, const uuid&);
  bool operator>= (const uuid&, const uuid&);

  // For iostream operators see uuid-io.hxx.

  // UUID generator interface.
  //
  class LIBBUTL_SYMEXPORT uuid_generator
  {
  public:
    virtual
    ~uuid_generator () = default;

    // Generate a UUID. If strong is true (default), generate a strongly-
    // unique UUID. Throw std::runtime_error to report errors, including if
    // strong uniqueness cannot be guaranteed.
    //
    // A weak UUID is not guaranteed to be unique, neither universialy nor
    // locally (that is, on the machine it has been generated).
    //
    virtual uuid
    generate (bool strong = true) = 0;
  };

  // System UUID generator.
  //
  class LIBBUTL_SYMEXPORT uuid_system_generator: public uuid_generator
  {
  public:
    // Throw std::system_error with the generic category and ENOTSUP error
    // code if strong uniqueness cannot be guaranteed.
    //
    virtual uuid
    generate (bool strong = true) override;

    // Optional explicit initialization and termination. Note that it is not
    // thread-safe and must only be performed once (normally from main())
    // before/after any calls to generate(), respectively. Both functions may
    // throw std::runtime_error to report errors.
    //
    static void
    initialize ();

    static void
    terminate ();
  };
}

namespace std
{
  template <>
  struct hash<butl::uuid>
  {
    using argument_type = butl::uuid;
    using result_type = size_t;

    size_t
    operator() (const butl::uuid&) const noexcept;
  };
}

#include <libbutl/uuid.ixx>