Sux
Vector.hpp
Go to the documentation of this file.
1 /*
2  * Sux: Succinct data structures
3  *
4  * Copyright (C) 2019-2020 Stefano Marchini
5  *
6  * This library is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by the Free
8  * Software Foundation; either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * This library is free software; you can redistribute it and/or modify it under
12  * the terms of the GNU General Public License as published by the Free Software
13  * Foundation; either version 3, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
17  * PARTICULAR PURPOSE. See the GNU General Public License for more details.
18  *
19  * Under Section 7 of GPL version 3, you are granted additional permissions
20  * described in the GCC Runtime Library Exception, version 3.1, as published by
21  * the Free Software Foundation.
22  *
23  * You should have received a copy of the GNU General Public License and a copy of
24  * the GCC Runtime Library Exception along with this program; see the files
25  * COPYING3 and COPYING.RUNTIME respectively. If not, see
26  * <http://www.gnu.org/licenses/>.
27  */
28 
29 #pragma once
30 
31 #include "../support/common.hpp"
32 #include "Expandable.hpp"
33 #include <assert.h>
34 #include <iostream>
35 #include <string>
36 #include <sys/mman.h>
37 
38 namespace sux::util {
39 
45 enum AllocType {
58 };
59 
78 template <typename T, AllocType AT = MALLOC> class Vector : public Expandable {
79 
80 #ifndef MAP_HUGETLB
81 #pragma message("Huge pages not supported")
82 #define MAP_HUGETLB 0
83 #define MADV_HUGEPAGE 0
84 #endif
85 
86  public:
87  static constexpr int PROT = PROT_READ | PROT_WRITE;
88  static constexpr int FLAGS = MAP_PRIVATE | MAP_ANONYMOUS | (AT == FORCEHUGEPAGE ? MAP_HUGETLB : 0);
89 
90  private:
91  size_t _size = 0, _capacity = 0;
92  T *data = nullptr;
93 
94  public:
95  Vector<T, AT>() = default;
96 
97  explicit Vector<T, AT>(size_t length) { size(length); }
98 
99  explicit Vector<T, AT>(const T *data, size_t length) : Vector(length) { memcpy(this->data, data, length); }
100 
102  if (data) {
103  if (AT == MALLOC) {
104  free(data);
105  } else {
106  int result = munmap(data, _capacity);
107  assert(result == 0 && "mmunmap failed");
108  }
109  }
110  }
111 
112  // Delete copy operators
113  Vector(const Vector &) = delete;
114  Vector &operator=(const Vector &) = delete;
115 
116  // Define move operators
117  Vector(Vector<T, AT> &&oth) : _size(std::exchange(oth._size, 0)), _capacity(std::exchange(oth._capacity, 0)), data(std::exchange(oth.data, nullptr)) {}
118 
120  swap(*this, oth);
121  return *this;
122  }
123 
127  void trim(size_t capacity) {
128  if (capacity >= _size && capacity < _capacity) remap(capacity);
129  }
130 
132  void trimToFit() { trim(_size); }
133 
141  void reserve(size_t capacity) {
142  if (capacity > _capacity) remap(capacity);
143  }
144 
153  void grow(size_t capacity) {
154  if (capacity > _capacity) remap(max(capacity, _capacity + (_capacity / 2)));
155  }
156 
166  void resize(size_t size) {
167  grow(size);
168  _size = size;
169  }
170 
178  void size(size_t size) {
179  reserve(size);
180  _size = size;
181  trimToFit();
182  }
183 
188  void pushBack(T elem) {
189  resize(_size + 1);
190  data[_size - 1] = elem;
191  }
192 
200  T popBack() { return data[--_size]; }
201 
202  friend void swap(Vector<T, AT> &first, Vector<T, AT> &second) noexcept {
203  std::swap(first._size, second._size);
204  std::swap(first._capacity, second._capacity);
205  std::swap(first.data, second.data);
206  }
207 
209  inline T *operator&() const { return data; }
210 
212  inline const T &operator[](size_t i) const { return data[i]; };
213 
215  inline T &operator[](size_t i) { return data[i]; };
216 
218  inline size_t size() const { return _size; }
219 
226  inline size_t capacity() const { return _capacity; }
227 
231  size_t bitCount() const { return sizeof(*this) * 8 + _capacity * sizeof(T) * 8; }
232 
233  private:
234  static size_t page_aligned(size_t size) {
235  if (AT == FORCEHUGEPAGE)
236  return ((2 * 1024 * 1024 - 1) | (size * sizeof(T) - 1)) + 1;
237  else
238  return ((4 * 1024 - 1) | (size * sizeof(T) - 1)) + 1;
239  }
240 
241  void remap(size_t size) {
242  if (size == 0) return;
243 
244  void *mem;
245  size_t space; // Space to allocate, in bytes
246 
247  if (AT == MALLOC) {
248  space = size * sizeof(T);
249  mem = _capacity == 0 ? malloc(space) : realloc(data, space);
250  assert(mem != NULL && "malloc failed");
251  } else {
252  space = page_aligned(size);
253  if (_capacity == 0)
254  mem = mmap(nullptr, space, PROT, FLAGS, -1, 0);
255  else {
256 #ifndef MREMAP_MAYMOVE
257  mem = mmap(nullptr, space, PROT, FLAGS, -1, 0);
258  memcpy(mem, data, page_aligned(_capacity));
259 #else
260  mem = mremap(data, page_aligned(_capacity), space, MREMAP_MAYMOVE, -1, 0);
261 #endif
262  }
263  assert(mem != MAP_FAILED && "mmap failed");
264 
265  if (AT == TRANSHUGEPAGE) {
266  int adv = madvise(mem, space, MADV_HUGEPAGE);
267  assert(adv == 0 && "madvise failed");
268  }
269  }
270 
271  if (_capacity * sizeof(T) < space) memset(static_cast<char *>(mem) + _capacity * sizeof(T), 0, space - _capacity * sizeof(T));
272 
273  _capacity = space / sizeof(T);
274  data = static_cast<T *>(mem);
275  }
276 
277  friend std::ostream &operator<<(std::ostream &os, const Vector<T, AT> &vector) {
278  const uint64_t nsize = vector.size();
279  os.write((char *)&nsize, sizeof(uint64_t));
280  os.write((char *)&vector, vector.size() * sizeof(T));
281  return os;
282  }
283 
284  friend std::istream &operator>>(std::istream &is, Vector<T, AT> &vector) {
285  uint64_t nsize;
286  is.read((char *)&nsize, sizeof(uint64_t));
287  vector = Vector<T, AT>(nsize);
288  is.read((char *)&vector, vector.size() * sizeof(T));
289  return is;
290  }
291 };
292 
293 } // namespace sux::util
sux::util::Vector::operator&
T * operator&() const
Definition: Vector.hpp:209
sux::util::AllocType
AllocType
Definition: Vector.hpp:45
sux::util::FORCEHUGEPAGE
Definition: Vector.hpp:57
sux::util
Definition: Expandable.hpp:37
sux::util::Vector::swap
friend void swap(Vector< T, AT > &first, Vector< T, AT > &second) noexcept
Definition: Vector.hpp:202
sux::util::Expandable
Definition: Expandable.hpp:43
sux::util::SMALLPAGE
Definition: Vector.hpp:49
MAP_HUGETLB
#define MAP_HUGETLB
Definition: Vector.hpp:82
sux::util::Vector::Vector
Vector(Vector< T, AT > &&oth)
Definition: Vector.hpp:117
MADV_HUGEPAGE
#define MADV_HUGEPAGE
Definition: Vector.hpp:83
sux::util::Vector::Vector
Vector()=default
sux::util::Vector::reserve
void reserve(size_t capacity)
Definition: Vector.hpp:141
sux::util::Vector::size
void size(size_t size)
Definition: Vector.hpp:178
sux::util::MALLOC
Definition: Vector.hpp:47
sux::util::Vector::grow
void grow(size_t capacity)
Definition: Vector.hpp:153
Expandable.hpp
sux::util::Vector::bitCount
size_t bitCount() const
Definition: Vector.hpp:231
sux::util::Vector::PROT
static constexpr int PROT
Definition: Vector.hpp:87
sux::util::Vector::trimToFit
void trimToFit()
Definition: Vector.hpp:132
sux::util::Vector::operator=
Vector< T, AT > & operator=(Vector< T, AT > &&oth)
Definition: Vector.hpp:119
sux::util::Vector::size
size_t size() const
Definition: Vector.hpp:218
sux::util::Vector::pushBack
void pushBack(T elem)
Definition: Vector.hpp:188
sux::util::Vector::operator<<
friend std::ostream & operator<<(std::ostream &os, const Vector< T, AT > &vector)
Definition: Vector.hpp:277
sux::util::Vector::resize
void resize(size_t size)
Definition: Vector.hpp:166
sux::util::Vector::operator[]
T & operator[](size_t i)
Definition: Vector.hpp:215
sux::util::Vector::operator[]
const T & operator[](size_t i) const
Definition: Vector.hpp:212
sux::util::Vector::capacity
size_t capacity() const
Definition: Vector.hpp:226
sux::util::TRANSHUGEPAGE
Definition: Vector.hpp:52
sux::util::Vector::operator>>
friend std::istream & operator>>(std::istream &is, Vector< T, AT > &vector)
Definition: Vector.hpp:284
sux::util::Vector
Definition: Vector.hpp:78
sux::util::Vector::FLAGS
static constexpr int FLAGS
Definition: Vector.hpp:88
sux::util::Vector::trim
void trim(size_t capacity)
Definition: Vector.hpp:127
sux::util::Vector::popBack
T popBack()
Definition: Vector.hpp:200
sux::util::Vector::operator=
Vector & operator=(const Vector &)=delete