xref: /aosp_15_r20/external/perfetto/src/shared_lib/intern_map.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2023 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #ifndef SRC_SHARED_LIB_INTERN_MAP_H_
18*6dbdd20aSAndroid Build Coastguard Worker #define SRC_SHARED_LIB_INTERN_MAP_H_
19*6dbdd20aSAndroid Build Coastguard Worker 
20*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/flat_hash_map.h"
21*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/public/fnv1a.h"
22*6dbdd20aSAndroid Build Coastguard Worker 
23*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
24*6dbdd20aSAndroid Build Coastguard Worker 
25*6dbdd20aSAndroid Build Coastguard Worker // Assigns and maintains the mapping between "interned" data and iids (small
26*6dbdd20aSAndroid Build Coastguard Worker // integers that can be used to refer to the same data without repeating it)
27*6dbdd20aSAndroid Build Coastguard Worker // for different types.
28*6dbdd20aSAndroid Build Coastguard Worker class InternMap {
29*6dbdd20aSAndroid Build Coastguard Worker  public:
30*6dbdd20aSAndroid Build Coastguard Worker   // Zero will never be assigned as a valid iid: it is used as the return value
31*6dbdd20aSAndroid Build Coastguard Worker   // of Find() to signal failure.
32*6dbdd20aSAndroid Build Coastguard Worker   using Iid = uint64_t;
33*6dbdd20aSAndroid Build Coastguard Worker 
34*6dbdd20aSAndroid Build Coastguard Worker   InternMap();
35*6dbdd20aSAndroid Build Coastguard Worker   ~InternMap();
36*6dbdd20aSAndroid Build Coastguard Worker 
37*6dbdd20aSAndroid Build Coastguard Worker   // Given a value (identified by the memory buffer starting at `value`,
38*6dbdd20aSAndroid Build Coastguard Worker   // `value_size` bytes long) of a specific `type`, finds if there was an
39*6dbdd20aSAndroid Build Coastguard Worker   // existing iid associated with it, or assigns a new iid to it. Assigned iids
40*6dbdd20aSAndroid Build Coastguard Worker   // are unique for a specific type, but are reused across different types.
41*6dbdd20aSAndroid Build Coastguard Worker   struct FindOrAssignRes {
42*6dbdd20aSAndroid Build Coastguard Worker     // Iid associated with the passed value.
43*6dbdd20aSAndroid Build Coastguard Worker     Iid iid;
44*6dbdd20aSAndroid Build Coastguard Worker     // Whether the iid was newly assigned in this call (i.e. true if the value
45*6dbdd20aSAndroid Build Coastguard Worker     // was not seen before).
46*6dbdd20aSAndroid Build Coastguard Worker     bool newly_assigned;
47*6dbdd20aSAndroid Build Coastguard Worker   };
48*6dbdd20aSAndroid Build Coastguard Worker   FindOrAssignRes FindOrAssign(int32_t type,
49*6dbdd20aSAndroid Build Coastguard Worker                                const void* value,
50*6dbdd20aSAndroid Build Coastguard Worker                                size_t value_size);
51*6dbdd20aSAndroid Build Coastguard Worker 
52*6dbdd20aSAndroid Build Coastguard Worker  private:
53*6dbdd20aSAndroid Build Coastguard Worker   // Stores a value of a specific type. If the value is small, it is stored
54*6dbdd20aSAndroid Build Coastguard Worker   // inline, otherwise it is stored in an external buffer. The Key can own the
55*6dbdd20aSAndroid Build Coastguard Worker   // external buffer (when the key is stored in the map) or not (when the key is
56*6dbdd20aSAndroid Build Coastguard Worker   // just used for lookup).
57*6dbdd20aSAndroid Build Coastguard Worker   class Key {
58*6dbdd20aSAndroid Build Coastguard Worker    public:
NonOwning(int32_t type,const void * value,size_t value_size)59*6dbdd20aSAndroid Build Coastguard Worker     static Key NonOwning(int32_t type, const void* value, size_t value_size) {
60*6dbdd20aSAndroid Build Coastguard Worker       Key key;
61*6dbdd20aSAndroid Build Coastguard Worker       key.type_ = type;
62*6dbdd20aSAndroid Build Coastguard Worker       key.val_type_ = ValueStorage::kNonOwnedPtr;
63*6dbdd20aSAndroid Build Coastguard Worker       key.ptr_ = value;
64*6dbdd20aSAndroid Build Coastguard Worker       key.value_size_ = value_size;
65*6dbdd20aSAndroid Build Coastguard Worker       return key;
66*6dbdd20aSAndroid Build Coastguard Worker     }
Owning(int32_t type,const void * value,size_t value_size)67*6dbdd20aSAndroid Build Coastguard Worker     static Key Owning(int32_t type, const void* value, size_t value_size) {
68*6dbdd20aSAndroid Build Coastguard Worker       Key key;
69*6dbdd20aSAndroid Build Coastguard Worker       key.type_ = type;
70*6dbdd20aSAndroid Build Coastguard Worker       key.value_size_ = value_size;
71*6dbdd20aSAndroid Build Coastguard Worker       if (value_size < sizeof(value_buf_)) {
72*6dbdd20aSAndroid Build Coastguard Worker         key.val_type_ = ValueStorage::kInline;
73*6dbdd20aSAndroid Build Coastguard Worker         memcpy(key.value_buf_, value, value_size);
74*6dbdd20aSAndroid Build Coastguard Worker       } else {
75*6dbdd20aSAndroid Build Coastguard Worker         key.val_type_ = ValueStorage::kOwnedPtr;
76*6dbdd20aSAndroid Build Coastguard Worker         char* newvalue = new char[value_size];
77*6dbdd20aSAndroid Build Coastguard Worker         memcpy(newvalue, value, value_size);
78*6dbdd20aSAndroid Build Coastguard Worker         key.owned_ptr_ = newvalue;
79*6dbdd20aSAndroid Build Coastguard Worker       }
80*6dbdd20aSAndroid Build Coastguard Worker       return key;
81*6dbdd20aSAndroid Build Coastguard Worker     }
~Key()82*6dbdd20aSAndroid Build Coastguard Worker     ~Key() {
83*6dbdd20aSAndroid Build Coastguard Worker       if (val_type_ == ValueStorage::kOwnedPtr) {
84*6dbdd20aSAndroid Build Coastguard Worker         delete[] owned_ptr_;
85*6dbdd20aSAndroid Build Coastguard Worker       }
86*6dbdd20aSAndroid Build Coastguard Worker     }
87*6dbdd20aSAndroid Build Coastguard Worker     Key(const Key&) = delete;
Key(Key && other)88*6dbdd20aSAndroid Build Coastguard Worker     Key(Key&& other) noexcept {
89*6dbdd20aSAndroid Build Coastguard Worker       type_ = other.type_;
90*6dbdd20aSAndroid Build Coastguard Worker       value_size_ = other.value_size_;
91*6dbdd20aSAndroid Build Coastguard Worker       switch (other.val_type_) {
92*6dbdd20aSAndroid Build Coastguard Worker         case ValueStorage::kNonOwnedPtr:
93*6dbdd20aSAndroid Build Coastguard Worker           val_type_ = ValueStorage::kNonOwnedPtr;
94*6dbdd20aSAndroid Build Coastguard Worker           ptr_ = other.ptr_;
95*6dbdd20aSAndroid Build Coastguard Worker           return;
96*6dbdd20aSAndroid Build Coastguard Worker         case ValueStorage::kOwnedPtr:
97*6dbdd20aSAndroid Build Coastguard Worker           val_type_ = ValueStorage::kOwnedPtr;
98*6dbdd20aSAndroid Build Coastguard Worker           owned_ptr_ = other.owned_ptr_;
99*6dbdd20aSAndroid Build Coastguard Worker           other.val_type_ = ValueStorage::kInline;
100*6dbdd20aSAndroid Build Coastguard Worker           other.value_size_ = 0;
101*6dbdd20aSAndroid Build Coastguard Worker           return;
102*6dbdd20aSAndroid Build Coastguard Worker         case ValueStorage::kInline:
103*6dbdd20aSAndroid Build Coastguard Worker           val_type_ = ValueStorage::kInline;
104*6dbdd20aSAndroid Build Coastguard Worker           memcpy(value_buf_, other.value_buf_, value_size_);
105*6dbdd20aSAndroid Build Coastguard Worker           return;
106*6dbdd20aSAndroid Build Coastguard Worker       }
107*6dbdd20aSAndroid Build Coastguard Worker     }
108*6dbdd20aSAndroid Build Coastguard Worker     bool operator==(const Key& other) const {
109*6dbdd20aSAndroid Build Coastguard Worker       if (type_ != other.type_) {
110*6dbdd20aSAndroid Build Coastguard Worker         return false;
111*6dbdd20aSAndroid Build Coastguard Worker       }
112*6dbdd20aSAndroid Build Coastguard Worker       if (value_size_ != other.value_size_) {
113*6dbdd20aSAndroid Build Coastguard Worker         return false;
114*6dbdd20aSAndroid Build Coastguard Worker       }
115*6dbdd20aSAndroid Build Coastguard Worker       return memcmp(value(), other.value(), value_size_) == 0;
116*6dbdd20aSAndroid Build Coastguard Worker     }
value()117*6dbdd20aSAndroid Build Coastguard Worker     const void* value() const {
118*6dbdd20aSAndroid Build Coastguard Worker       switch (val_type_) {
119*6dbdd20aSAndroid Build Coastguard Worker         case ValueStorage::kNonOwnedPtr:
120*6dbdd20aSAndroid Build Coastguard Worker           return ptr_;
121*6dbdd20aSAndroid Build Coastguard Worker         case ValueStorage::kOwnedPtr:
122*6dbdd20aSAndroid Build Coastguard Worker           return owned_ptr_;
123*6dbdd20aSAndroid Build Coastguard Worker         case ValueStorage::kInline:
124*6dbdd20aSAndroid Build Coastguard Worker           break;
125*6dbdd20aSAndroid Build Coastguard Worker       }
126*6dbdd20aSAndroid Build Coastguard Worker       return &value_buf_;
127*6dbdd20aSAndroid Build Coastguard Worker     }
128*6dbdd20aSAndroid Build Coastguard Worker     struct Hash {
operatorHash129*6dbdd20aSAndroid Build Coastguard Worker       size_t operator()(const Key& obj) const {
130*6dbdd20aSAndroid Build Coastguard Worker         return std::hash<int32_t>()(obj.type_) ^
131*6dbdd20aSAndroid Build Coastguard Worker                static_cast<size_t>(PerfettoFnv1a(obj.value(), obj.value_size_));
132*6dbdd20aSAndroid Build Coastguard Worker       }
133*6dbdd20aSAndroid Build Coastguard Worker     };
134*6dbdd20aSAndroid Build Coastguard Worker 
135*6dbdd20aSAndroid Build Coastguard Worker    private:
136*6dbdd20aSAndroid Build Coastguard Worker     enum class ValueStorage {
137*6dbdd20aSAndroid Build Coastguard Worker       kInline,       // `value_buf_` is used directly to store the value.
138*6dbdd20aSAndroid Build Coastguard Worker       kNonOwnedPtr,  // `ptr_` points to an external buffer that stores the
139*6dbdd20aSAndroid Build Coastguard Worker                      // value. Not owned by this Key.
140*6dbdd20aSAndroid Build Coastguard Worker       kOwnedPtr,     // `owned_ptr_` points to an external buffer that stores
141*6dbdd20aSAndroid Build Coastguard Worker                      // the value. Owned by this Key.
142*6dbdd20aSAndroid Build Coastguard Worker     };
143*6dbdd20aSAndroid Build Coastguard Worker     Key() = default;
144*6dbdd20aSAndroid Build Coastguard Worker     int32_t type_;
145*6dbdd20aSAndroid Build Coastguard Worker     ValueStorage val_type_;
146*6dbdd20aSAndroid Build Coastguard Worker     size_t value_size_;
147*6dbdd20aSAndroid Build Coastguard Worker     union {
148*6dbdd20aSAndroid Build Coastguard Worker       char value_buf_[sizeof(uint64_t)];
149*6dbdd20aSAndroid Build Coastguard Worker       const void* ptr_;
150*6dbdd20aSAndroid Build Coastguard Worker       char* owned_ptr_;
151*6dbdd20aSAndroid Build Coastguard Worker     };
152*6dbdd20aSAndroid Build Coastguard Worker   };
153*6dbdd20aSAndroid Build Coastguard Worker 
154*6dbdd20aSAndroid Build Coastguard Worker   base::FlatHashMap<Key, uint64_t, Key::Hash> map_;
155*6dbdd20aSAndroid Build Coastguard Worker   base::FlatHashMap<int32_t, uint64_t> last_iid_by_type_;
156*6dbdd20aSAndroid Build Coastguard Worker };
157*6dbdd20aSAndroid Build Coastguard Worker 
158*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
159*6dbdd20aSAndroid Build Coastguard Worker 
160*6dbdd20aSAndroid Build Coastguard Worker #endif  // SRC_SHARED_LIB_INTERN_MAP_H_
161