OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef CONTENT_BROWSER_DOWNLOAD_ID_TYPE_H_ | |
6 #define CONTENT_BROWSER_DOWNLOAD_ID_TYPE_H_ | |
ncarter (slow)
2016/01/07 00:48:50
Let's put this in content/common for now.
Łukasz Anforowicz
2016/01/07 18:02:13
Done.
| |
7 | |
8 #include <ostream> | |
9 | |
10 #include "base/containers/hash_tables.h" | |
11 | |
12 // Problem: | |
13 // | |
14 // void f(int foo_id, int bar_id); | |
15 // ... | |
16 // // Arguments passed in a wrong order: | |
17 // f(bar_id, foo_id); // Compiles - sigh... :-( | |
18 // | |
19 // Solution: | |
20 // | |
21 // using FooId = content::IdType<Foo, uint64_t, 0>; | |
22 // using BarId = content::IdType<Bar, uint64_t, 0>; | |
ncarter (slow)
2016/01/07 00:48:50
Id prefer if we had a design that didn't require t
Łukasz Anforowicz
2016/01/07 18:02:12
I agree that this is desirable, although:
1) I wo
ncarter (slow)
2016/01/07 20:14:32
I like this idea, a lot.
It looks like, in existi
Łukasz Anforowicz
2016/01/07 21:43:01
Done. (changed IdType32/64 to wrap a signed integ
| |
23 // void f(FooId foo_id, BarId bar_id); | |
24 // ... | |
25 // // Arguments passed in a wrong order: | |
26 // f(bar_id, foo_id); // Doesn't compile anymore - yay! :-) | |
27 // | |
28 // Typically FooId would be declared like this: | |
29 // | |
30 // foo_id.h: | |
31 // | |
32 // #include "content/browser/download/id_type.h" | |
33 // | |
34 // namespace foo_namespace { | |
35 // | |
36 // class Foo; | |
37 // using FooId = content::IdType<Foo, uint64_t, 0>; | |
38 // | |
39 // } // namespace foo_namespace | |
40 // | |
41 // For most practical purposes, FooId declared like above behaves just like | |
42 // an uint64_t, except that: | |
43 // | |
44 // 1. FooId only supports a subset of uint64_t operations: | |
45 // - ==, !=, <, hashing | |
46 // - stream output | |
47 // - copy construction and assignment | |
48 // | |
49 // 2. FooId does not implicitly coerce to/from other uint64_t values and | |
50 // to/from content::IdType<SomeOtherType, ...>. Explicit coercion to/from | |
51 // uint64_t is possible through the following FooId methods: | |
52 // - static FooId FromUnsafeValue(uint64_t) | |
53 // - uint64_t GetUnsafeValue() | |
54 // | |
55 // 3. Default-constructed FooId contains a "null" / "invalid" value specified | |
56 // by the 3rd argument of the IdType<...> template. Testing against this | |
57 // value can be done by the following FooId methods: | |
58 // - bool is_valid() | |
59 // - bool is_null() | |
60 // | |
61 // 4. The presence of a custom default constructor means that FooId is not a | |
62 // "trivial" class and therefore is not a POD type (unlike an uint64_t). | |
63 // At the same time FooId has almost all of the properties of a POD type: | |
64 // - is "trivially copyable" (i.e. is memcpy-able), | |
65 // - has "standard layout" (i.e. interops with things expecting C layout). | |
66 // See http://stackoverflow.com/a/7189821 for more info about these | |
67 // concepts. | |
68 | |
69 namespace content { | |
70 | |
71 template <typename TypeMarker, typename WrappedType, WrappedType kInvalidValue> | |
ncarter (slow)
2016/01/07 00:48:50
I don't really know C++ templates well, so I wonde
Łukasz Anforowicz
2016/01/07 18:02:12
I've tried this ans got an error:
../../content/co
ncarter (slow)
2016/01/07 20:14:32
I really like the solution of expose a ready-to-us
Łukasz Anforowicz
2016/01/07 21:43:01
Acknowledged.
| |
72 struct IdType { | |
ncarter (slow)
2016/01/07 00:48:50
why struct? IdType has no public data members.
Łukasz Anforowicz
2016/01/07 18:02:13
I changed to a class.
RE: why
No particular reas
| |
73 public: | |
74 IdType() : value_(kInvalidValue) {} | |
75 bool is_valid() const { return value_ != kInvalidValue; } | |
76 bool is_null() const { return value_ == kInvalidValue; } | |
77 | |
78 static IdType FromUnsafeValue(WrappedType value) { return IdType(value); } | |
79 WrappedType GetUnsafeValue() const { return value_; } | |
80 | |
81 IdType(const IdType& other) = default; | |
82 IdType& operator=(const IdType& other) = default; | |
83 | |
84 bool operator==(const IdType& other) const { return value_ == other.value_; } | |
85 bool operator!=(const IdType& other) const { return value_ != other.value_; } | |
86 bool operator<(const IdType& other) const { return value_ < other.value_; } | |
87 | |
88 protected: | |
89 explicit IdType(WrappedType val) : value_(val) {} | |
90 | |
91 private: | |
92 WrappedType value_; | |
93 }; | |
94 | |
95 template <typename TypeMarker, typename WrappedType, WrappedType kInvalidValue> | |
96 std::ostream& operator<<( | |
97 std::ostream& stream, | |
98 const IdType<TypeMarker, WrappedType, kInvalidValue>& id) { | |
99 return stream << id.GetUnsafeValue(); | |
100 } | |
101 | |
102 } // namespace content | |
103 | |
104 namespace BASE_HASH_NAMESPACE { | |
105 | |
106 template <typename TypeMarker, typename WrappedType, WrappedType kInvalidValue> | |
107 struct hash<content::IdType<TypeMarker, WrappedType, kInvalidValue>> { | |
108 using argument_type = content::IdType<TypeMarker, WrappedType, kInvalidValue>; | |
109 using result_type = std::size_t; | |
110 result_type operator()(const argument_type& id) const { | |
111 return BASE_HASH_NAMESPACE::hash<WrappedType>()(id.GetUnsafeValue()); | |
112 } | |
113 }; | |
114 | |
115 } // namespace BASE_HASH_NAMESPACE | |
116 | |
117 // If defined(COMPILER_MSVC) then BASE_HASH_NAMESPACE == std. | |
118 // In this case we need to avoid defininig std::hash<...> second time | |
119 // (it has already been defined above). | |
120 #if !defined(COMPILER_MSVC) | |
121 | |
122 namespace std { | |
123 | |
124 template <typename TypeMarker, typename WrappedType, WrappedType kInvalidValue> | |
125 struct hash<content::IdType<TypeMarker, WrappedType, kInvalidValue>> { | |
126 using argument_type = content::IdType<TypeMarker, WrappedType, kInvalidValue>; | |
127 using result_type = std::size_t; | |
128 result_type operator()(const argument_type& id) const { | |
129 return std::hash<WrappedType>()(id.GetUnsafeValue()); | |
130 } | |
131 }; | |
132 | |
133 } // namespace std; | |
134 | |
135 #endif // !defined(COMPILER_MSVC) | |
136 | |
137 #endif // CONTENT_BROWSER_DOWNLOAD_ID_TYPE_H_ | |
OLD | NEW |