xref: /aosp_15_r20/art/libartbase/base/bit_table.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_LIBARTBASE_BASE_BIT_TABLE_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_LIBARTBASE_BASE_BIT_TABLE_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <array>
21*795d594fSAndroid Build Coastguard Worker #include <initializer_list>
22*795d594fSAndroid Build Coastguard Worker #include <numeric>
23*795d594fSAndroid Build Coastguard Worker #include <string.h>
24*795d594fSAndroid Build Coastguard Worker #include <type_traits>
25*795d594fSAndroid Build Coastguard Worker #include <unordered_map>
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker #include "base/bit_memory_region.h"
28*795d594fSAndroid Build Coastguard Worker #include "base/casts.h"
29*795d594fSAndroid Build Coastguard Worker #include "base/iteration_range.h"
30*795d594fSAndroid Build Coastguard Worker #include "base/memory_region.h"
31*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_containers.h"
32*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker namespace art {
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker // Generic purpose table of uint32_t values, which are tightly packed at bit level.
37*795d594fSAndroid Build Coastguard Worker // It has its own header with the number of rows and the bit-widths of all columns.
38*795d594fSAndroid Build Coastguard Worker // The values are accessible by (row, column).  The value -1 is stored efficiently.
39*795d594fSAndroid Build Coastguard Worker template<uint32_t kNumColumns>
40*795d594fSAndroid Build Coastguard Worker class BitTableBase {
41*795d594fSAndroid Build Coastguard Worker  public:
42*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kNoValue = std::numeric_limits<uint32_t>::max();  // == -1.
43*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kValueBias = kNoValue;  // Bias so that -1 is encoded as 0.
44*795d594fSAndroid Build Coastguard Worker 
BitTableBase()45*795d594fSAndroid Build Coastguard Worker   BitTableBase() {}
BitTableBase(BitMemoryReader & reader)46*795d594fSAndroid Build Coastguard Worker   explicit BitTableBase(BitMemoryReader& reader) {
47*795d594fSAndroid Build Coastguard Worker     Decode(reader);
48*795d594fSAndroid Build Coastguard Worker   }
49*795d594fSAndroid Build Coastguard Worker 
Decode(BitMemoryReader & reader)50*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE void Decode(BitMemoryReader& reader) {
51*795d594fSAndroid Build Coastguard Worker     // Decode row count and column sizes from the table header.
52*795d594fSAndroid Build Coastguard Worker     std::array<uint32_t, 1+kNumColumns> header = reader.ReadInterleavedVarints<1+kNumColumns>();
53*795d594fSAndroid Build Coastguard Worker     num_rows_ = header[0];
54*795d594fSAndroid Build Coastguard Worker     column_offset_[0] = 0;
55*795d594fSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < kNumColumns; i++) {
56*795d594fSAndroid Build Coastguard Worker       size_t column_end = column_offset_[i] + header[i + 1];
57*795d594fSAndroid Build Coastguard Worker       column_offset_[i + 1] = dchecked_integral_cast<uint16_t>(column_end);
58*795d594fSAndroid Build Coastguard Worker     }
59*795d594fSAndroid Build Coastguard Worker 
60*795d594fSAndroid Build Coastguard Worker     // Record the region which contains the table data and skip past it.
61*795d594fSAndroid Build Coastguard Worker     table_data_ = reader.ReadRegion(num_rows_ * NumRowBits());
62*795d594fSAndroid Build Coastguard Worker   }
63*795d594fSAndroid Build Coastguard Worker 
64*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE uint32_t Get(uint32_t row, uint32_t column = 0) const {
65*795d594fSAndroid Build Coastguard Worker     DCHECK(table_data_.IsValid()) << "Table has not been loaded";
66*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(row, num_rows_);
67*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(column, kNumColumns);
68*795d594fSAndroid Build Coastguard Worker     size_t offset = row * NumRowBits() + column_offset_[column];
69*795d594fSAndroid Build Coastguard Worker     return table_data_.LoadBits(offset, NumColumnBits(column)) + kValueBias;
70*795d594fSAndroid Build Coastguard Worker   }
71*795d594fSAndroid Build Coastguard Worker 
72*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE BitMemoryRegion GetBitMemoryRegion(uint32_t row, uint32_t column = 0) const {
73*795d594fSAndroid Build Coastguard Worker     DCHECK(table_data_.IsValid()) << "Table has not been loaded";
74*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(row, num_rows_);
75*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(column, kNumColumns);
76*795d594fSAndroid Build Coastguard Worker     size_t offset = row * NumRowBits() + column_offset_[column];
77*795d594fSAndroid Build Coastguard Worker     return table_data_.Subregion(offset, NumColumnBits(column));
78*795d594fSAndroid Build Coastguard Worker   }
79*795d594fSAndroid Build Coastguard Worker 
NumRows()80*795d594fSAndroid Build Coastguard Worker   uint32_t NumRows() const { return num_rows_; }
81*795d594fSAndroid Build Coastguard Worker 
NumRowBits()82*795d594fSAndroid Build Coastguard Worker   uint32_t NumRowBits() const { return column_offset_[kNumColumns]; }
83*795d594fSAndroid Build Coastguard Worker 
NumColumns()84*795d594fSAndroid Build Coastguard Worker   constexpr uint32_t NumColumns() const { return kNumColumns; }
85*795d594fSAndroid Build Coastguard Worker 
NumColumnBits(uint32_t column)86*795d594fSAndroid Build Coastguard Worker   uint32_t NumColumnBits(uint32_t column) const {
87*795d594fSAndroid Build Coastguard Worker     return column_offset_[column + 1] - column_offset_[column];
88*795d594fSAndroid Build Coastguard Worker   }
89*795d594fSAndroid Build Coastguard Worker 
DataBitSize()90*795d594fSAndroid Build Coastguard Worker   size_t DataBitSize() const { return table_data_.size_in_bits(); }
91*795d594fSAndroid Build Coastguard Worker 
Equals(const BitTableBase & other)92*795d594fSAndroid Build Coastguard Worker   bool Equals(const BitTableBase& other) const {
93*795d594fSAndroid Build Coastguard Worker     return num_rows_ == other.num_rows_ &&
94*795d594fSAndroid Build Coastguard Worker         std::equal(column_offset_, column_offset_ + kNumColumns, other.column_offset_) &&
95*795d594fSAndroid Build Coastguard Worker         BitMemoryRegion::Equals(table_data_, other.table_data_);
96*795d594fSAndroid Build Coastguard Worker   }
97*795d594fSAndroid Build Coastguard Worker 
98*795d594fSAndroid Build Coastguard Worker  protected:
99*795d594fSAndroid Build Coastguard Worker   BitMemoryRegion table_data_;
100*795d594fSAndroid Build Coastguard Worker   uint32_t num_rows_ = 0;
101*795d594fSAndroid Build Coastguard Worker   uint16_t column_offset_[kNumColumns + 1] = {};
102*795d594fSAndroid Build Coastguard Worker };
103*795d594fSAndroid Build Coastguard Worker 
104*795d594fSAndroid Build Coastguard Worker // Helper class which can be used to create BitTable accessors with named getters.
105*795d594fSAndroid Build Coastguard Worker template<uint32_t NumColumns>
106*795d594fSAndroid Build Coastguard Worker class BitTableAccessor {
107*795d594fSAndroid Build Coastguard Worker  public:
108*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kNumColumns = NumColumns;
109*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kNoValue = BitTableBase<kNumColumns>::kNoValue;
110*795d594fSAndroid Build Coastguard Worker 
111*795d594fSAndroid Build Coastguard Worker   BitTableAccessor() = default;
BitTableAccessor(const BitTableBase<kNumColumns> * table,uint32_t row)112*795d594fSAndroid Build Coastguard Worker   BitTableAccessor(const BitTableBase<kNumColumns>* table, uint32_t row)
113*795d594fSAndroid Build Coastguard Worker       : table_(table), row_(row) {
114*795d594fSAndroid Build Coastguard Worker     DCHECK(table_ != nullptr);
115*795d594fSAndroid Build Coastguard Worker   }
116*795d594fSAndroid Build Coastguard Worker 
Row()117*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE uint32_t Row() const { return row_; }
118*795d594fSAndroid Build Coastguard Worker 
IsValid()119*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE bool IsValid() const { return row_ < table_->NumRows(); }
120*795d594fSAndroid Build Coastguard Worker 
Equals(const BitTableAccessor & other)121*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE bool Equals(const BitTableAccessor& other) {
122*795d594fSAndroid Build Coastguard Worker     return this->table_ == other.table_ && this->row_ == other.row_;
123*795d594fSAndroid Build Coastguard Worker   }
124*795d594fSAndroid Build Coastguard Worker 
125*795d594fSAndroid Build Coastguard Worker // Helper macro to create constructors and per-table utilities in derived class.
126*795d594fSAndroid Build Coastguard Worker #define BIT_TABLE_HEADER(NAME)                                                       \
127*795d594fSAndroid Build Coastguard Worker   using BitTableAccessor<kNumColumns>::BitTableAccessor; /* inherit constructors */  \
128*795d594fSAndroid Build Coastguard Worker   template<int COLUMN, int UNUSED /*needed to compile*/> struct ColumnName;          \
129*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kTableName = #NAME;                                   \
130*795d594fSAndroid Build Coastguard Worker 
131*795d594fSAndroid Build Coastguard Worker // Helper macro to create named column accessors in derived class.
132*795d594fSAndroid Build Coastguard Worker #define BIT_TABLE_COLUMN(COLUMN, NAME)                                               \
133*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t k##NAME = COLUMN;                                        \
134*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE uint32_t Get##NAME() const { return table_->Get(row_, COLUMN); }     \
135*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE bool Has##NAME() const { return Get##NAME() != kNoValue; }           \
136*795d594fSAndroid Build Coastguard Worker   template<int UNUSED> struct ColumnName<COLUMN, UNUSED> {                           \
137*795d594fSAndroid Build Coastguard Worker     static constexpr const char* Value = #NAME;                                      \
138*795d594fSAndroid Build Coastguard Worker   };                                                                                 \
139*795d594fSAndroid Build Coastguard Worker 
140*795d594fSAndroid Build Coastguard Worker  protected:
141*795d594fSAndroid Build Coastguard Worker   const BitTableBase<kNumColumns>* table_ = nullptr;
142*795d594fSAndroid Build Coastguard Worker   uint32_t row_ = -1;
143*795d594fSAndroid Build Coastguard Worker };
144*795d594fSAndroid Build Coastguard Worker 
145*795d594fSAndroid Build Coastguard Worker // Template meta-programming helper.
146*795d594fSAndroid Build Coastguard Worker template<typename Accessor, size_t... Columns>
GetBitTableColumnNamesImpl(std::index_sequence<Columns...>)147*795d594fSAndroid Build Coastguard Worker static const char* const* GetBitTableColumnNamesImpl(std::index_sequence<Columns...>) {
148*795d594fSAndroid Build Coastguard Worker   static const char* names[] = { Accessor::template ColumnName<Columns, 0>::Value... };
149*795d594fSAndroid Build Coastguard Worker   return names;
150*795d594fSAndroid Build Coastguard Worker }
151*795d594fSAndroid Build Coastguard Worker 
152*795d594fSAndroid Build Coastguard Worker // Wrapper which makes it easier to use named accessors for the individual rows.
153*795d594fSAndroid Build Coastguard Worker template<typename Accessor>
154*795d594fSAndroid Build Coastguard Worker class BitTable : public BitTableBase<Accessor::kNumColumns> {
155*795d594fSAndroid Build Coastguard Worker  public:
156*795d594fSAndroid Build Coastguard Worker   class const_iterator {
157*795d594fSAndroid Build Coastguard Worker    public:
158*795d594fSAndroid Build Coastguard Worker     using iterator_category = std::random_access_iterator_tag;
159*795d594fSAndroid Build Coastguard Worker     using value_type = Accessor;
160*795d594fSAndroid Build Coastguard Worker     using difference_type = int32_t;
161*795d594fSAndroid Build Coastguard Worker     using pointer = void;
162*795d594fSAndroid Build Coastguard Worker     using reference = void;
const_iterator()163*795d594fSAndroid Build Coastguard Worker     const_iterator() {}
const_iterator(const BitTable * table,uint32_t row)164*795d594fSAndroid Build Coastguard Worker     const_iterator(const BitTable* table, uint32_t row) : table_(table), row_(row) {}
165*795d594fSAndroid Build Coastguard Worker     const_iterator operator+(difference_type n) { return const_iterator(table_, row_ + n); }
166*795d594fSAndroid Build Coastguard Worker     const_iterator operator-(difference_type n) { return const_iterator(table_, row_ - n); }
167*795d594fSAndroid Build Coastguard Worker     difference_type operator-(const const_iterator& other) { return row_ - other.row_; }
168*795d594fSAndroid Build Coastguard Worker     void operator+=(difference_type rows) { row_ += rows; }
169*795d594fSAndroid Build Coastguard Worker     void operator-=(difference_type rows) { row_ -= rows; }
170*795d594fSAndroid Build Coastguard Worker     const_iterator operator++() { return const_iterator(table_, ++row_); }
171*795d594fSAndroid Build Coastguard Worker     const_iterator operator--() { return const_iterator(table_, --row_); }
172*795d594fSAndroid Build Coastguard Worker     const_iterator operator++(int) { return const_iterator(table_, row_++); }
173*795d594fSAndroid Build Coastguard Worker     const_iterator operator--(int) { return const_iterator(table_, row_--); }
174*795d594fSAndroid Build Coastguard Worker     bool operator==(const_iterator i) const { DCHECK(table_ == i.table_); return row_ == i.row_; }
175*795d594fSAndroid Build Coastguard Worker     bool operator!=(const_iterator i) const { DCHECK(table_ == i.table_); return row_ != i.row_; }
176*795d594fSAndroid Build Coastguard Worker     bool operator<=(const_iterator i) const { DCHECK(table_ == i.table_); return row_ <= i.row_; }
177*795d594fSAndroid Build Coastguard Worker     bool operator>=(const_iterator i) const { DCHECK(table_ == i.table_); return row_ >= i.row_; }
178*795d594fSAndroid Build Coastguard Worker     bool operator<(const_iterator i) const { DCHECK(table_ == i.table_); return row_ < i.row_; }
179*795d594fSAndroid Build Coastguard Worker     bool operator>(const_iterator i) const { DCHECK(table_ == i.table_); return row_ > i.row_; }
180*795d594fSAndroid Build Coastguard Worker     Accessor operator*() {
181*795d594fSAndroid Build Coastguard Worker       DCHECK_LT(row_, table_->NumRows());
182*795d594fSAndroid Build Coastguard Worker       return Accessor(table_, row_);
183*795d594fSAndroid Build Coastguard Worker     }
184*795d594fSAndroid Build Coastguard Worker     Accessor operator->() {
185*795d594fSAndroid Build Coastguard Worker       DCHECK_LT(row_, table_->NumRows());
186*795d594fSAndroid Build Coastguard Worker       return Accessor(table_, row_);
187*795d594fSAndroid Build Coastguard Worker     }
188*795d594fSAndroid Build Coastguard Worker     Accessor operator[](size_t index) {
189*795d594fSAndroid Build Coastguard Worker       DCHECK_LT(row_ + index, table_->NumRows());
190*795d594fSAndroid Build Coastguard Worker       return Accessor(table_, row_ + index);
191*795d594fSAndroid Build Coastguard Worker     }
192*795d594fSAndroid Build Coastguard Worker 
193*795d594fSAndroid Build Coastguard Worker    private:
194*795d594fSAndroid Build Coastguard Worker     const BitTable* table_ = nullptr;
195*795d594fSAndroid Build Coastguard Worker     uint32_t row_ = 0;
196*795d594fSAndroid Build Coastguard Worker   };
197*795d594fSAndroid Build Coastguard Worker 
198*795d594fSAndroid Build Coastguard Worker   using BitTableBase<Accessor::kNumColumns>::BitTableBase;  // Constructors.
199*795d594fSAndroid Build Coastguard Worker 
begin()200*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE const_iterator begin() const { return const_iterator(this, 0); }
end()201*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE const_iterator end() const { return const_iterator(this, this->NumRows()); }
202*795d594fSAndroid Build Coastguard Worker 
GetRow(uint32_t row)203*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE Accessor GetRow(uint32_t row) const {
204*795d594fSAndroid Build Coastguard Worker     return Accessor(this, row);
205*795d594fSAndroid Build Coastguard Worker   }
206*795d594fSAndroid Build Coastguard Worker 
GetInvalidRow()207*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE Accessor GetInvalidRow() const {
208*795d594fSAndroid Build Coastguard Worker     return Accessor(this, static_cast<uint32_t>(-1));
209*795d594fSAndroid Build Coastguard Worker   }
210*795d594fSAndroid Build Coastguard Worker 
GetName()211*795d594fSAndroid Build Coastguard Worker   const char* GetName() const {
212*795d594fSAndroid Build Coastguard Worker     return Accessor::kTableName;
213*795d594fSAndroid Build Coastguard Worker   }
214*795d594fSAndroid Build Coastguard Worker 
GetColumnNames()215*795d594fSAndroid Build Coastguard Worker   const char* const* GetColumnNames() const {
216*795d594fSAndroid Build Coastguard Worker     return GetBitTableColumnNamesImpl<Accessor>(std::make_index_sequence<Accessor::kNumColumns>());
217*795d594fSAndroid Build Coastguard Worker   }
218*795d594fSAndroid Build Coastguard Worker };
219*795d594fSAndroid Build Coastguard Worker 
220*795d594fSAndroid Build Coastguard Worker template<typename Accessor>
221*795d594fSAndroid Build Coastguard Worker typename BitTable<Accessor>::const_iterator operator+(
222*795d594fSAndroid Build Coastguard Worker     typename BitTable<Accessor>::const_iterator::difference_type n,
223*795d594fSAndroid Build Coastguard Worker     typename BitTable<Accessor>::const_iterator a) {
224*795d594fSAndroid Build Coastguard Worker   return a + n;
225*795d594fSAndroid Build Coastguard Worker }
226*795d594fSAndroid Build Coastguard Worker 
227*795d594fSAndroid Build Coastguard Worker template<typename Accessor>
228*795d594fSAndroid Build Coastguard Worker class BitTableRange : public IterationRange<typename BitTable<Accessor>::const_iterator> {
229*795d594fSAndroid Build Coastguard Worker  public:
230*795d594fSAndroid Build Coastguard Worker   using const_iterator = typename BitTable<Accessor>::const_iterator;
231*795d594fSAndroid Build Coastguard Worker 
232*795d594fSAndroid Build Coastguard Worker   using IterationRange<const_iterator>::IterationRange;
BitTableRange()233*795d594fSAndroid Build Coastguard Worker   BitTableRange() : IterationRange<const_iterator>(const_iterator(), const_iterator()) { }
234*795d594fSAndroid Build Coastguard Worker 
empty()235*795d594fSAndroid Build Coastguard Worker   bool empty() const { return this->begin() == this->end(); }
size()236*795d594fSAndroid Build Coastguard Worker   size_t size() const { return this->end() - this->begin(); }
237*795d594fSAndroid Build Coastguard Worker 
238*795d594fSAndroid Build Coastguard Worker   Accessor operator[](size_t index) const {
239*795d594fSAndroid Build Coastguard Worker     const_iterator it = this->begin() + index;
240*795d594fSAndroid Build Coastguard Worker     DCHECK(it < this->end());
241*795d594fSAndroid Build Coastguard Worker     return *it;
242*795d594fSAndroid Build Coastguard Worker   }
243*795d594fSAndroid Build Coastguard Worker 
back()244*795d594fSAndroid Build Coastguard Worker   Accessor back() const {
245*795d594fSAndroid Build Coastguard Worker     DCHECK(!empty());
246*795d594fSAndroid Build Coastguard Worker     return *(this->end() - 1);
247*795d594fSAndroid Build Coastguard Worker   }
248*795d594fSAndroid Build Coastguard Worker 
pop_back()249*795d594fSAndroid Build Coastguard Worker   void pop_back() {
250*795d594fSAndroid Build Coastguard Worker     DCHECK(!empty());
251*795d594fSAndroid Build Coastguard Worker     --this->last_;
252*795d594fSAndroid Build Coastguard Worker   }
253*795d594fSAndroid Build Coastguard Worker };
254*795d594fSAndroid Build Coastguard Worker 
255*795d594fSAndroid Build Coastguard Worker // Helper class for encoding BitTable. It can optionally de-duplicate the inputs.
256*795d594fSAndroid Build Coastguard Worker template<uint32_t kNumColumns>
257*795d594fSAndroid Build Coastguard Worker class BitTableBuilderBase {
258*795d594fSAndroid Build Coastguard Worker  public:
259*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kNoValue = BitTableBase<kNumColumns>::kNoValue;
260*795d594fSAndroid Build Coastguard Worker   static constexpr uint32_t kValueBias = BitTableBase<kNumColumns>::kValueBias;
261*795d594fSAndroid Build Coastguard Worker 
262*795d594fSAndroid Build Coastguard Worker   class Entry {
263*795d594fSAndroid Build Coastguard Worker    public:
Entry()264*795d594fSAndroid Build Coastguard Worker     Entry() {
265*795d594fSAndroid Build Coastguard Worker       // The definition of kLocalNoValue here is for host and target debug builds which
266*795d594fSAndroid Build Coastguard Worker       // complain about missing a symbol definition for BitTableBase<N>::kNovValue when
267*795d594fSAndroid Build Coastguard Worker       // optimization is off.
268*795d594fSAndroid Build Coastguard Worker       static constexpr uint32_t kLocalNoValue = BitTableBase<kNumColumns>::kNoValue;
269*795d594fSAndroid Build Coastguard Worker       std::fill_n(data_, kNumColumns, kLocalNoValue);
270*795d594fSAndroid Build Coastguard Worker     }
271*795d594fSAndroid Build Coastguard Worker 
Entry(std::initializer_list<uint32_t> values)272*795d594fSAndroid Build Coastguard Worker     Entry(std::initializer_list<uint32_t> values) {
273*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(values.size(), kNumColumns);
274*795d594fSAndroid Build Coastguard Worker       std::copy(values.begin(), values.end(), data_);
275*795d594fSAndroid Build Coastguard Worker     }
276*795d594fSAndroid Build Coastguard Worker 
277*795d594fSAndroid Build Coastguard Worker     uint32_t& operator[](size_t column) {
278*795d594fSAndroid Build Coastguard Worker       DCHECK_LT(column, kNumColumns);
279*795d594fSAndroid Build Coastguard Worker       return data_[column];
280*795d594fSAndroid Build Coastguard Worker     }
281*795d594fSAndroid Build Coastguard Worker 
282*795d594fSAndroid Build Coastguard Worker     uint32_t operator[](size_t column) const {
283*795d594fSAndroid Build Coastguard Worker       DCHECK_LT(column, kNumColumns);
284*795d594fSAndroid Build Coastguard Worker       return data_[column];
285*795d594fSAndroid Build Coastguard Worker     }
286*795d594fSAndroid Build Coastguard Worker 
287*795d594fSAndroid Build Coastguard Worker    private:
288*795d594fSAndroid Build Coastguard Worker     uint32_t data_[kNumColumns];
289*795d594fSAndroid Build Coastguard Worker   };
290*795d594fSAndroid Build Coastguard Worker 
BitTableBuilderBase(ScopedArenaAllocator * allocator)291*795d594fSAndroid Build Coastguard Worker   explicit BitTableBuilderBase(ScopedArenaAllocator* allocator)
292*795d594fSAndroid Build Coastguard Worker       : rows_(allocator->Adapter(kArenaAllocBitTableBuilder)),
293*795d594fSAndroid Build Coastguard Worker         dedup_(8, allocator->Adapter(kArenaAllocBitTableBuilder)) {
294*795d594fSAndroid Build Coastguard Worker   }
295*795d594fSAndroid Build Coastguard Worker 
296*795d594fSAndroid Build Coastguard Worker   Entry& operator[](size_t row) { return rows_[row]; }
297*795d594fSAndroid Build Coastguard Worker   const Entry& operator[](size_t row) const { return rows_[row]; }
back()298*795d594fSAndroid Build Coastguard Worker   const Entry& back() const { return rows_.back(); }
size()299*795d594fSAndroid Build Coastguard Worker   size_t size() const { return rows_.size(); }
300*795d594fSAndroid Build Coastguard Worker 
301*795d594fSAndroid Build Coastguard Worker   // Append given value to the vector without de-duplication.
302*795d594fSAndroid Build Coastguard Worker   // This will not add the element to the dedup map to avoid its associated costs.
Add(Entry value)303*795d594fSAndroid Build Coastguard Worker   void Add(Entry value) {
304*795d594fSAndroid Build Coastguard Worker     rows_.push_back(value);
305*795d594fSAndroid Build Coastguard Worker   }
306*795d594fSAndroid Build Coastguard Worker 
307*795d594fSAndroid Build Coastguard Worker   // Append given list of values and return the index of the first value.
308*795d594fSAndroid Build Coastguard Worker   // If the exact same set of values was already added, return the old index.
309*795d594fSAndroid Build Coastguard Worker   uint32_t Dedup(Entry* values, size_t count = 1) {
310*795d594fSAndroid Build Coastguard Worker     FNVHash<MemoryRegion> hasher;
311*795d594fSAndroid Build Coastguard Worker     uint32_t hash = hasher(MemoryRegion(values, sizeof(Entry) * count));
312*795d594fSAndroid Build Coastguard Worker 
313*795d594fSAndroid Build Coastguard Worker     // Check if we have already added identical set of values.
314*795d594fSAndroid Build Coastguard Worker     auto range = dedup_.equal_range(hash);
315*795d594fSAndroid Build Coastguard Worker     for (auto it = range.first; it != range.second; ++it) {
316*795d594fSAndroid Build Coastguard Worker       uint32_t index = it->second;
317*795d594fSAndroid Build Coastguard Worker       if (count <= size() - index &&
318*795d594fSAndroid Build Coastguard Worker           std::equal(values,
319*795d594fSAndroid Build Coastguard Worker                      values + count,
320*795d594fSAndroid Build Coastguard Worker                      rows_.begin() + index,
321*795d594fSAndroid Build Coastguard Worker                      [](const Entry& lhs, const Entry& rhs) {
322*795d594fSAndroid Build Coastguard Worker                        return memcmp(&lhs, &rhs, sizeof(Entry)) == 0;
323*795d594fSAndroid Build Coastguard Worker                      })) {
324*795d594fSAndroid Build Coastguard Worker         return index;
325*795d594fSAndroid Build Coastguard Worker       }
326*795d594fSAndroid Build Coastguard Worker     }
327*795d594fSAndroid Build Coastguard Worker 
328*795d594fSAndroid Build Coastguard Worker     // Add the set of values and add the index to the dedup map.
329*795d594fSAndroid Build Coastguard Worker     uint32_t index = size();
330*795d594fSAndroid Build Coastguard Worker     rows_.insert(rows_.end(), values, values + count);
331*795d594fSAndroid Build Coastguard Worker     dedup_.emplace(hash, index);
332*795d594fSAndroid Build Coastguard Worker     return index;
333*795d594fSAndroid Build Coastguard Worker   }
334*795d594fSAndroid Build Coastguard Worker 
Dedup(Entry value)335*795d594fSAndroid Build Coastguard Worker   uint32_t Dedup(Entry value) {
336*795d594fSAndroid Build Coastguard Worker     return Dedup(&value, /* count */ 1);
337*795d594fSAndroid Build Coastguard Worker   }
338*795d594fSAndroid Build Coastguard Worker 
339*795d594fSAndroid Build Coastguard Worker   // Calculate the column bit widths based on the current data.
Measure(uint32_t * column_bits)340*795d594fSAndroid Build Coastguard Worker   void Measure(/*out*/ uint32_t* column_bits) const {
341*795d594fSAndroid Build Coastguard Worker     uint32_t max_column_value[kNumColumns];
342*795d594fSAndroid Build Coastguard Worker     std::fill_n(max_column_value, kNumColumns, 0);
343*795d594fSAndroid Build Coastguard Worker     for (uint32_t r = 0; r < size(); r++) {
344*795d594fSAndroid Build Coastguard Worker       for (uint32_t c = 0; c < kNumColumns; c++) {
345*795d594fSAndroid Build Coastguard Worker         max_column_value[c] |= rows_[r][c] - kValueBias;
346*795d594fSAndroid Build Coastguard Worker       }
347*795d594fSAndroid Build Coastguard Worker     }
348*795d594fSAndroid Build Coastguard Worker     for (uint32_t c = 0; c < kNumColumns; c++) {
349*795d594fSAndroid Build Coastguard Worker       column_bits[c] = MinimumBitsToStore(max_column_value[c]);
350*795d594fSAndroid Build Coastguard Worker     }
351*795d594fSAndroid Build Coastguard Worker   }
352*795d594fSAndroid Build Coastguard Worker 
353*795d594fSAndroid Build Coastguard Worker   // Encode the stored data into a BitTable.
354*795d594fSAndroid Build Coastguard Worker   template<typename Vector>
Encode(BitMemoryWriter<Vector> & out)355*795d594fSAndroid Build Coastguard Worker   void Encode(BitMemoryWriter<Vector>& out) const {
356*795d594fSAndroid Build Coastguard Worker     size_t initial_bit_offset = out.NumberOfWrittenBits();
357*795d594fSAndroid Build Coastguard Worker 
358*795d594fSAndroid Build Coastguard Worker     // Write table header.
359*795d594fSAndroid Build Coastguard Worker     std::array<uint32_t, 1 + kNumColumns> header;
360*795d594fSAndroid Build Coastguard Worker     header[0] = size();
361*795d594fSAndroid Build Coastguard Worker     uint32_t* column_bits = header.data() + 1;
362*795d594fSAndroid Build Coastguard Worker     Measure(column_bits);
363*795d594fSAndroid Build Coastguard Worker     out.WriteInterleavedVarints(header);
364*795d594fSAndroid Build Coastguard Worker 
365*795d594fSAndroid Build Coastguard Worker     // Write table data.
366*795d594fSAndroid Build Coastguard Worker     for (uint32_t r = 0; r < size(); r++) {
367*795d594fSAndroid Build Coastguard Worker       for (uint32_t c = 0; c < kNumColumns; c++) {
368*795d594fSAndroid Build Coastguard Worker         out.WriteBits(rows_[r][c] - kValueBias, column_bits[c]);
369*795d594fSAndroid Build Coastguard Worker       }
370*795d594fSAndroid Build Coastguard Worker     }
371*795d594fSAndroid Build Coastguard Worker 
372*795d594fSAndroid Build Coastguard Worker     // Verify the written data.
373*795d594fSAndroid Build Coastguard Worker     if (kIsDebugBuild) {
374*795d594fSAndroid Build Coastguard Worker       BitTableBase<kNumColumns> table;
375*795d594fSAndroid Build Coastguard Worker       BitMemoryReader reader(out.GetWrittenRegion().Subregion(initial_bit_offset));
376*795d594fSAndroid Build Coastguard Worker       table.Decode(reader);
377*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(size(), table.NumRows());
378*795d594fSAndroid Build Coastguard Worker       for (uint32_t c = 0; c < kNumColumns; c++) {
379*795d594fSAndroid Build Coastguard Worker         DCHECK_EQ(column_bits[c], table.NumColumnBits(c));
380*795d594fSAndroid Build Coastguard Worker       }
381*795d594fSAndroid Build Coastguard Worker       for (uint32_t r = 0; r < size(); r++) {
382*795d594fSAndroid Build Coastguard Worker         for (uint32_t c = 0; c < kNumColumns; c++) {
383*795d594fSAndroid Build Coastguard Worker           DCHECK_EQ(rows_[r][c], table.Get(r, c)) << " (" << r << ", " << c << ")";
384*795d594fSAndroid Build Coastguard Worker         }
385*795d594fSAndroid Build Coastguard Worker       }
386*795d594fSAndroid Build Coastguard Worker     }
387*795d594fSAndroid Build Coastguard Worker   }
388*795d594fSAndroid Build Coastguard Worker 
389*795d594fSAndroid Build Coastguard Worker  protected:
390*795d594fSAndroid Build Coastguard Worker   ScopedArenaDeque<Entry> rows_;
391*795d594fSAndroid Build Coastguard Worker   ScopedArenaUnorderedMultimap<uint32_t, uint32_t> dedup_;  // Hash -> row index.
392*795d594fSAndroid Build Coastguard Worker };
393*795d594fSAndroid Build Coastguard Worker 
394*795d594fSAndroid Build Coastguard Worker template<typename Accessor>
395*795d594fSAndroid Build Coastguard Worker class BitTableBuilder : public BitTableBuilderBase<Accessor::kNumColumns> {
396*795d594fSAndroid Build Coastguard Worker  public:
397*795d594fSAndroid Build Coastguard Worker   using BitTableBuilderBase<Accessor::kNumColumns>::BitTableBuilderBase;  // Constructors.
398*795d594fSAndroid Build Coastguard Worker };
399*795d594fSAndroid Build Coastguard Worker 
400*795d594fSAndroid Build Coastguard Worker // Helper class for encoding single-column BitTable of bitmaps (allows more than 32 bits).
401*795d594fSAndroid Build Coastguard Worker class BitmapTableBuilder {
402*795d594fSAndroid Build Coastguard Worker  public:
BitmapTableBuilder(ScopedArenaAllocator * const allocator)403*795d594fSAndroid Build Coastguard Worker   explicit BitmapTableBuilder(ScopedArenaAllocator* const allocator)
404*795d594fSAndroid Build Coastguard Worker       : allocator_(allocator),
405*795d594fSAndroid Build Coastguard Worker         rows_(allocator->Adapter(kArenaAllocBitTableBuilder)),
406*795d594fSAndroid Build Coastguard Worker         dedup_(8, allocator_->Adapter(kArenaAllocBitTableBuilder)) {
407*795d594fSAndroid Build Coastguard Worker   }
408*795d594fSAndroid Build Coastguard Worker 
409*795d594fSAndroid Build Coastguard Worker   MemoryRegion operator[](size_t row) { return rows_[row]; }
410*795d594fSAndroid Build Coastguard Worker   const MemoryRegion operator[](size_t row) const { return rows_[row]; }
size()411*795d594fSAndroid Build Coastguard Worker   size_t size() const { return rows_.size(); }
412*795d594fSAndroid Build Coastguard Worker 
413*795d594fSAndroid Build Coastguard Worker   // Add the given bitmap to the table and return its index.
414*795d594fSAndroid Build Coastguard Worker   // If the bitmap was already added it will be deduplicated.
415*795d594fSAndroid Build Coastguard Worker   // The last bit must be set and any padding bits in the last byte must be zero.
Dedup(const void * bitmap,size_t num_bits)416*795d594fSAndroid Build Coastguard Worker   uint32_t Dedup(const void* bitmap, size_t num_bits) {
417*795d594fSAndroid Build Coastguard Worker     MemoryRegion region(const_cast<void*>(bitmap), BitsToBytesRoundUp(num_bits));
418*795d594fSAndroid Build Coastguard Worker     DCHECK(num_bits == 0 || BitMemoryRegion(region).LoadBit(num_bits - 1) == 1);
419*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(BitMemoryRegion(region).LoadBits(num_bits, region.size_in_bits() - num_bits), 0u);
420*795d594fSAndroid Build Coastguard Worker     FNVHash<MemoryRegion> hasher;
421*795d594fSAndroid Build Coastguard Worker     uint32_t hash = hasher(region);
422*795d594fSAndroid Build Coastguard Worker 
423*795d594fSAndroid Build Coastguard Worker     // Check if we have already added identical bitmap.
424*795d594fSAndroid Build Coastguard Worker     auto range = dedup_.equal_range(hash);
425*795d594fSAndroid Build Coastguard Worker     for (auto it = range.first; it != range.second; ++it) {
426*795d594fSAndroid Build Coastguard Worker       if (MemoryRegion::ContentEquals()(region, rows_[it->second])) {
427*795d594fSAndroid Build Coastguard Worker         return it->second;
428*795d594fSAndroid Build Coastguard Worker       }
429*795d594fSAndroid Build Coastguard Worker     }
430*795d594fSAndroid Build Coastguard Worker 
431*795d594fSAndroid Build Coastguard Worker     // Add the bitmap and add the index to the dedup map.
432*795d594fSAndroid Build Coastguard Worker     uint32_t index = size();
433*795d594fSAndroid Build Coastguard Worker     void* copy = allocator_->Alloc(region.size(), kArenaAllocBitTableBuilder);
434*795d594fSAndroid Build Coastguard Worker     memcpy(copy, region.pointer(), region.size());
435*795d594fSAndroid Build Coastguard Worker     rows_.push_back(MemoryRegion(copy, region.size()));
436*795d594fSAndroid Build Coastguard Worker     dedup_.emplace(hash, index);
437*795d594fSAndroid Build Coastguard Worker     max_num_bits_ = std::max(max_num_bits_, num_bits);
438*795d594fSAndroid Build Coastguard Worker     return index;
439*795d594fSAndroid Build Coastguard Worker   }
440*795d594fSAndroid Build Coastguard Worker 
441*795d594fSAndroid Build Coastguard Worker   // Encode the stored data into a BitTable.
442*795d594fSAndroid Build Coastguard Worker   template<typename Vector>
Encode(BitMemoryWriter<Vector> & out)443*795d594fSAndroid Build Coastguard Worker   void Encode(BitMemoryWriter<Vector>& out) const {
444*795d594fSAndroid Build Coastguard Worker     size_t initial_bit_offset = out.NumberOfWrittenBits();
445*795d594fSAndroid Build Coastguard Worker 
446*795d594fSAndroid Build Coastguard Worker     // Write table header.
447*795d594fSAndroid Build Coastguard Worker     out.WriteInterleavedVarints(std::array<uint32_t, 2>{
448*795d594fSAndroid Build Coastguard Worker       dchecked_integral_cast<uint32_t>(size()),
449*795d594fSAndroid Build Coastguard Worker       dchecked_integral_cast<uint32_t>(max_num_bits_),
450*795d594fSAndroid Build Coastguard Worker     });
451*795d594fSAndroid Build Coastguard Worker 
452*795d594fSAndroid Build Coastguard Worker     // Write table data.
453*795d594fSAndroid Build Coastguard Worker     for (MemoryRegion row : rows_) {
454*795d594fSAndroid Build Coastguard Worker       size_t bits_to_copy = std::min(max_num_bits_, row.size_in_bits());
455*795d594fSAndroid Build Coastguard Worker       BitMemoryRegion src(row, /*bit_offset=*/ 0u, bits_to_copy);
456*795d594fSAndroid Build Coastguard Worker       BitMemoryRegion dst = out.Allocate(max_num_bits_);
457*795d594fSAndroid Build Coastguard Worker       dst.Subregion(/*bit_offset=*/ 0, bits_to_copy).CopyBits(src);
458*795d594fSAndroid Build Coastguard Worker     }
459*795d594fSAndroid Build Coastguard Worker 
460*795d594fSAndroid Build Coastguard Worker     // Verify the written data.
461*795d594fSAndroid Build Coastguard Worker     if (kIsDebugBuild) {
462*795d594fSAndroid Build Coastguard Worker       BitTableBase<1> table;
463*795d594fSAndroid Build Coastguard Worker       BitMemoryReader reader(out.GetWrittenRegion().Subregion(initial_bit_offset));
464*795d594fSAndroid Build Coastguard Worker       table.Decode(reader);
465*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(size(), table.NumRows());
466*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(max_num_bits_, table.NumColumnBits(0));
467*795d594fSAndroid Build Coastguard Worker       for (uint32_t r = 0; r < size(); r++) {
468*795d594fSAndroid Build Coastguard Worker         BitMemoryRegion expected(rows_[r]);
469*795d594fSAndroid Build Coastguard Worker         BitMemoryRegion seen = table.GetBitMemoryRegion(r);
470*795d594fSAndroid Build Coastguard Worker         size_t num_bits = std::max(expected.size_in_bits(), seen.size_in_bits());
471*795d594fSAndroid Build Coastguard Worker         for (size_t b = 0; b < num_bits; b++) {
472*795d594fSAndroid Build Coastguard Worker           bool e = b < expected.size_in_bits() && expected.LoadBit(b);
473*795d594fSAndroid Build Coastguard Worker           bool s = b < seen.size_in_bits() && seen.LoadBit(b);
474*795d594fSAndroid Build Coastguard Worker           DCHECK_EQ(e, s) << " (" << r << ")[" << b << "]";
475*795d594fSAndroid Build Coastguard Worker         }
476*795d594fSAndroid Build Coastguard Worker       }
477*795d594fSAndroid Build Coastguard Worker     }
478*795d594fSAndroid Build Coastguard Worker   }
479*795d594fSAndroid Build Coastguard Worker 
480*795d594fSAndroid Build Coastguard Worker  private:
481*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator* const allocator_;
482*795d594fSAndroid Build Coastguard Worker   ScopedArenaDeque<MemoryRegion> rows_;
483*795d594fSAndroid Build Coastguard Worker   ScopedArenaUnorderedMultimap<uint32_t, uint32_t> dedup_;  // Hash -> row index.
484*795d594fSAndroid Build Coastguard Worker   size_t max_num_bits_ = 0u;
485*795d594fSAndroid Build Coastguard Worker };
486*795d594fSAndroid Build Coastguard Worker 
487*795d594fSAndroid Build Coastguard Worker }  // namespace art
488*795d594fSAndroid Build Coastguard Worker 
489*795d594fSAndroid Build Coastguard Worker #endif  // ART_LIBARTBASE_BASE_BIT_TABLE_H_
490