///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// See accompanying file COPYING.TXT file for licensing details.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_IMPL_STRING_MAP_H
#define CPPCMS_IMPL_STRING_MAP_H
#include <string.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <limits>
#include <booster/noncopyable.h>
namespace cppcms {
namespace impl {
class string_pool : public booster::noncopyable {
public:
string_pool(size_t page_size = 2048) :
page_size_(page_size),
pages_(0),
free_space_(0),
data_(0)
{
}
void set_page_size(size_t n)
{
page_size_ = n;
}
void clear()
{
destroy();
}
~string_pool()
{
destroy();
}
char *alloc(size_t n)
{
char *s = allocate_space(n);
memset(s,0,n);
return s;
}
char *add(std::string const &s)
{
return add(s.c_str());
}
char *add_substr(std::string const &s,size_t pos = 0,size_t len=std::string::npos)
{
if(pos > s.size())
return add("");
return add(s.c_str() + pos,len);
}
char *add(char const *s)
{
return add_bounded_string(s,strlen(s));
}
char *add(char const *b,char const *e)
{
return add(b,e-b);
}
char *add(char const *s,size_t len)
{
char const *tmp = s;
size_t real_len = 0;
while(real_len < len && *tmp!=0) {
real_len ++;
tmp++;
}
return add_bounded_string(s,real_len);
}
private:
void destroy()
{
while(pages_) {
page *p = pages_;
pages_ = pages_->next;
free(p);
}
}
/// data
struct page {
page *next;
char data[1];
};
size_t page_size_;
page *pages_;
size_t free_space_;
char *data_;
char *allocate_space(size_t size)
{
if(size * 2 > page_size_) {
page *p=(page *)malloc(size + sizeof(page));
if(!p)
throw std::bad_alloc();
p->next = pages_->next;
pages_->next = p;
return p->data;
}
if(size > free_space_) {
add_page();
}
char *result = data_;
data_+=size;
free_space_ -= size;
return result;
}
char *add_bounded_string(char const *str,size_t size)
{
char *s=allocate_space(size + 1);
memcpy(s,str,size);
s[size]=0;
return s;
}
void add_page()
{
page *p=(page *)malloc(sizeof(page) + page_size_);
if(!p)
throw std::bad_alloc();
p->next = pages_;
pages_ = p;
data_ = p->data;
free_space_ = page_size_;
}
};
class string_map {
public:
struct entry {
char const *key;
char const *value;
entry(char const *k ="",char const *v="") : key(k),value(v) {}
bool operator<(entry const &other) const
{
return strcmp(key,other.key) < 0;
}
bool operator==(entry const &other) const
{
return strcmp(key,other.key) == 0;
}
};
string_map() : sorted_(true)
{
data_.reserve(64);
}
typedef std::vector<entry>::iterator iterator;
iterator begin()
{
sort();
return data_.begin();
}
iterator end()
{
sort();
return data_.end();
}
void add(char const *key,char const *value)
{
data_.push_back(entry(key,value));
sorted_=false;
}
void sort()
{
if(!sorted_) {
std::sort(data_.begin(),data_.end());
sorted_ = true;
}
}
char const *get(char const *ckey)
{
sort();
entry key(ckey);
iterator p = std::lower_bound(data_.begin(),data_.end(),key);
if(p!=data_.end() && *p==key)
return p->value;
return 0;
}
char const *get_safe(char const *key)
{
char const *value =get(key);
if(value)
return value;
return "";
}
void clear()
{
data_.clear();
sorted_ = false;
}
private:
bool sorted_;
std::vector<entry> data_;
};
} // impl
}
#endif