pasta::bit_vector  v1.0.0
Compact and Fast Rank and Select Data Structure for Bit Vectors
l12_type.hpp
1/*******************************************************************************
2 * This file is part of pasta::bit_vector.
3 *
4 * Copyright (C) 2021 Florian Kurpicz <florian@kurpicz.org>
5 *
6 * pasta::bit_vector is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * pasta::bit_vector is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with pasta::bit_vector. If not, see <http://www.gnu.org/licenses/>.
18 *
19 ******************************************************************************/
20
21#pragma once
22
23#include <array>
24#include <cstdint>
25#include <tlx/define.hpp>
26
27namespace pasta {
28
29/*!
30 * \brief Struct used to store L1- and L2-blocks for \c BitVectorRank and
31 * \c BitVectorSelect.
32 *
33 * In \c L12Entry, the 32-bit L1-block entry is stored, as well as the three
34 * corresponding L2-block entries (each requiring 10 bits). Note that 2 bits
35 * are still unused.
36 */
37struct L12Type {
38 //! Constructor. Empty constructor required for \c tlx::SimpleVector.
39 L12Type() = default;
40
41 /*!
42 * \brief Constructor. Setting all values and packing the L2-block entries.
43 * \param _l1 Value of the L1-block entry.
44 * \param _l2 Values of the three L2-block entries ( as\c std::array).
45 */
46 L12Type(uint32_t const _l1, std::array<uint16_t, 3> const _l2)
47 : l1(_l1),
48 l2_values(((uint32_t(0b1111111111) & _l2[2]) << 20) |
49 ((uint32_t(0b1111111111) & _l2[1]) << 10) |
50 (uint32_t(0b1111111111) & _l2[0])) {}
51
52 /*!
53 * \brief Access operator used to access the L2-block entries individually.
54 * \param index The index (0, 1, or 3) of the L2-block.
55 * \return Popcount of the corresponding L2-block.
56 */
57 inline uint16_t operator[](size_t const index) const {
58 return (l2_values >> (10 * index)) & uint16_t(0b1111111111);
59 }
60
61 //! L1-block value.
62 uint32_t l1;
63 //! Packed L2-block values.
64 uint32_t l2_values;
65} TLX_ATTRIBUTE_PACKED; // struct L12Entry
66
67//! Check that L12Type requires only 64 bits
68static_assert(sizeof(L12Type) == 8);
69
70/*!
71 * \brief Struct used to store L1- and L2-blocks for \c BitVectorFlatRank and
72 * \c BitVectorFlatRankSelect.
73 *
74 * We store the L1-information of 8 L2-blocks in 40 bits and the
75 * corresponding seven L2-information in 12 bits each. Using 12 bits
76 * allows us to store the prefix sum of the popcounts in the 512-bit
77 * L2-blocks. All this can be stored in 128 bits. To be precise 124 bits
78 * would suffice, but the additional 4 bits allow for faster access and
79 * result in exactly the same overhead the non-flat popcount rank and
80 * select data structure has.
81 *
82 * +------+------+------+------+------+------+---+------+------+--------+
83 * | 8bit | 8bit | 8bit | 8bit | 8bit | 8bit |...| 8bit | 8bit | 40 bit |
84 * +------+------+------+------+------+------+---+------+------+--------+
85 * | 3 * 12-bit integer | 3 * 12 bit integer |...| 12 bit int. | L1-info|
86 * +------+------+------+------+------+------+---+------+------+--------+
87 * | 8 | 4/4 | 8 | 8 | 4/4 | 8 |...| 8 | 4/4 + 40 Bit |
88 * +------+------+------+------+------+------+---+------+------+--------+
89 *
90 * The order of the 12-bit integers should remain the same (as they occur
91 * in the bit vector). This helps us to determine the correct block later
92 * on. To this end, we have to split
93 */
94struct BigL12Type {
95 //! Constructor. Empty constructor required for \c tlx::SimpleVector.
96 BigL12Type() = default;
97
98 /*!
99 * \brief Constructor. Setting all values and packing the L2-block entries.
100 * \param _l1 Value of the L1-block entry.
101 * \param _l2 Values of the three L2-block entries ( as\c std::array).
102 */
103 BigL12Type(uint64_t const _l1, std::array<uint16_t, 7>& _l2)
104 : data(((__uint128_t{0b111111111111} & _l2[6]) << 116) |
105 ((__uint128_t{0b111111111111} & _l2[5]) << 104) |
106 ((__uint128_t{0b111111111111} & _l2[4]) << 92) |
107 ((__uint128_t{0b111111111111} & _l2[3]) << 80) |
108 ((__uint128_t{0b111111111111} & _l2[2]) << 68) |
109 ((__uint128_t{0b111111111111} & _l2[1]) << 56) |
110 ((__uint128_t{0b111111111111} & _l2[0]) << 44) |
111 ((__uint128_t{0xFFFFFFFFFFF} & _l1))) {}
112
113 /*!
114 * \brief Access operator used to access the L2-block entries individually.
115 * \param index The index (0 to 6) of the L2-block.
116 * \return Popcount of the corresponding L2-block.
117 */
118 inline uint64_t operator[](size_t const index) const {
119 return (index == 0) ?
120 0 :
121 ((data >> ((12 * index) + 32)) & uint64_t(0b111111111111));
122 // Here, shifting by 32 bits + X is sufficient, because index > 1.
123 }
124
125 /*!
126 * \brief Get the L1-value of the L12-block.
127 * \returns L1-value of the L12-block.
128 */
129 inline uint64_t l1() const {
130 return uint64_t{0xFFFFFFFFFFF} & data;
131 }
132
133 //! All data of the \c BigL12Type packed into 128 bits.
134 __uint128_t data;
135} TLX_ATTRIBUTE_PACKED; // struct BigL12Type
136
137//! Check that BigL12Type requires only 128 bits
138static_assert(sizeof(BigL12Type) == 16);
139
140} // namespace pasta
141
142/******************************************************************************/
Check that L12Type requires only 64 bits.
Definition: l12_type.hpp:94
uint64_t operator[](size_t const index) const
Access operator used to access the L2-block entries individually.
Definition: l12_type.hpp:118
uint64_t l1() const
Get the L1-value of the L12-block.
Definition: l12_type.hpp:129
BigL12Type()=default
Constructor. Empty constructor required for tlx::SimpleVector.
BigL12Type(uint64_t const _l1, std::array< uint16_t, 7 > &_l2)
Constructor. Setting all values and packing the L2-block entries.
Definition: l12_type.hpp:103
__uint128_t data
All data of the BigL12Type packed into 128 bits.
Definition: l12_type.hpp:134
Struct used to store L1- and L2-blocks for BitVectorRank and BitVectorSelect.
Definition: l12_type.hpp:37
L12Type()=default
Constructor. Empty constructor required for tlx::SimpleVector.
L12Type(uint32_t const _l1, std::array< uint16_t, 3 > const _l2)
Constructor. Setting all values and packing the L2-block entries.
Definition: l12_type.hpp:46
uint32_t l2_values
Packed L2-block values.
Definition: l12_type.hpp:64
uint16_t operator[](size_t const index) const
Access operator used to access the L2-block entries individually.
Definition: l12_type.hpp:57
uint32_t l1
L1-block value.
Definition: l12_type.hpp:62