1 // Copyright 2020 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 THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABILITY_INTERNAL_TEMPLATES_H_
6 #define THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABILITY_INTERNAL_TEMPLATES_H_
7
8 #include <cstdint>
9 #include <cstring>
10 #include <type_traits>
11
12 namespace blink {
13
14 namespace internal {
15
16 // Handroll a remove_cv_t until we get to C++20.
17 template <typename T>
18 using remove_cvref_t = typename std::remove_cv_t<std::remove_reference_t<T>>;
19
20 // Kinda conservative implementation of
21 // std::has_unique_object_representations<>. Perhaps not as conservative as we'd
22 // like.
23 //
24 // At a minimum, this predicate should require that the data type not contain
25 // internal padding since uninitialized padding bytes defeat the uniqueness of
26 // the representation. Trailing padding is allowed.
27 //
28 // Not checking <version> because we don't want to use the feature
29 // automatically. We should wait until C++-17 library functionality is
30 // explicitly allowed in Chromium.
31 template <typename T>
32 using has_unique_object_representations = std::is_arithmetic<T>;
33
34 // Calculate a digest of an object with a unique representation.
35 //
36 // In a perfect world, we should also require that this representation be
37 // portable or made to be portable. Such a transformation could be done, for
38 // example, by adopting a consistent byte ordering on all platforms.
39 //
40 // This function should only be invoked on a bare (sans qualifiers and
41 // references) type for the sake of simplicity.
42 //
43 // Should not be used as a primitive for manually constructing a unique
44 // representation. For such cases, use the byte-wise digest functions instead.
45 //
46 // Should not be used outside of the narrow use cases in this file.
47 //
48 // This implementation does not work for x86 extended precision floating point
49 // numbers. These are 80-bits wide, but in practice includes 6 bytes of padding
50 // in order to extend the size to 16 bytes. The extra bytes are uninitialized
51 // and will not contribute a stable digest.
52 template <
53 typename T,
54 typename std::enable_if_t<std::is_same<T, remove_cvref_t<T>>::value &&
55 std::is_trivially_copyable<T>::value &&
56 has_unique_object_representations<T>::value &&
57 sizeof(T) <= sizeof(int64_t)>* = nullptr>
DigestOfObjectRepresentation(T in)58 constexpr int64_t DigestOfObjectRepresentation(T in) {
59 // If |in| is small enough, the digest is itself. There's no point hashing
60 // this value since the identity has all the properties we are looking for
61 // in a digest.
62 if (std::is_integral<T>::value && std::is_signed<T>::value)
63 return in;
64
65 if (std::is_integral<T>::value && sizeof(T) < sizeof(int64_t))
66 return in;
67
68 int64_t result = 0;
69 std::memcpy(&result, &in, sizeof(in));
70 return result;
71 }
72
73 } // namespace internal
74
75 } // namespace blink
76
77 #endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABILITY_INTERNAL_TEMPLATES_H_
78