Loki/include/loki/flex/allocatorstringstorage.h
syntheticpp d72b2ff1b3 replace tabs with 4 spaces in all files
git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@600 7ec92016-0320-0410-acc4-a06ded1c099a
2006-03-08 17:07:20 +00:00

275 lines
7.2 KiB
C++
Executable file

////////////////////////////////////////////////////////////////////////////////
// flex_string
// Copyright (c) 2001 by Andrei Alexandrescu
// Permission to use, copy, modify, distribute and sell this software for any
// purpose is hereby granted without fee, provided that the above copyright
// notice appear in all copies and that both that copyright notice and this
// permission notice appear in supporting documentation.
// The author makes no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
#ifndef ALLOCATOR_STRING_STORAGE_INC_
#define ALLOCATOR_STRING_STORAGE_INC_
/* This is the template for a storage policy
////////////////////////////////////////////////////////////////////////////////
template <typename E, class A = @>
class StoragePolicy
{
typedef E value_type;
typedef @ iterator;
typedef @ const_iterator;
typedef A allocator_type;
typedef @ size_type;
StoragePolicy(const StoragePolicy& s);
StoragePolicy(const A&);
StoragePolicy(const E* s, size_type len, const A&);
StoragePolicy(size_type len, E c, const A&);
~StoragePolicy();
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
size_type size() const;
size_type max_size() const;
size_type capacity() const;
void reserve(size_type res_arg);
template <class ForwardIterator>
void append(ForwardIterator b, ForwardIterator e);
void resize(size_type newSize, E fill);
void swap(StoragePolicy& rhs);
const E* c_str() const;
const E* data() const;
A get_allocator() const;
};
////////////////////////////////////////////////////////////////////////////////
*/
#include <memory>
#include <algorithm>
#include <functional>
#include <cassert>
#include <limits>
#include <stdexcept>
#include "flex_string_details.h"
#include "simplestringstorage.h"
////////////////////////////////////////////////////////////////////////////////
// class template AllocatorStringStorage
// Allocates with your allocator
// Takes advantage of the Empty Base Optimization if available
////////////////////////////////////////////////////////////////////////////////
template <typename E, class A = std::allocator<E> >
class AllocatorStringStorage : public A
{
typedef typename A::size_type size_type;
typedef typename SimpleStringStorage<E, A>::Data Data;
void* Alloc(size_type sz, const void* p = 0)
{
return A::allocate(1 + (sz - 1) / sizeof(E),
static_cast<const char*>(p));
}
void* Realloc(void* p, size_type oldSz, size_type newSz)
{
void* r = Alloc(newSz);
flex_string_details::pod_copy(p, p + Min(oldSz, newSz), r);
Free(p, oldSz);
return r;
}
void Free(void* p, size_type sz)
{
A::deallocate(static_cast<E*>(p), sz);
}
Data* pData_;
void Init(size_type size, size_type cap)
{
assert(size <= cap);
if (cap == 0)
{
pData_ = const_cast<Data*>(
&SimpleStringStorage<E, A>::emptyString_);
}
else
{
pData_ = static_cast<Data*>(Alloc(
cap * sizeof(E) + sizeof(Data)));
pData_->pEnd_ = pData_->buffer_ + size;
pData_->pEndOfMem_ = pData_->buffer_ + cap;
}
}
public:
typedef E value_type;
typedef A allocator_type;
typedef typename A::pointer iterator;
typedef typename A::const_pointer const_iterator;
AllocatorStringStorage()
: A(), pData_(0)
{
}
AllocatorStringStorage(const AllocatorStringStorage& rhs)
: A(rhs.get_allocator())
{
const size_type sz = rhs.size();
Init(sz, sz);
if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin());
}
AllocatorStringStorage(const AllocatorStringStorage& s,
flex_string_details::Shallow)
: A(s.get_allocator())
{
pData_ = s.pData_;
}
AllocatorStringStorage(const A& a) : A(a)
{
pData_ = const_cast<Data*>(
&SimpleStringStorage<E, A>::emptyString_);
}
AllocatorStringStorage(const E* s, size_type len, const A& a)
: A(a)
{
Init(len, len);
flex_string_details::pod_copy(s, s + len, begin());
}
AllocatorStringStorage(size_type len, E c, const A& a)
: A(a)
{
Init(len, len);
flex_string_details::pod_fill(&*begin(), &*end(), c);
}
AllocatorStringStorage& operator=(const AllocatorStringStorage& rhs)
{
const size_type sz = rhs.size();
reserve(sz);
flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin());
pData_->pEnd_ = &*begin() + rhs.size();
return *this;
}
~AllocatorStringStorage()
{
if (capacity())
{
Free(pData_,
sizeof(Data) + capacity() * sizeof(E));
}
}
iterator begin()
{ return pData_->buffer_; }
const_iterator begin() const
{ return pData_->buffer_; }
iterator end()
{ return pData_->pEnd_; }
const_iterator end() const
{ return pData_->pEnd_; }
size_type size() const
{ return size_type(end() - begin()); }
size_type max_size() const
{ return A::max_size(); }
size_type capacity() const
{ return size_type(pData_->pEndOfMem_ - pData_->buffer_); }
void resize(size_type n, E c)
{
reserve(n);
iterator newEnd = begin() + n;
iterator oldEnd = end();
if (newEnd > oldEnd)
{
// Copy the characters
flex_string_details::pod_fill(oldEnd, newEnd, c);
}
if (capacity()) pData_->pEnd_ = newEnd;
}
void reserve(size_type res_arg)
{
if (res_arg <= capacity())
{
// @@@ shrink to fit here
return;
}
A& myAlloc = *this;
AllocatorStringStorage newStr(myAlloc);
newStr.Init(size(), res_arg);
flex_string_details::pod_copy(begin(), end(), newStr.begin());
swap(newStr);
}
template <class ForwardIterator>
void append(ForwardIterator b, ForwardIterator e)
{
const size_type
sz = std::distance(b, e),
neededCapacity = size() + sz;
if (capacity() < neededCapacity)
{
static std::less_equal<const E*> le;
(void) le;
assert(!(le(begin(), &*b) && le(&*b, end())));
reserve(neededCapacity);
}
std::copy(b, e, end());
pData_->pEnd_ += sz;
}
void swap(AllocatorStringStorage& rhs)
{
// @@@ The following line is commented due to a bug in MSVC
//std::swap(lhsAlloc, rhsAlloc);
std::swap(pData_, rhs.pData_);
}
const E* c_str() const
{
if (pData_ != &SimpleStringStorage<E, A>::emptyString_)
{
*pData_->pEnd_ = E();
}
return &*begin();
}
const E* data() const
{ return &*begin(); }
A get_allocator() const
{ return *this; }
};
#endif // ALLOCATOR_STRING_STORAGE_INC_