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_IDENTIFIABLE_SURFACE_H_
6 #define THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABLE_SURFACE_H_
7 
8 #include <stdint.h>
9 
10 #include <cstddef>
11 #include <functional>
12 #include <tuple>
13 
14 #include "third_party/blink/public/common/common_export.h"
15 
16 namespace blink {
17 
18 // An identifiable surface.
19 //
20 // This class intends to be a lightweight wrapper over a simple integer. It
21 // exhibits the following characteristics:
22 //
23 //   * All methods are constexpr.
24 //   * Immutable.
25 //   * Efficient enough to pass by value.
26 //
27 class IdentifiableSurface {
28  public:
29   // Type of identifiable surface.
30   //
31   // Even though the data type is uint64_t, we can only use 8 bits due to how we
32   // pack the surface type and a digest of the input into a 64 bits. See
33   // README.md in this directory for details on encoding.
34   //
35   // These values are used for aggregation across versions. Entries should not
36   // be renumbered and numeric values should never be reused.
37   enum class Type : uint64_t {
38     // This type is reserved for internal use and should not be used for
39     // reporting any identifiability metrics.
40     kReservedInternal = 0,
41 
42     // Input is a mojom::WebFeature
43     kWebFeature = 1,
44 
45     // We can use values up to and including |kMax|.
46     kMax = 0xff
47   };
48 
49   // Construct an IdentifiableSurface based on a precalculated metric hash. Can
50   // also be used as the first step in decoding an encoded metric hash.
FromMetricHash(uint64_t metric_hash)51   static constexpr IdentifiableSurface FromMetricHash(uint64_t metric_hash) {
52     return IdentifiableSurface(metric_hash);
53   }
54 
55   // Construct an IdentifiableSurface based on a surface type and an input hash.
FromTypeAndInput(Type type,uint64_t input)56   static constexpr IdentifiableSurface FromTypeAndInput(Type type,
57                                                         uint64_t input) {
58     return IdentifiableSurface(KeyFromSurfaceTypeAndInput(type, input));
59   }
60 
61   // Returns the UKM metric hash corresponding to this IdentifiableSurface.
ToUkmMetricHash()62   constexpr uint64_t ToUkmMetricHash() const { return metric_hash_; }
63 
64   // Returns the type of this IdentifiableSurface.
GetType()65   constexpr Type GetType() const {
66     return std::get<0>(SurfaceTypeAndInputFromMetricKey(metric_hash_));
67   }
68 
69   // Returns the input hash for this IdentifiableSurface.
70   //
71   // The value that's returned can be different from what's used for
72   // constructing the IdentifiableSurface via FromTypeAndInput() if the input is
73   // >= 2^56.
GetInputHash()74   constexpr uint64_t GetInputHash() const {
75     return std::get<1>(SurfaceTypeAndInputFromMetricKey(metric_hash_));
76   }
77 
78  private:
79   // Returns a 64-bit metric key given an IdentifiableSurfaceType and a 64 bit
80   // input digest.
81   //
82   // The returned key can be used as the metric hash when invoking
83   // UkmEntryBuilderBase::SetMetricInternal().
KeyFromSurfaceTypeAndInput(Type type,uint64_t input)84   static constexpr uint64_t KeyFromSurfaceTypeAndInput(Type type,
85                                                        uint64_t input) {
86     uint64_t type_as_int = static_cast<uint64_t>(type);
87     return type_as_int | (input << 8);
88   }
89 
90   // Returns the IdentifiableSurfaceType and the input hash given a metric key.
91   //
92   // This is approximately the inverse of MetricKeyFromSurfaceTypeAndInput().
93   // See caveat in GetInputHash() about cases where the input hash can differ
94   // from that used to construct this IdentifiableSurface.
SurfaceTypeAndInputFromMetricKey(uint64_t metric)95   static constexpr std::tuple<Type, uint64_t> SurfaceTypeAndInputFromMetricKey(
96       uint64_t metric) {
97     return std::make_tuple(static_cast<Type>(metric & 0xff), metric >> 8);
98   }
99 
100  private:
IdentifiableSurface(uint64_t metric_hash)101   constexpr explicit IdentifiableSurface(uint64_t metric_hash)
102       : metric_hash_(metric_hash) {}
103   uint64_t metric_hash_;
104 };
105 
106 constexpr bool operator<(const IdentifiableSurface& left,
107                          const IdentifiableSurface& right) {
108   return left.ToUkmMetricHash() < right.ToUkmMetricHash();
109 }
110 
111 constexpr bool operator==(const IdentifiableSurface& left,
112                           const IdentifiableSurface& right) {
113   return left.ToUkmMetricHash() == right.ToUkmMetricHash();
114 }
115 
116 constexpr bool operator!=(const IdentifiableSurface& left,
117                           const IdentifiableSurface& right) {
118   return left.ToUkmMetricHash() != right.ToUkmMetricHash();
119 }
120 
121 // Hash function compatible with std::hash.
122 struct IdentifiableSurfaceHash {
operatorIdentifiableSurfaceHash123   size_t operator()(const IdentifiableSurface& s) const {
124     return std::hash<uint64_t>{}(s.ToUkmMetricHash());
125   }
126 };
127 
128 }  // namespace blink
129 
130 #endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABLE_SURFACE_H_
131