| 75 | |
| 76 | |
| 77 | class TCompressedArray { |
| 78 | public: |
| 79 | TCompressedArray() = default; |
| 80 | |
| 81 | TCompressedArray(ui64 size, ui32 bitsPerKey, NCB::TMaybeOwningArrayHolder<ui64> storage) |
| 82 | : Size(size) |
| 83 | , IndexHelper(bitsPerKey) |
| 84 | , Storage(std::move(storage)) |
| 85 | {} |
| 86 | |
| 87 | TCompressedArray(ui64 size, ui32 bitsPerKey, TVector<ui64>&& storage) |
| 88 | : Size(size) |
| 89 | , IndexHelper(bitsPerKey) |
| 90 | , Storage(NCB::TMaybeOwningArrayHolder<ui64>::CreateOwning(std::move(storage))) |
| 91 | {} |
| 92 | |
| 93 | // init later using GetRawArray or GetRawPtr |
| 94 | static TCompressedArray CreateWithUninitializedData(ui64 size, ui32 bitsPerKey) { |
| 95 | TIndexHelper<ui64> indexHelper(bitsPerKey); |
| 96 | TVector<ui64> storage; |
| 97 | storage.yresize(indexHelper.CompressedSize(size)); |
| 98 | return TCompressedArray(size, bitsPerKey, std::move(storage)); |
| 99 | } |
| 100 | |
| 101 | SAVELOAD(Size, IndexHelper, Storage); |
| 102 | |
| 103 | ui64 GetSize() const { |
| 104 | return Size; |
| 105 | } |
| 106 | |
| 107 | ui32 GetBitsPerKey() const { |
| 108 | return IndexHelper.GetBitsPerKey(); |
| 109 | } |
| 110 | |
| 111 | template <class T = ui32> |
| 112 | T operator[](ui32 index) const { |
| 113 | Y_ASSERT(index < Size); |
| 114 | return IndexHelper.Extract<T>(*Storage, index); |
| 115 | } |
| 116 | |
| 117 | // comparison is strict by default, useful for unit tests |
| 118 | bool operator==(const TCompressedArray& rhs) const { |
| 119 | return EqualTo(rhs, /*strict*/ true); |
| 120 | } |
| 121 | |
| 122 | template <class T> |
| 123 | bool operator==(TConstArrayRef<T> rhs) const { |
| 124 | static_assert(std::is_integral<T>::value); |
| 125 | |
| 126 | if (Size != rhs.size()) { |
| 127 | return false; |
| 128 | } |
| 129 | |
| 130 | for (auto i : xrange(Size)) { |
| 131 | if ((*this)[i] != rhs[i]) { |
| 132 | return false; |
| 133 | } |
| 134 | } |
no outgoing calls