2012-05-31 04:49:55 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <Yandex/optimization.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Пул, в который можно складывать короткие строки.
|
|
|
|
|
* Сценарий использования:
|
|
|
|
|
* - складываем много строк и запоминаем их адреса;
|
|
|
|
|
* - адреса остаются валидными в течение жизни пула;
|
|
|
|
|
* - при уничтожении пула, вся память освобождается;
|
|
|
|
|
* - память выделяется и освобождается большими кусками;
|
|
|
|
|
* - удаление части данных не предусмотрено;
|
2012-05-31 05:41:56 +00:00
|
|
|
|
* - строки кладутся без выравнивания.
|
2012-05-31 04:49:55 +00:00
|
|
|
|
*/
|
|
|
|
|
class StringPool
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
/// Непрерывный кусок памяти и указатель на свободное место в нём. Односвязный список.
|
|
|
|
|
struct Chunk
|
|
|
|
|
{
|
|
|
|
|
char * begin;
|
|
|
|
|
char * pos;
|
|
|
|
|
char * end;
|
|
|
|
|
|
|
|
|
|
Chunk * prev;
|
|
|
|
|
|
|
|
|
|
Chunk(size_t size_, Chunk * prev_)
|
|
|
|
|
{
|
|
|
|
|
begin = new char[size_];
|
|
|
|
|
pos = begin;
|
|
|
|
|
end = begin + size_;
|
|
|
|
|
prev = prev_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~Chunk()
|
|
|
|
|
{
|
|
|
|
|
if (prev)
|
|
|
|
|
delete prev;
|
|
|
|
|
delete[] begin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t size() { return end - begin; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
size_t growth_factor;
|
|
|
|
|
/// Последний непрерывный кусок памяти.
|
|
|
|
|
Chunk * head;
|
|
|
|
|
|
|
|
|
|
/// Добавить следующий непрерывный кусок памяти размера не меньше заданного.
|
|
|
|
|
void addChunk(size_t min_size)
|
|
|
|
|
{
|
|
|
|
|
if (unlikely(head->size() * growth_factor > min_size))
|
|
|
|
|
min_size = head->size() * growth_factor;
|
|
|
|
|
|
|
|
|
|
head = new Chunk(min_size, head);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
StringPool(size_t initial_size_ = 4096, size_t growth_factor_ = 2)
|
|
|
|
|
: growth_factor(growth_factor_), head(new Chunk(initial_size_, NULL))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~StringPool()
|
|
|
|
|
{
|
|
|
|
|
delete head;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Получить кусок памяти. (Полезно, если размер строки заранее известен, но вставить её нужно по частям.)
|
|
|
|
|
char * alloc(size_t size)
|
|
|
|
|
{
|
|
|
|
|
if (unlikely(head->pos + size > head->end))
|
|
|
|
|
addChunk(size);
|
|
|
|
|
|
|
|
|
|
char * res = head->pos;
|
|
|
|
|
head->pos += size;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Вставить строку.
|
|
|
|
|
const char * insert(const char * data, size_t size)
|
|
|
|
|
{
|
|
|
|
|
char * res = alloc(size);
|
|
|
|
|
memcpy(res, data, size);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|