スキップしてメイン コンテンツに移動

ComponentID

Win32のUUID(GUID)構造体のラッパークラス。VS.NET2003付属STLのhashコンテナ(hash_map/hash_set /hash_multimap/hash_multiset)用比較関数、SGI系STLのhashコンテナ用ハッシュ関数オブジェクト付き。システムの用意した構造体を継承してクラスを作るというのは割とよくやる方法で、継承した場合vtableが無ければメモリレイアウトの先頭に継承元が入るので、後ろに追加のデータをペイロードとして付けた上で、親の構造体を引数とするAPIの引数に使えるという利点がある。換言すれば、templateと、template policyを利用したmix-inによって、C++における継承は、Java等のクラスライブラリに顕著な、現実世界やデザインパターンとして観念されるモデルのマッピングに近いカテゴリ概念の素朴な具体化のための道具というよりは、本来の意味でのデータ抽象/アルゴリズム抽象に向けての手段として、あるいはCOMのバイナリ仕様の表現として活用(exploit)される箇所しか出る幕が無くなってしまった。



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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
// ComponentID クラス (c) RyuK
 
#ifndef CALC_COMPONENTID_H
#define CALC_COMPONENTID_H
 
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500 // Windows 2000 以降の機能を使用
#endif _WIN32_WINNT
 
#include <windows.h>
 
// あくまでMS Windows依存。UUID<=>文字列変換はわざわざプラットフォーム
// 依存のAPIに頼る必然性は無いものの、適当なGUIDの生成だけは依存せざる
// を得ない。
// Windowsの場合、最近になってMACアドレスが生成結果から判別できないように
// UUIDを生成できるようになった。Windowsは必要な物は大概
// Platform SDKの中に道具が用意されているので手間の節約のためにできる
// だけ依存することにする。
 
#include <rpc.h> // UUID
 
#include <string>
#include <functional>
#include <hash_map>
#include <hash_set>
 
#ifdef _STLPORT_VERSION // STLport使用時
using namespace std;
#else // VS.NET2003付属STL(Dinkumware)使用時
using namespace std;
using namespace stdext;
#endif
 
// CスタイルUUID文字列クラス(ASCII)(間のハイフン無し)
struct ComponentIDString
{
 ComponentIDString()
 {
  m_szBuffer[32] = 0x00;
 }
 
 ~ComponentIDString() {}
 
 char m_szBuffer[36];
};
 
struct ComponentID : public UUID
{
 typedef unsigned __int64 UInt64;
 
 // デフォルトのコンストラクタ。UUID生成有り
 ComponentID()
 {
  UuidCreate(this);
 }
 
 // UUID生成無し
 ComponentID(bool init) {}
 
 ~ComponentID() {}
 
 // (STLportなどのSGI系STL向けに)hash_mapのキーとするために必要な等
 // 値演算子を定義する
 // MicrosoftがData1等抽象的なメンバ名を付けた理由は不明である
 __forceinline bool operator==(const ComponentID& right) const
 {
  return (
   (*reinterpret_cast<const UInt64*>(&Data1)
   == *reinterpret_cast<const UInt64*>(&(right.Data1)))
   && (*reinterpret_cast<const UInt64*>(&Data4)
   == *reinterpret_cast<const UInt64*>(&(right.Data4)))
  );
 }
 
 // (VS.NET2003付属STL - Dinkumware STL向けに)hash_mapのキーとする
 // ために必要な比較演算子を定義する。
 __forceinline bool operator<(const ComponentID& right) const
 {
  if (*reinterpret_cast<const UInt64*>(&Data4)
  < *reinterpret_cast<const UInt64*>(&(right.Data4)))
   return true;
  else if (*reinterpret_cast<const UInt64*>(&Data4)
  > *reinterpret_cast<const UInt64*>(&(right.Data4)))
   return false;
  else {
  return (*reinterpret_cast<const UInt64*>(&Data1)
   < *reinterpret_cast<const UInt64*>(&(right.Data1)));
  }
 }
 
