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