2013-09-15 10:53:53 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
|
|
#include <boost/noncopyable.hpp>
|
2013-12-08 02:29:40 +00:00
|
|
|
|
#include <boost/iterator_adaptors.hpp>
|
2013-09-15 10:53:53 +00:00
|
|
|
|
|
2015-09-29 19:19:54 +00:00
|
|
|
|
#include <common/likely.h>
|
|
|
|
|
#include <common/strong_typedef.h>
|
2013-09-15 10:53:53 +00:00
|
|
|
|
|
2015-08-16 13:00:22 +00:00
|
|
|
|
#include <DB/Common/Allocator.h>
|
2015-10-05 01:35:28 +00:00
|
|
|
|
#include <DB/Common/Exception.h>
|
2013-09-15 10:53:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/** Динамический массив для POD-типов.
|
|
|
|
|
* Предназначен для небольшого количества больших массивов (а не большого количества маленьких).
|
|
|
|
|
* А точнее - для использования в ColumnVector.
|
|
|
|
|
* Отличается от std::vector тем, что не инициализирует элементы.
|
2013-12-08 02:29:40 +00:00
|
|
|
|
*
|
|
|
|
|
* Сделан некопируемым, чтобы не было случайных копий. Скопировать данные можно с помощью метода assign.
|
|
|
|
|
*
|
2013-09-15 10:53:53 +00:00
|
|
|
|
* Поддерживается только часть интерфейса std::vector.
|
|
|
|
|
*
|
2013-12-08 02:29:40 +00:00
|
|
|
|
* Конструктор по-умолчанию создаёт пустой объект, который не выделяет память.
|
2015-11-15 03:09:40 +00:00
|
|
|
|
* Затем выделяется память минимум под INITIAL_SIZE элементов.
|
2013-12-08 02:29:40 +00:00
|
|
|
|
*
|
2013-09-15 10:53:53 +00:00
|
|
|
|
* Если вставлять элементы push_back-ом, не делая reserve, то PODArray примерно в 2.5 раза быстрее std::vector.
|
|
|
|
|
*/
|
2015-01-22 01:13:13 +00:00
|
|
|
|
|
2015-11-15 03:09:40 +00:00
|
|
|
|
template <typename T, size_t INITIAL_SIZE = 4096, typename TAllocator = Allocator<false>>
|
|
|
|
|
class PODArray : private boost::noncopyable, private TAllocator /// empty base optimization
|
2013-09-15 10:53:53 +00:00
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
char * c_start;
|
|
|
|
|
char * c_end;
|
|
|
|
|
char * c_end_of_storage;
|
|
|
|
|
|
|
|
|
|
T * t_start() { return reinterpret_cast<T *>(c_start); }
|
|
|
|
|
T * t_end() { return reinterpret_cast<T *>(c_end); }
|
|
|
|
|
T * t_end_of_storage() { return reinterpret_cast<T *>(c_end_of_storage); }
|
2014-07-06 04:22:12 +00:00
|
|
|
|
|
2013-09-15 10:53:53 +00:00
|
|
|
|
const T * t_start() const { return reinterpret_cast<const T *>(c_start); }
|
|
|
|
|
const T * t_end() const { return reinterpret_cast<const T *>(c_end); }
|
|
|
|
|
const T * t_end_of_storage() const { return reinterpret_cast<const T *>(c_end_of_storage); }
|
|
|
|
|
|
|
|
|
|
static size_t byte_size(size_t n) { return n * sizeof(T); }
|
|
|
|
|
|
|
|
|
|
static size_t round_up_to_power_of_two(size_t n)
|
|
|
|
|
{
|
|
|
|
|
--n;
|
|
|
|
|
n |= n >> 1;
|
|
|
|
|
n |= n >> 2;
|
|
|
|
|
n |= n >> 4;
|
|
|
|
|
n |= n >> 8;
|
|
|
|
|
n |= n >> 16;
|
|
|
|
|
n |= n >> 32;
|
|
|
|
|
++n;
|
|
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
}
|
2014-07-06 04:22:12 +00:00
|
|
|
|
|
2015-10-16 17:27:11 +00:00
|
|
|
|
static size_t to_size(size_t n) { return byte_size(round_up_to_power_of_two(n)); }
|
2014-07-06 04:22:12 +00:00
|
|
|
|
|
2013-09-15 10:53:53 +00:00
|
|
|
|
void alloc(size_t n)
|
|
|
|
|
{
|
2013-12-08 02:29:40 +00:00
|
|
|
|
if (n == 0)
|
|
|
|
|
{
|
2014-04-08 07:31:51 +00:00
|
|
|
|
c_start = c_end = c_end_of_storage = nullptr;
|
2013-12-08 02:29:40 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2014-07-06 04:22:12 +00:00
|
|
|
|
|
2013-09-15 10:53:53 +00:00
|
|
|
|
size_t bytes_to_alloc = to_size(n);
|
2014-05-03 22:57:43 +00:00
|
|
|
|
|
2015-11-15 03:09:40 +00:00
|
|
|
|
c_start = c_end = reinterpret_cast<char *>(TAllocator::alloc(bytes_to_alloc));
|
2013-09-15 10:53:53 +00:00
|
|
|
|
c_end_of_storage = c_start + bytes_to_alloc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dealloc()
|
|
|
|
|
{
|
2014-04-08 07:31:51 +00:00
|
|
|
|
if (c_start == nullptr)
|
2013-12-08 02:29:40 +00:00
|
|
|
|
return;
|
2014-07-06 04:22:12 +00:00
|
|
|
|
|
2015-11-15 03:09:40 +00:00
|
|
|
|
TAllocator::free(c_start, storage_size());
|
2013-09-15 10:53:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void realloc(size_t n)
|
|
|
|
|
{
|
2014-04-08 07:31:51 +00:00
|
|
|
|
if (c_start == nullptr)
|
2013-12-08 02:29:40 +00:00
|
|
|
|
{
|
|
|
|
|
alloc(n);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-07-06 04:22:12 +00:00
|
|
|
|
|
2013-09-15 10:53:53 +00:00
|
|
|
|
ptrdiff_t end_diff = c_end - c_start;
|
|
|
|
|
size_t bytes_to_alloc = to_size(n);
|
|
|
|
|
|
2015-11-15 03:09:40 +00:00
|
|
|
|
c_start = reinterpret_cast<char *>(TAllocator::realloc(c_start, storage_size(), bytes_to_alloc));
|
2014-04-02 18:38:17 +00:00
|
|
|
|
|
2013-09-15 10:53:53 +00:00
|
|
|
|
c_end = c_start + end_diff;
|
|
|
|
|
c_end_of_storage = c_start + bytes_to_alloc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
typedef T value_type;
|
|
|
|
|
|
2015-03-24 11:30:02 +00:00
|
|
|
|
size_t storage_size() const { return c_end_of_storage - c_start; }
|
2013-09-15 10:53:53 +00:00
|
|
|
|
|
|
|
|
|
/// Просто typedef нельзя, так как возникает неоднозначность для конструкторов и функций assign.
|
2013-12-08 02:29:40 +00:00
|
|
|
|
struct iterator : public boost::iterator_adaptor<iterator, T*>
|
2013-09-15 10:53:53 +00:00
|
|
|
|
{
|
|
|
|
|
iterator() {}
|
2014-12-19 18:33:30 +00:00
|
|
|
|
iterator(T * ptr_) : iterator::iterator_adaptor_(ptr_) {}
|
2013-09-15 10:53:53 +00:00
|
|
|
|
};
|
|
|
|
|
|
2013-12-08 02:29:40 +00:00
|
|
|
|
struct const_iterator : public boost::iterator_adaptor<const_iterator, const T*>
|
2013-09-15 10:53:53 +00:00
|
|
|
|
{
|
|
|
|
|
const_iterator() {}
|
2013-12-08 02:29:40 +00:00
|
|
|
|
const_iterator(const T * ptr_) : const_iterator::iterator_adaptor_(ptr_) {}
|
2013-09-15 10:53:53 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2015-03-17 21:05:03 +00:00
|
|
|
|
PODArray() { alloc(0); }
|
|
|
|
|
PODArray(size_t n) { alloc(n); c_end += byte_size(n); }
|
|
|
|
|
PODArray(size_t n, const T & x) { alloc(n); assign(n, x); }
|
|
|
|
|
PODArray(const_iterator from_begin, const_iterator from_end) { alloc(from_end - from_begin); insert(from_begin, from_end); }
|
2013-09-15 10:53:53 +00:00
|
|
|
|
~PODArray() { dealloc(); }
|
|
|
|
|
|
2015-11-15 05:52:41 +00:00
|
|
|
|
PODArray(PODArray && other)
|
|
|
|
|
{
|
|
|
|
|
c_start = other.c_start;
|
|
|
|
|
c_end = other.c_end;
|
|
|
|
|
c_end_of_storage = other.c_end_of_storage;
|
|
|
|
|
|
|
|
|
|
other.c_start = nullptr;
|
|
|
|
|
other.c_end = nullptr;
|
|
|
|
|
other.c_end_of_storage = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 14:51:28 +00:00
|
|
|
|
PODArray & operator=(PODArray && other)
|
|
|
|
|
{
|
|
|
|
|
std::swap(c_start, other.c_start);
|
|
|
|
|
std::swap(c_end, other.c_end);
|
|
|
|
|
std::swap(c_end_of_storage, other.c_end_of_storage);
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-28 12:32:43 +00:00
|
|
|
|
T * data() { return t_start(); }
|
|
|
|
|
const T * data() const { return t_start(); }
|
2013-12-08 02:29:40 +00:00
|
|
|
|
|
2013-09-15 10:53:53 +00:00
|
|
|
|
size_t size() const { return t_end() - t_start(); }
|
|
|
|
|
bool empty() const { return t_end() == t_start(); }
|
|
|
|
|
size_t capacity() const { return t_end_of_storage() - t_start(); }
|
|
|
|
|
|
|
|
|
|
T & operator[] (size_t n) { return t_start()[n]; }
|
|
|
|
|
const T & operator[] (size_t n) const { return t_start()[n]; }
|
|
|
|
|
|
|
|
|
|
T & front() { return t_start()[0]; }
|
|
|
|
|
T & back() { return t_end()[-1]; }
|
|
|
|
|
const T & front() const { return t_start()[0]; }
|
|
|
|
|
const T & back() const { return t_end()[-1]; }
|
|
|
|
|
|
|
|
|
|
iterator begin() { return t_start(); }
|
|
|
|
|
iterator end() { return t_end(); }
|
|
|
|
|
const_iterator begin() const { return t_start(); }
|
|
|
|
|
const_iterator end() const { return t_end(); }
|
2015-10-15 19:41:32 +00:00
|
|
|
|
const_iterator cbegin() const { return t_start(); }
|
|
|
|
|
const_iterator cend() const { return t_end(); }
|
2013-09-15 10:53:53 +00:00
|
|
|
|
|
|
|
|
|
void reserve(size_t n)
|
|
|
|
|
{
|
|
|
|
|
if (n > capacity())
|
|
|
|
|
realloc(n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void reserve()
|
|
|
|
|
{
|
2013-12-08 02:29:40 +00:00
|
|
|
|
if (size() == 0)
|
2015-11-15 03:09:40 +00:00
|
|
|
|
realloc(INITIAL_SIZE);
|
2013-12-08 02:29:40 +00:00
|
|
|
|
else
|
|
|
|
|
realloc(size() * 2);
|
2013-09-15 10:53:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void resize(size_t n)
|
|
|
|
|
{
|
|
|
|
|
reserve(n);
|
2014-08-28 11:59:41 +00:00
|
|
|
|
resize_assume_reserved(n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void resize_assume_reserved(const size_t n)
|
|
|
|
|
{
|
2013-09-15 10:53:53 +00:00
|
|
|
|
c_end = c_start + byte_size(n);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-03 10:01:04 +00:00
|
|
|
|
/// Как resize, но обнуляет новые элементы.
|
|
|
|
|
void resize_fill(size_t n)
|
|
|
|
|
{
|
|
|
|
|
size_t old_size = size();
|
|
|
|
|
if (n > old_size)
|
|
|
|
|
{
|
|
|
|
|
reserve(n);
|
|
|
|
|
memset(c_end, 0, n - old_size);
|
|
|
|
|
}
|
|
|
|
|
c_end = c_start + byte_size(n);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 16:23:07 +00:00
|
|
|
|
void resize_fill(size_t n, const T & value)
|
|
|
|
|
{
|
|
|
|
|
size_t old_size = size();
|
|
|
|
|
if (n > old_size)
|
|
|
|
|
{
|
|
|
|
|
reserve(n);
|
2015-03-23 13:26:13 +00:00
|
|
|
|
std::fill(t_end(), t_end() + n - old_size, value);
|
2015-01-28 16:23:07 +00:00
|
|
|
|
}
|
|
|
|
|
c_end = c_start + byte_size(n);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-15 10:53:53 +00:00
|
|
|
|
void clear()
|
|
|
|
|
{
|
|
|
|
|
c_end = c_start;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void push_back(const T & x)
|
|
|
|
|
{
|
|
|
|
|
if (unlikely(c_end == c_end_of_storage))
|
|
|
|
|
reserve();
|
|
|
|
|
|
|
|
|
|
*t_end() = x;
|
|
|
|
|
c_end += byte_size(1);
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-15 05:52:41 +00:00
|
|
|
|
template <typename... Args>
|
|
|
|
|
void emplace_back(Args &&... args)
|
|
|
|
|
{
|
|
|
|
|
if (unlikely(c_end == c_end_of_storage))
|
|
|
|
|
reserve();
|
|
|
|
|
|
|
|
|
|
new (t_end()) T(std::forward<Args>(args)...);
|
|
|
|
|
c_end += byte_size(1);
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-16 16:39:39 +00:00
|
|
|
|
void pop_back()
|
|
|
|
|
{
|
|
|
|
|
c_end -= byte_size(1);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-15 10:53:53 +00:00
|
|
|
|
/// Не вставляйте в массив кусок самого себя. Потому что при ресайзе, итераторы на самого себя могут инвалидироваться.
|
2013-12-08 02:29:40 +00:00
|
|
|
|
template <typename It1, typename It2>
|
|
|
|
|
void insert(It1 from_begin, It2 from_end)
|
2013-09-15 10:53:53 +00:00
|
|
|
|
{
|
|
|
|
|
size_t required_capacity = size() + (from_end - from_begin);
|
|
|
|
|
if (required_capacity > capacity())
|
|
|
|
|
reserve(round_up_to_power_of_two(required_capacity));
|
|
|
|
|
|
2014-08-17 07:39:28 +00:00
|
|
|
|
insert_assume_reserved(from_begin, from_end);
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-16 16:39:39 +00:00
|
|
|
|
template <typename It1, typename It2>
|
|
|
|
|
void insert(iterator it, It1 from_begin, It2 from_end)
|
|
|
|
|
{
|
|
|
|
|
size_t required_capacity = size() + (from_end - from_begin);
|
|
|
|
|
if (required_capacity > capacity())
|
|
|
|
|
reserve(round_up_to_power_of_two(required_capacity));
|
|
|
|
|
|
|
|
|
|
size_t bytes_to_copy = byte_size(from_end - from_begin);
|
|
|
|
|
size_t bytes_to_move = (end() - it) * sizeof(T);
|
|
|
|
|
|
|
|
|
|
if (unlikely(bytes_to_move))
|
|
|
|
|
memcpy(c_end + bytes_to_copy - bytes_to_move, c_end - bytes_to_move, bytes_to_move);
|
|
|
|
|
|
|
|
|
|
memcpy(c_end - bytes_to_move, reinterpret_cast<const void *>(&*from_begin), bytes_to_copy);
|
|
|
|
|
c_end += bytes_to_copy;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-17 07:39:28 +00:00
|
|
|
|
template <typename It1, typename It2>
|
|
|
|
|
void insert_assume_reserved(It1 from_begin, It2 from_end)
|
|
|
|
|
{
|
2013-09-15 10:53:53 +00:00
|
|
|
|
size_t bytes_to_copy = byte_size(from_end - from_begin);
|
|
|
|
|
memcpy(c_end, reinterpret_cast<const void *>(&*from_begin), bytes_to_copy);
|
|
|
|
|
c_end += bytes_to_copy;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-15 07:05:01 +00:00
|
|
|
|
void swap(PODArray & rhs)
|
2013-09-15 10:53:53 +00:00
|
|
|
|
{
|
|
|
|
|
std::swap(c_start, rhs.c_start);
|
|
|
|
|
std::swap(c_end, rhs.c_end);
|
|
|
|
|
std::swap(c_end_of_storage, rhs.c_end_of_storage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void assign(size_t n, const T & x)
|
|
|
|
|
{
|
|
|
|
|
resize(n);
|
|
|
|
|
std::fill(begin(), end(), x);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-08 02:29:40 +00:00
|
|
|
|
template <typename It1, typename It2>
|
|
|
|
|
void assign(It1 from_begin, It2 from_end)
|
2013-09-15 10:53:53 +00:00
|
|
|
|
{
|
|
|
|
|
size_t required_capacity = from_end - from_begin;
|
|
|
|
|
if (required_capacity > capacity())
|
|
|
|
|
reserve(round_up_to_power_of_two(required_capacity));
|
|
|
|
|
|
|
|
|
|
size_t bytes_to_copy = byte_size(required_capacity);
|
2013-12-08 02:29:40 +00:00
|
|
|
|
memcpy(c_start, reinterpret_cast<const void *>(&*from_begin), bytes_to_copy);
|
2013-09-15 10:53:53 +00:00
|
|
|
|
c_end = c_start + bytes_to_copy;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-15 07:05:01 +00:00
|
|
|
|
void assign(const PODArray & from)
|
2013-09-15 10:53:53 +00:00
|
|
|
|
{
|
|
|
|
|
assign(from.begin(), from.end());
|
|
|
|
|
}
|
2013-12-08 02:29:40 +00:00
|
|
|
|
|
|
|
|
|
|
2015-11-15 07:05:01 +00:00
|
|
|
|
bool operator== (const PODArray & other) const
|
2013-12-08 02:29:40 +00:00
|
|
|
|
{
|
|
|
|
|
if (size() != other.size())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
const_iterator this_it = begin();
|
|
|
|
|
const_iterator that_it = other.begin();
|
|
|
|
|
|
|
|
|
|
while (this_it != end())
|
|
|
|
|
{
|
|
|
|
|
if (*this_it != *that_it)
|
|
|
|
|
return false;
|
2014-07-06 04:22:12 +00:00
|
|
|
|
|
2013-12-08 02:29:40 +00:00
|
|
|
|
++this_it;
|
|
|
|
|
++that_it;
|
|
|
|
|
}
|
2014-07-06 04:22:12 +00:00
|
|
|
|
|
2013-12-08 02:29:40 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-15 07:05:01 +00:00
|
|
|
|
bool operator!= (const PODArray & other) const
|
2013-12-08 02:29:40 +00:00
|
|
|
|
{
|
|
|
|
|
return !operator==(other);
|
|
|
|
|
}
|
2013-09-15 10:53:53 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|