 // VS.NET2003付属STL - Dinkumware STL向けに必要なハッシュ関数をsize_t
 // へのキャスト演算子として定義する
#ifndef _STLPORT_VERSION
 __forceinline operator size_t() const
 { // Win32APIをUnix上で実装するWine ProjectがUuidHashで借用している
  // FreeDCEのコードを又借り
  const BYTE* data = reinterpret_cast<const BYTE*>(this);
  short c0 = 0;
  short c1 = 0;
  for (DWORD i = 0; i < sizeof(UUID); ++i) {
   c0 += data[i];
   c1 += c0;
  }
 
  short x = -c1 % 255;
  if (x < 0)
   x += 255;
 
  short y = (c1 - c0) % 255;
  if (y < 0)
   y += 255;
 
  return y * 256 + x;
 }
#endif
 
 __forceinline ComponentID& operator=(const ComponentID& right)
 {
  if (&right != this) {
   CopyMemory(this, &right, sizeof(ComponentID));
  }
 
  return *this;
 }
 
 __forceinline const ComponentID& initialize()
 {
  UuidCreate(this);
  return *this;
 }
 
 // ハイフン入りASCII文字列として文字列化。sprintfなんかより実はこちら
 // の方がかなり速い
 string toString() const
 {
  unsigned char* pszUuid;
  UuidToStringA(
   const_cast<ComponentID*>(this),
   &pszUuid
  );
  string result(reinterpret_cast<char*>(pszUuid));
  RpcStringFreeA(&pszUuid);
  return result;
 }
 
 // ハイフン無し文字列としてComponentIDStringへエクスポート
 // (バイトオーダーを変換)
 void toString(ComponentIDString& dst) const
 {
  const char szHexTable[] = "0123456789abcdef";
  const BYTE* s
  = reinterpret_cast<BYTE*>(const_cast<ComponentID*>(this));
 
  dst.m_szBuffer[0] = szHexTable[s[3] >> 4];
  dst.m_szBuffer[1] = szHexTable[s[3] & 15];
  dst.m_szBuffer[2] = szHexTable[s[2] >> 4];
  dst.m_szBuffer[3] = szHexTable[s[2] & 15];
  dst.m_szBuffer[4] = szHexTable[s[1] >> 4];
  dst.m_szBuffer[5] = szHexTable[s[1] & 15];
  dst.m_szBuffer[6] = szHexTable[s[0] >> 4];
  dst.m_szBuffer[7] = szHexTable[s[0] & 15];
 
  dst.m_szBuffer[8] = szHexTable[s[5] >> 4];
  dst.m_szBuffer[9] = szHexTable[s[5] & 15];
  dst.m_szBuffer[10] = szHexTable[s[4] >> 4];
  dst.m_szBuffer[11] = szHexTable[s[4] & 15];
 
  dst.m_szBuffer[12] = szHexTable[s[7] >> 4];
  dst.m_szBuffer[13] = szHexTable[s[7] & 15];
  dst.m_szBuffer[14] = szHexTable[s[6] >> 4];
  dst.m_szBuffer[15] = szHexTable[s[6] & 15];
 
  dst.m_szBuffer[16] = szHexTable[Data4[0] >> 4];
  dst.m_szBuffer[17] = szHexTable[Data4[0] & 15];
  dst.m_szBuffer[18] = szHexTable[Data4[1] >> 4];
  dst.m_szBuffer[19] = szHexTable[Data4[1] & 15];
  dst.m_szBuffer[20] = szHexTable[Data4[2] >> 4];
  dst.m_szBuffer[21] = szHexTable[Data4[2] & 15];
  dst.m_szBuffer[22] = szHexTable[Data4[3] >> 4];
  dst.m_szBuffer[23] = szHexTable[Data4[3] & 15];
  dst.m_szBuffer[24] = szHexTable[Data4[4] >> 4];
  dst.m_szBuffer[25] = szHexTable[Data4[4] & 15];
  dst.m_szBuffer[26] = szHexTable[Data4[5] >> 4];
  dst.m_szBuffer[27] = szHexTable[Data4[5] & 15];
  dst.m_szBuffer[28] = szHexTable[Data4[6] >> 4];
  dst.m_szBuffer[29] = szHexTable[Data4[6] & 15];
  dst.m_szBuffer[30] = szHexTable[Data4[7] >> 4];
  dst.m_szBuffer[31] = szHexTable[Data4[7] & 15];
 }
 
