|
1 | 1 | Hash functions in C++ |
2 | 2 | ===================== |
3 | 3 |
|
4 | | -TODO: #1431 |
5 | | - |
6 | | -For types marked as `Equatable` Gluecodium will also generate a hash function. It appears most |
7 | | -convenient to generate `hash` for custom types in `std` namespace. Sadly STL does not provide |
8 | | -`hash` for containers used by Gluecodium, i.e. `vector`, `unordered_map` and `unordered_set`. In order to |
9 | | -not conflict with any library providing these, Gluecodium should not provide hash functionality for these |
10 | | -in `std` namespace. Gluecodium also distinguishes between `Equatable` and `PointerEquatable` for classes, |
11 | | -which should result in different hashing for `shared_ptr` of the classes. This would conflict with |
12 | | -STL which already defines hash for `shared_ptr` thus might lead to conflicts in generated code. All |
13 | | -in all it is much more consistent if Gluecodium uses `hash` in internal namespace which is implemented |
14 | | -in a way to fallback to `std::hash` if no specialization is available, reusing hash for primitive |
15 | | -types. |
| 4 | +For types marked as `Equatable`, Gluecodium will generate a C++ hash function in addition to any equality operators. It |
| 5 | +may seem most convenient to generate the `hash` function for custom types in the `std` namespace. Unfortunately, C++ |
| 6 | +standard library (STL) does not provide `std::hash` for container types: `vector`, `unordered_map` and `unordered_set`. |
| 7 | +To avoid conflict with any third-party library providing these container hashes, the decision was made to provide such |
| 8 | +Gluecodium hashes in a custom namespace instead. The custom hash falls through to `std::hash` for types, where it is |
| 9 | +available. |
| 10 | + |
| 11 | +Main hash function |
| 12 | +------------------ |
| 13 | + |
| 14 | +`gluecodium::hash` function, generated in a custom namespace, provides the hashing functionality for |
| 15 | +Gluecodium-generated code. The main function itself is a template with no logic of its own. The logic is provided either |
| 16 | +by a generated specialization, or by the fall-though template selector: |
| 17 | +* `gluecodium::hash` specialization is used, if available. Otherwise, |
| 18 | +* for enumerations, the trivial `EnumHash` is used, returning the enumerator value as the hash value; |
| 19 | +* for shared pointer, a specialization of `EqualityHash` template is used, if available (see below); |
| 20 | +* `std::hash` is used, if available. |
| 21 | +* if none of the above works, compilation fails (normally, this never happens). |
| 22 | + |
| 23 | +Manual implementation |
| 24 | +--------------------- |
| 25 | + |
| 26 | +When a `class` or `interface` is marked with `@Equatable` in LIME IDL definitions, a `gluecodium::hash` specialization |
| 27 | +has to be implemented manually (next to the rest of the manual "logic" code). When this specialization is implemented, |
| 28 | +the main `gluecodium::hash` template uses it through the custom "shared pointer hash" template (see below). |
| 29 | + |
| 30 | +Shared pointer hash |
| 31 | +------------------- |
| 32 | + |
| 33 | +The standard `std::hash` does exist for `std::shared_ptr`. It computes the hash value based on the raw pointer value. |
| 34 | +However, for `@Equatable` classes the working assumption is: if an instance of this is somehow "equatable" based on its |
| 35 | +internal state, it also would be "hashable" based on the same state. Therefore, for such classes `gluecodium::hash` main |
| 36 | +template falls through to `EqualityHash` custom shared pointer hash. `EqualityHash`, in turn, uses the manually |
| 37 | +implemented specialization `gluecodium::hash` (see above), that is expected to perform this "internal state hashing". |
| 38 | + |
| 39 | +Container hashes |
| 40 | +---------------- |
| 41 | + |
| 42 | +The `gluecodium::hash` template has specializations for several container types: `std::vector`, `std::unordered_set`, |
| 43 | +and `std::unordered_map`. For vector and set types, the hash value is calculated based on hash values of individual |
| 44 | +elements in the container. For the map type, the hash value is calculated based on both the keys and the values in the |
| 45 | +map. |
| 46 | + |
| 47 | +Struct hash |
| 48 | +----------- |
| 49 | + |
| 50 | +`@Equatable` structs have a generated specialization of the `gluecodium::hash` template. The hash value is calculated |
| 51 | +based on hash values of individual struct fields. |
| 52 | + |
| 53 | +Other custom hashes |
| 54 | +------------------- |
| 55 | + |
| 56 | +The `gluecodium::hash` template also has specializations for `std::chrono::duration` and `std::chrono::time_point`. The |
| 57 | +custom Gluecodium type `Locale` has a dedicated hash specialization too. |
0 commit comments