1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license.
3
4#pragma once
5
6#include <cassert>
7#include <cstdint>
8#include <cstring>
9#include <functional>
10#include <string>
11
12#ifdef _WIN32
13#define NOMINMAX
14#define _WINSOCKAPI_
15#include <Windows.h>
16#else
17#include <uuid/uuid.h>
18#endif
19
20namespace FASTER {
21namespace core {
22
23/// Wrapper for GUIDs, for Windows and Linux.
24class Guid {
25 public:
26#ifdef _WIN32
27 Guid() {
28 guid_.Data1 = 0;
29 guid_.Data2 = 0;
30 guid_.Data3 = 0;
31 std::memset(guid_.Data4, 0, 8);
32 }
33#else
34 Guid() {
35 uuid_clear(uuid_);
36 }
37#endif
38
39 private:
40#ifdef _WIN32
41 Guid(const GUID& guid)
42 : guid_{ guid } {
43 }
44#else
45 Guid(const uuid_t uuid) {
46 uuid_copy(uuid_, uuid);
47 }
48#endif
49
50 public:
51 static Guid Create() {
52#ifdef _WIN32
53 GUID guid;
54 HRESULT result = ::CoCreateGuid(&guid);
55 assert(result == S_OK);
56 return guid;
57#else
58 uuid_t uuid;
59 uuid_generate(uuid);
60 return uuid;
61#endif
62 }
63
64 static Guid Parse(const std::string str) {
65#ifdef _WIN32
66 GUID guid;
67 auto result = ::UuidFromString(reinterpret_cast<uint8_t*>(const_cast<char*>(str.c_str())),
68 &guid);
69 assert(result = RPC_S_OK);
70 return guid;
71#else
72 uuid_t uuid;
73 int result = uuid_parse(const_cast<char*>(str.c_str()), uuid);
74 assert(result == 0);
75 return uuid;
76#endif
77 }
78
79 std::string ToString() const {
80 char buffer[37];
81#ifdef _WIN32
82 size_t offset = sprintf(buffer, "%.8lX-%.4hX-%.4hX-", guid_.Data1, guid_.Data2, guid_.Data3);
83 for(size_t idx = 0; idx < 2; ++idx) {
84 offset += sprintf(buffer + offset, "%.2hhX", guid_.Data4[idx]);
85 }
86 offset += sprintf(buffer + offset, "-");
87 for(size_t idx = 2; idx < sizeof(guid_.Data4); ++idx) {
88 offset += sprintf(buffer + offset, "%.2hhX", guid_.Data4[idx]);
89 }
90 buffer[36] = '\0';
91#else
92 uuid_unparse(uuid_, buffer);
93#endif
94 return std::string { buffer };
95 }
96
97 bool operator==(const Guid& other) const {
98#ifdef _WIN32
99 return guid_.Data1 == other.guid_.Data1 &&
100 guid_.Data2 == other.guid_.Data2 &&
101 guid_.Data3 == other.guid_.Data3 &&
102 std::memcmp(guid_.Data4, other.guid_.Data4, 8) == 0;
103#else
104 return uuid_compare(uuid_, other.uuid_) == 0;
105#endif
106 }
107
108 uint32_t GetHashCode() const {
109#ifdef _WIN32
110 // From C#, .NET Reference Framework.
111 return guid_.Data1 ^ ((static_cast<uint32_t>(guid_.Data2) << 16) |
112 static_cast<uint32_t>(guid_.Data3)) ^
113 ((static_cast<uint32_t>(guid_.Data4[2]) << 24) | guid_.Data4[7]);
114#else
115 uint32_t Data1;
116 uint16_t Data2;
117 uint16_t Data3;
118 std::memcpy(&Data1, uuid_, sizeof(Data1));
119 std::memcpy(&Data2, uuid_ + 4, sizeof(Data2));
120 std::memcpy(&Data3, uuid_ + 6, sizeof(Data3));
121 // From C#, .NET Reference Framework.
122 return Data1 ^ ((static_cast<uint32_t>(Data2) << 16) |
123 static_cast<uint32_t>(Data3)) ^
124 ((static_cast<uint32_t>(uuid_[10]) << 24) | uuid_[15]);
125#endif
126 }
127
128 private:
129#ifdef _WIN32
130 GUID guid_;
131#else
132 uuid_t uuid_;
133#endif
134};
135
136}
137} // namespace FASTER::core
138
139/// Implement std::hash<> for GUIDs.
140namespace std {
141template<>
142struct hash<FASTER::core::Guid> {
143 size_t operator()(const FASTER::core::Guid& val) const {
144 return val.GetHashCode();
145 }
146};
147}
148