 // ハイフン入りASCII文字列からインポート
 __forceinline bool importFromString(const string& s)
 {
  return (UuidFromStringA(
  reinterpret_cast<unsigned char*>(const_cast<char*>(s.c_str())),
  (UUID*)this
  ) == RPC_S_OK);
 }
 
 // ハイフン無しASCII文字列からインポート。s.size() >= 32に留意せよ
 bool importFromStringWithoutHyphen(const string& s)
 {
  char szBuffer[] = {0, 0, 0, 0, 0, 0, 0, 0,
   '-', 0, 0, 0, 0,
   '-', 0, 0, 0, 0,
   '-', 0, 0, 0, 0,
   '-', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0
  };
 
  CopyMemory(&szBuffer[0], s.data(), 8);
  CopyMemory(&szBuffer[9], s.data() + 8, 4);
  CopyMemory(&szBuffer[14], s.data() + 12, 4);
  CopyMemory(&szBuffer[19], s.data() + 16, 4);
  CopyMemory(&szBuffer[24], s.data() + 20, 12);
 
  return (UuidFromStringA(
   reinterpret_cast<unsigned char*>(&szBuffer[0]),
   (UUID*)this
  ) == RPC_S_OK);
 }
};
 
// SGI系STL(STLport他)でhash_map等のキーとしてComponentIDを使用するためのhasher
// 関数オブジェクト
 
#include <functional>
#include <hash_map>
#include <hash_set>
 
struct ComponentIDHasher : public unary_function<ComponentID, size_t>
{
 // Win32APIをUnix上で実装するWine ProjectがUuidHashで借用している
 // FreeDCEのコードを又借り
__forceinline size_t operator()(const ComponentID& arg) const
{
 const BYTE* data = reinterpret_cast<const BYTE*>(&arg);
 short c0 = 0;
 short c1 = 0;
 for (DWORD i = 0; i < sizeof(UUID); ++i) {
  c0 += data[i];
  c1 += c0;
 }
 
 short x = -c1 % 255;
 if (x < 0)
  x += 255;
 
 short y = (c1 - c0) % 255;
 if (y < 0)
  y += 255;
 
 return y * 256 + x;
}
};
 
/*
// 別バージョン - UuidHash使用
 
class ComponentIDHasher : public unary_function<ComponentID, size_t>
{
private:
mutable RPC_STATUS m_rpc_status;
public:
ComponentIDHasher() {}
~ComponentIDHasher() {}
 
// 都合良くUuidHashなるAPI(128bit->16bit)が用意されているのでそれを使用。
// C++のconstは重要なDesign by Contractの手段である。
// ここではテンプレートの要求に応えるために引数のみならず関数もconst指定する
// 必要がある
size_t operator()(const ComponentID& arg) const
{
 return static_cast<size_t>(
 UuidHash(
  reinterpret_cast<UUID*>(const_cast<ComponentID*>(&arg)),
  &m_rpc_status
 )
 );
}
};
*/
 
#ifdef _STLPORT_VERSION
typedef hash_set<ComponentID, ComponentIDHasher> ComponentIDSet;
typedef hash_map<ComponentID, DWORD, ComponentIDHasher> ComponentID2DWORD;
typedef hash_map<ComponentID, ComponentID, ComponentIDHasher>
 ComponentID2ComponentID;
typedef hash_map<string, ComponentID> String2ComponentID;
typedef hash_map<ComponentID, string, ComponentIDHasher> ComponentID2String;
#else
typedef hash_set<ComponentID> ComponentIDSet;
typedef hash_map<ComponentID, DWORD> ComponentID2DWORD;
typedef hash_map<ComponentID, ComponentID> ComponentID2ComponentID;
typedef hash_map<string, ComponentID> String2ComponentID;
typedef hash_map<ComponentID, string> ComponentID2String;
#endif
 
#endif CALC_COMPONENTID_H

コメント