Loki/include/loki/flex/simplestringstorage.h
jfbastien a2e99a55dd Cosmetic: remove trailing spaces.
git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@1008 7ec92016-0320-0410-acc4-a06ded1c099a
2009-03-13 12:07:15 +00:00

285 lines
7.4 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// 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 SIMPLE_STRING_STORAGE_INC_
#define SIMPLE_STRING_STORAGE_INC_
// $Id$
/* 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>
////////////////////////////////////////////////////////////////////////////////
// class template SimpleStringStorage
// Allocates memory with malloc
////////////////////////////////////////////////////////////////////////////////
template <typename E, class A = std::allocator<E> >
class SimpleStringStorage
{
// The "public" below exists because MSVC can't do template typedefs
public:
struct Data
{
Data() : pEnd_(buffer_), pEndOfMem_(buffer_) { buffer_[0] = E(0); }
E* pEnd_;
E* pEndOfMem_;
E buffer_[1];
};
static const Data emptyString_;
typedef typename A::size_type size_type;
private:
Data* pData_;
void Init(size_type size, size_type capacity)
{
assert(size <= capacity);
if (capacity == 0)
{
pData_ = const_cast<Data*>(&emptyString_);
}
else
{
// 11-17-2000: comment added:
// No need to allocate (capacity + 1) to
// accommodate the terminating 0, because Data already
// has one one character in there
pData_ = static_cast<Data*>(
malloc(sizeof(Data) + capacity * sizeof(E)));
if (!pData_) throw std::bad_alloc();
pData_->pEnd_ = pData_->buffer_ + size;
pData_->pEndOfMem_ = pData_->buffer_ + capacity;
}
}
private:
// Warning - this doesn't initialize pData_. Used in reserve()
SimpleStringStorage()
{ }
public:
typedef E value_type;
typedef E* iterator;
typedef const E* const_iterator;
typedef A allocator_type;
typedef typename A::reference reference;
SimpleStringStorage(const SimpleStringStorage& rhs)
{
const size_type sz = rhs.size();
Init(sz, sz);
if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin());
}
SimpleStringStorage(const SimpleStringStorage& s,
flex_string_details::Shallow)
: pData_(s.pData_)
{
}
SimpleStringStorage(const A&)
{ pData_ = const_cast<Data*>(&emptyString_); }
SimpleStringStorage(const E* s, size_type len, const A&)
{
Init(len, len);
flex_string_details::pod_copy(s, s + len, begin());
}
SimpleStringStorage(size_type len, E c, const A&)
{
Init(len, len);
flex_string_details::pod_fill(begin(), end(), c);
}
SimpleStringStorage& operator=(const SimpleStringStorage& rhs)
{
const size_type sz = rhs.size();
reserve(sz);
flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin());
pData_->pEnd_ = &*begin() + sz;
return *this;
}
~SimpleStringStorage()
{
assert(begin() <= end());
if (pData_ != &emptyString_) free(pData_);
}
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 pData_->pEnd_ - pData_->buffer_; }
size_type max_size() const
{ return size_t(-1) / sizeof(E) - sizeof(Data) - 1; }
size_type capacity() const
{ return pData_->pEndOfMem_ - pData_->buffer_; }
void reserve(size_type res_arg)
{
if (res_arg <= capacity())
{
// @@@ insert shrinkage here if you wish
return;
}
if (pData_ == &emptyString_)
{
Init(0, res_arg);
}
else
{
const size_type sz = size();
void* p = realloc(pData_,
sizeof(Data) + res_arg * sizeof(E));
if (!p) throw std::bad_alloc();
if (p != pData_)
{
pData_ = static_cast<Data*>(p);
pData_->pEnd_ = pData_->buffer_ + sz;
}
pData_->pEndOfMem_ = pData_->buffer_ + res_arg;
}
}
template <class InputIterator>
void append(InputIterator b, InputIterator 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()))); // no aliasing
reserve(neededCapacity);
}
std::copy(b, e, end());
pData_->pEnd_ += sz;
}
void resize(size_type newSize, E fill)
{
const int delta = int(newSize - size());
if (delta == 0) return;
if (delta > 0)
{
if (newSize > capacity())
{
reserve(newSize);
}
E* e = &*end();
flex_string_details::pod_fill(e, e + delta, fill);
}
pData_->pEnd_ = pData_->buffer_ + newSize;
}
void swap(SimpleStringStorage& rhs)
{
std::swap(pData_, rhs.pData_);
}
const E* c_str() const
{
if (pData_ != &emptyString_) *pData_->pEnd_ = E();
return pData_->buffer_;
}
const E* data() const
{ return pData_->buffer_; }
A get_allocator() const
{ return A(); }
};
template <typename E, class A>
const typename SimpleStringStorage<E, A>::Data
SimpleStringStorage<E, A>::emptyString_;
//{
// const_cast<E*>(SimpleStringStorage<E, A>::emptyString_.buffer_),
// const_cast<E*>(SimpleStringStorage<E, A>::emptyString_.buffer_),
// { E() }
//};
#endif // SIMPLE_STRING_STORAGE_INC_