2013-01-07 00:57:43 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
2013-01-07 01:00:35 +00:00
|
|
|
|
#include <cstddef>
|
|
|
|
|
|
2013-01-07 00:57:43 +00:00
|
|
|
|
#include <Yandex/optimization.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/** Массив (почти) неизменяемого размера:
|
|
|
|
|
* размер задаётся в конструкторе;
|
|
|
|
|
* метод resize приводит к удалению старых данных и нужен лишь для того,
|
|
|
|
|
* чтобы можно было сначала создать пустой объект, используя конструктор по-умолчанию,
|
|
|
|
|
* а потом уже определиться с размером.
|
|
|
|
|
*
|
|
|
|
|
* Есть возможность не инициализировать элементы по-умолчанию, а создавать их inplace.
|
|
|
|
|
* Деструкторы элементов вызываются автоматически.
|
|
|
|
|
*
|
|
|
|
|
* sizeof равен размеру одного указателя.
|
|
|
|
|
*
|
|
|
|
|
* Не exception-safe.
|
|
|
|
|
* Копирование и присваивание разрушающее: исходный объект становится пустым.
|
|
|
|
|
* То есть, использовать этот массив во многих случаях неудобно.
|
|
|
|
|
*
|
|
|
|
|
* Предназначен для ситуаций, в которых создаётся много массивов одинакового небольшого размера,
|
|
|
|
|
* но при этом размер не известен во время компиляции.
|
|
|
|
|
* Также даёт существенное преимущество в случаях, когда важно, чтобы sizeof был минимальным.
|
|
|
|
|
* Например, если массивы кладутся в open-addressing хэш-таблицу с inplace хранением значений (как DB::HashMap)
|
|
|
|
|
*
|
|
|
|
|
* В этом случае, по сравнению с std::vector:
|
|
|
|
|
* - для массивов размером в 1 элемент - преимущество примерно в 2 раза;
|
|
|
|
|
* - для массивов размером в 5 элементов - преимущество примерно в 1.5 раза
|
|
|
|
|
* (в качестве T использовались DB::Field, содержащие UInt64 и String);
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
const size_t empty_auto_array_helper = 0;
|
|
|
|
|
|
2013-01-09 12:06:21 +00:00
|
|
|
|
struct DontInitElemsTag {};
|
|
|
|
|
|
2013-01-07 00:57:43 +00:00
|
|
|
|
template <typename T>
|
|
|
|
|
class AutoArray
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
/// Для отложенного создания.
|
|
|
|
|
AutoArray()
|
|
|
|
|
{
|
|
|
|
|
setEmpty();
|
|
|
|
|
}
|
2013-01-09 10:49:57 +00:00
|
|
|
|
|
2013-01-09 11:23:52 +00:00
|
|
|
|
AutoArray(size_t size_)
|
|
|
|
|
{
|
|
|
|
|
init(size_, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Не будут вызваны конструкторы по-умолчанию для элементов.
|
2013-01-07 00:57:43 +00:00
|
|
|
|
* В этом случае, вы должны вставить все элементы с помощью функции place и placement new,
|
|
|
|
|
* так как для них потом будут вызваны деструкторы.
|
|
|
|
|
*/
|
2013-01-09 11:23:52 +00:00
|
|
|
|
AutoArray(size_t size_, const DontInitElemsTag & tag)
|
2013-01-07 00:57:43 +00:00
|
|
|
|
{
|
2013-01-09 11:23:52 +00:00
|
|
|
|
init(size_, true);
|
2013-01-07 00:57:43 +00:00
|
|
|
|
}
|
2013-01-09 10:49:57 +00:00
|
|
|
|
|
|
|
|
|
/** Инициализирует все элементы копирующим конструктором с параметром value.
|
|
|
|
|
*/
|
|
|
|
|
AutoArray(size_t size_, const T & value)
|
|
|
|
|
{
|
|
|
|
|
init(size_, true);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < size_; ++i)
|
|
|
|
|
{
|
|
|
|
|
new (place(i)) T(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-01-07 00:57:43 +00:00
|
|
|
|
|
|
|
|
|
/** resize удаляет все существующие элементы.
|
|
|
|
|
*/
|
|
|
|
|
void resize(size_t size_, bool dont_init_elems = false)
|
|
|
|
|
{
|
|
|
|
|
uninit();
|
|
|
|
|
init(size_, dont_init_elems);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Разрушающее копирование.
|
|
|
|
|
*/
|
|
|
|
|
AutoArray(const AutoArray & src)
|
|
|
|
|
{
|
2013-01-15 19:11:06 +00:00
|
|
|
|
//std::cerr << this << " AutoArray(const AutoArray & src)" << std::endl;
|
|
|
|
|
|
|
|
|
|
setEmpty();
|
|
|
|
|
data = src.data;
|
|
|
|
|
const_cast<AutoArray<T> &>(src).setEmpty();
|
2013-01-07 00:57:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AutoArray & operator= (const AutoArray & src)
|
|
|
|
|
{
|
2013-01-15 19:11:06 +00:00
|
|
|
|
//std::cerr << this << " operator=(const AutoArray & src)" << std::endl;
|
|
|
|
|
|
2013-01-15 18:38:55 +00:00
|
|
|
|
uninit();
|
2013-01-07 00:57:43 +00:00
|
|
|
|
data = src.data;
|
|
|
|
|
const_cast<AutoArray<T> &>(src).setEmpty();
|
2013-01-15 19:11:06 +00:00
|
|
|
|
|
2013-01-07 00:57:43 +00:00
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~AutoArray()
|
|
|
|
|
{
|
|
|
|
|
uninit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t size() const
|
|
|
|
|
{
|
|
|
|
|
return m_size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool empty() const
|
|
|
|
|
{
|
|
|
|
|
return size() == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void clear()
|
|
|
|
|
{
|
|
|
|
|
uninit();
|
|
|
|
|
setEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Можно читать и модифицировать элементы с помощью оператора []
|
|
|
|
|
* только если элементы были инициализированы
|
2013-01-09 12:06:21 +00:00
|
|
|
|
* (то есть, в конструктор не был передан DontInitElemsTag,
|
2013-01-07 00:57:43 +00:00
|
|
|
|
* или вы их инициализировали с помощью place и placement new).
|
|
|
|
|
*/
|
|
|
|
|
T & operator[](size_t i)
|
|
|
|
|
{
|
|
|
|
|
return elem(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const T & operator[](size_t i) const
|
|
|
|
|
{
|
|
|
|
|
return elem(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Получить кусок памяти, в котором должен быть расположен элемент.
|
|
|
|
|
* Функция предназначена, чтобы инициализировать элемент,
|
|
|
|
|
* который ещё не был инициализирован:
|
|
|
|
|
* new (arr.place(i)) T(args);
|
|
|
|
|
*/
|
|
|
|
|
char * place(size_t i)
|
|
|
|
|
{
|
|
|
|
|
return data + sizeof(T) * i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef T * iterator;
|
|
|
|
|
typedef const T * const_iterator;
|
|
|
|
|
|
|
|
|
|
iterator begin() { return &elem(0); }
|
|
|
|
|
iterator end() { return &elem(size()); }
|
|
|
|
|
|
|
|
|
|
const_iterator begin() const { return &elem(0); }
|
|
|
|
|
const_iterator end() const { return &elem(size()); }
|
|
|
|
|
|
|
|
|
|
bool operator== (const AutoArray<T> & rhs) const
|
|
|
|
|
{
|
|
|
|
|
size_t s = size();
|
|
|
|
|
|
|
|
|
|
if (s != rhs.size())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < s; ++i)
|
|
|
|
|
if (elem(i) != rhs.elem(i))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator!= (const AutoArray<T> & rhs) const
|
|
|
|
|
{
|
|
|
|
|
return !(*this == rhs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator< (const AutoArray<T> & rhs) const
|
|
|
|
|
{
|
|
|
|
|
size_t s = size();
|
|
|
|
|
size_t rhs_s = rhs.size();
|
|
|
|
|
|
|
|
|
|
if (s < rhs_s)
|
|
|
|
|
return true;
|
|
|
|
|
if (s > rhs_s)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < s; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (elem(i) < rhs.elem(i))
|
|
|
|
|
return true;
|
|
|
|
|
if (elem(i) > rhs.elem(i))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
char * data;
|
|
|
|
|
|
|
|
|
|
size_t & m_size()
|
|
|
|
|
{
|
|
|
|
|
return reinterpret_cast<size_t *>(data)[-1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t m_size() const
|
|
|
|
|
{
|
|
|
|
|
return reinterpret_cast<const size_t *>(data)[-1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T & elem(size_t i)
|
|
|
|
|
{
|
|
|
|
|
return reinterpret_cast<T *>(data)[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const T & elem(size_t i) const
|
|
|
|
|
{
|
|
|
|
|
return reinterpret_cast<const T *>(data)[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setEmpty()
|
|
|
|
|
{
|
|
|
|
|
data = const_cast<char *>(reinterpret_cast<const char *>(&empty_auto_array_helper)) + sizeof(size_t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void init(size_t size_, bool dont_init_elems)
|
|
|
|
|
{
|
2013-01-08 19:41:22 +00:00
|
|
|
|
if (!size_)
|
2013-01-07 00:57:43 +00:00
|
|
|
|
{
|
|
|
|
|
setEmpty();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data = new char[size_ * sizeof(T) + sizeof(size_t)];
|
|
|
|
|
data += sizeof(size_t);
|
|
|
|
|
m_size() = size_;
|
|
|
|
|
|
|
|
|
|
if (!dont_init_elems)
|
|
|
|
|
for (size_t i = 0; i < size_; ++i)
|
|
|
|
|
new (place(i)) T();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void uninit()
|
|
|
|
|
{
|
|
|
|
|
size_t s = size();
|
|
|
|
|
|
|
|
|
|
if (likely(s))
|
|
|
|
|
{
|
|
|
|
|
for (size_t i = 0; i < s; ++i)
|
|
|
|
|
elem(i).~T();
|
|
|
|
|
|
|
|
|
|
data -= sizeof(size_t);
|
|
|
|
|
delete[] data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|