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 | |
20 | namespace FASTER { |
21 | namespace core { |
22 | |
23 | /// Wrapper for GUIDs, for Windows and Linux. |
24 | class 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. |
140 | namespace std { |
141 | template<> |
142 | struct hash<FASTER::core::Guid> { |
143 | size_t operator()(const FASTER::core::Guid& val) const { |
144 | return val.GetHashCode(); |
145 | } |
146 | }; |
147 | } |
148 | |