Chromium Code Reviews| 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 |