-adding flex_string
git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@214 7ec92016-0320-0410-acc4-a06ded1c099a
This commit is contained in:
parent
7d639aff90
commit
f994398a51
8 changed files with 2812 additions and 0 deletions
274
include/loki/flex/allocatorstringstorage.h
Executable file
274
include/loki/flex/allocatorstringstorage.h
Executable file
|
@ -0,0 +1,274 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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;
|
||||||
|
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_
|
275
include/loki/flex/cowstringopt.h
Executable file
275
include/loki/flex/cowstringopt.h
Executable file
|
@ -0,0 +1,275 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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 COW_STRING_OPT_INC_
|
||||||
|
#define COW_STRING_OPT_INC_
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// class template CowStringOpt
|
||||||
|
// Implements Copy on Write over any storage
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
void append(const E* s, size_type sz);
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
void append(InputIterator b, InputIterator 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"
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// class template CowStringOpt
|
||||||
|
// Implements Copy on Write over any storage
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template <class Storage, typename Align = typename Storage::value_type*>
|
||||||
|
class CowStringOpt
|
||||||
|
{
|
||||||
|
typedef typename Storage::value_type E;
|
||||||
|
typedef typename flex_string_details::get_unsigned<E>::result RefCountType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef E value_type;
|
||||||
|
typedef typename Storage::iterator iterator;
|
||||||
|
typedef typename Storage::const_iterator const_iterator;
|
||||||
|
typedef typename Storage::allocator_type allocator_type;
|
||||||
|
typedef typename allocator_type::size_type size_type;
|
||||||
|
typedef typename Storage::reference reference;
|
||||||
|
|
||||||
|
private:
|
||||||
|
union
|
||||||
|
{
|
||||||
|
mutable char buf_[sizeof(Storage)];
|
||||||
|
Align align_;
|
||||||
|
};
|
||||||
|
|
||||||
|
Storage& Data() const
|
||||||
|
{ return *reinterpret_cast<Storage*>(buf_); }
|
||||||
|
|
||||||
|
RefCountType GetRefs() const
|
||||||
|
{
|
||||||
|
const Storage& d = Data();
|
||||||
|
assert(d.size() > 0);
|
||||||
|
assert(*d.begin() > 0);
|
||||||
|
return *d.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
RefCountType& Refs()
|
||||||
|
{
|
||||||
|
Storage& d = Data();
|
||||||
|
assert(d.size() > 0);
|
||||||
|
return reinterpret_cast<RefCountType&>(*d.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MakeUnique() const
|
||||||
|
{
|
||||||
|
assert(GetRefs() >= 1);
|
||||||
|
if (GetRefs() == 1) return;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
char buf_[sizeof(Storage)];
|
||||||
|
Align align_;
|
||||||
|
} temp;
|
||||||
|
|
||||||
|
new(buf_) Storage(
|
||||||
|
*new(temp.buf_) Storage(Data()),
|
||||||
|
flex_string_details::Shallow());
|
||||||
|
*Data().begin() = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
CowStringOpt(const CowStringOpt& s)
|
||||||
|
{
|
||||||
|
if (s.GetRefs() == std::numeric_limits<RefCountType>::max())
|
||||||
|
{
|
||||||
|
// must make a brand new copy
|
||||||
|
new(buf_) Storage(s.Data()); // non shallow
|
||||||
|
Refs() = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new(buf_) Storage(s.Data(), flex_string_details::Shallow());
|
||||||
|
++Refs();
|
||||||
|
}
|
||||||
|
assert(Data().size() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
CowStringOpt(const allocator_type& a)
|
||||||
|
{
|
||||||
|
new(buf_) Storage(1, 1, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
CowStringOpt(const E* s, size_type len, const allocator_type& a)
|
||||||
|
{
|
||||||
|
// Warning - MSVC's debugger has trouble tracing through the code below.
|
||||||
|
// It seems to be a const-correctness issue
|
||||||
|
//
|
||||||
|
new(buf_) Storage(a);
|
||||||
|
Data().reserve(len + 1);
|
||||||
|
Data().resize(1, 1);
|
||||||
|
Data().append(s, s + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
CowStringOpt(size_type len, E c, const allocator_type& a)
|
||||||
|
{
|
||||||
|
new(buf_) Storage(len + 1, c, a);
|
||||||
|
Refs() = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CowStringOpt& operator=(const CowStringOpt& rhs)
|
||||||
|
{
|
||||||
|
CowStringOpt(rhs).swap(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~CowStringOpt()
|
||||||
|
{
|
||||||
|
assert(Data().size() > 0);
|
||||||
|
if (--Refs() == 0) Data().~Storage();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
assert(Data().size() > 0);
|
||||||
|
MakeUnique();
|
||||||
|
return Data().begin() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
assert(Data().size() > 0);
|
||||||
|
return Data().begin() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
MakeUnique();
|
||||||
|
return Data().end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return Data().end();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type size() const
|
||||||
|
{
|
||||||
|
assert(Data().size() > 0);
|
||||||
|
return Data().size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type max_size() const
|
||||||
|
{
|
||||||
|
assert(Data().max_size() > 0);
|
||||||
|
return Data().max_size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type capacity() const
|
||||||
|
{
|
||||||
|
assert(Data().capacity() > 0);
|
||||||
|
return Data().capacity() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(size_type n, E c)
|
||||||
|
{
|
||||||
|
assert(Data().size() > 0);
|
||||||
|
MakeUnique();
|
||||||
|
Data().resize(n + 1, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class FwdIterator>
|
||||||
|
void append(FwdIterator b, FwdIterator e)
|
||||||
|
{
|
||||||
|
MakeUnique();
|
||||||
|
Data().append(b, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(size_type res_arg)
|
||||||
|
{
|
||||||
|
if (capacity() > res_arg) return;
|
||||||
|
MakeUnique();
|
||||||
|
Data().reserve(res_arg + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(CowStringOpt& rhs)
|
||||||
|
{
|
||||||
|
Data().swap(rhs.Data());
|
||||||
|
}
|
||||||
|
|
||||||
|
const E* c_str() const
|
||||||
|
{
|
||||||
|
assert(Data().size() > 0);
|
||||||
|
return Data().c_str() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const E* data() const
|
||||||
|
{
|
||||||
|
assert(Data().size() > 0);
|
||||||
|
return Data().data() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
allocator_type get_allocator() const
|
||||||
|
{
|
||||||
|
return Data().get_allocator();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // COW_STRING_OPT_INC_
|
28
include/loki/flex/flex_string.h
Executable file
28
include/loki/flex/flex_string.h
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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 FLEX_STRING_INC_
|
||||||
|
#define FLEX_STRING_INC_
|
||||||
|
|
||||||
|
|
||||||
|
// <THE> string
|
||||||
|
#include "flex_string_shell.h"
|
||||||
|
|
||||||
|
// Storage policies
|
||||||
|
#include "simplestringstorage.h"
|
||||||
|
#include "allocatorstringstorage.h"
|
||||||
|
#include "vectorstringstorage.h"
|
||||||
|
#include "smallstringopt.h"
|
||||||
|
#include "cowstringopt.h"
|
||||||
|
//#include "utf16encoding.h"
|
||||||
|
|
||||||
|
#endif // FLEX_STRING_INC_
|
99
include/loki/flex/flex_string_details.h
Executable file
99
include/loki/flex/flex_string_details.h
Executable file
|
@ -0,0 +1,99 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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 FLEX_STRING_DETAILS_INC_
|
||||||
|
#define FLEX_STRING_DETAILS_INC_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace flex_string_details
|
||||||
|
{
|
||||||
|
template <class InIt, class OutIt>
|
||||||
|
OutIt copy_n(InIt b, typename std::iterator_traits<InIt>::difference_type n, OutIt d)
|
||||||
|
{
|
||||||
|
for (; n != 0; --n, ++b, ++d)
|
||||||
|
{
|
||||||
|
*d = *b;
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Pod, class T>
|
||||||
|
inline void pod_fill(Pod* b, Pod* e, T c)
|
||||||
|
{
|
||||||
|
switch ((e - b) & 7)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
while (b != e)
|
||||||
|
{
|
||||||
|
*b = c; ++b;
|
||||||
|
case 7: *b = c; ++b;
|
||||||
|
case 6: *b = c; ++b;
|
||||||
|
case 5: *b = c; ++b;
|
||||||
|
case 4: *b = c; ++b;
|
||||||
|
case 3: *b = c; ++b;
|
||||||
|
case 2: *b = c; ++b;
|
||||||
|
case 1: *b = c; ++b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Pod>
|
||||||
|
inline void pod_move(const Pod* b, const Pod* e, Pod* d)
|
||||||
|
{
|
||||||
|
using namespace std;
|
||||||
|
memmove(d, b, (e - b) * sizeof(*b));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Pod>
|
||||||
|
inline Pod* pod_copy(const Pod* b, const Pod* e, Pod* d)
|
||||||
|
{
|
||||||
|
const size_t s = e - b;
|
||||||
|
using namespace std;
|
||||||
|
memcpy(d, b, s * sizeof(*b));
|
||||||
|
return d + s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> struct get_unsigned
|
||||||
|
{
|
||||||
|
typedef T result;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct get_unsigned<char>
|
||||||
|
{
|
||||||
|
typedef unsigned char result;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct get_unsigned<signed char>
|
||||||
|
{
|
||||||
|
typedef unsigned char result;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct get_unsigned<short int>
|
||||||
|
{
|
||||||
|
typedef unsigned short int result;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct get_unsigned<int>
|
||||||
|
{
|
||||||
|
typedef unsigned int result;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct get_unsigned<long int>
|
||||||
|
{
|
||||||
|
typedef unsigned long int result;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Shallow {};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FLEX_STRING_DETAILS_INC_
|
1274
include/loki/flex/flex_string_shell.h
Executable file
1274
include/loki/flex/flex_string_shell.h
Executable file
File diff suppressed because it is too large
Load diff
281
include/loki/flex/simplestringstorage.h
Executable file
281
include/loki/flex/simplestringstorage.h
Executable file
|
@ -0,0 +1,281 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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_
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
// accomodate 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;
|
||||||
|
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_
|
392
include/loki/flex/smallstringopt.h
Executable file
392
include/loki/flex/smallstringopt.h
Executable file
|
@ -0,0 +1,392 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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 SMALL_STRING_OPT_INC_
|
||||||
|
#define SMALL_STRING_OPT_INC_
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// class template SmallStringOpt
|
||||||
|
// Builds the small string optimization over any other storage
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
void append(const E* s, size_type sz);
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
void append(InputIterator b, InputIterator 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"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// class template SmallStringOpt
|
||||||
|
// Builds the small string optimization over any other storage
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template <class Storage, unsigned int threshold,
|
||||||
|
typename Align = typename Storage::value_type*>
|
||||||
|
class SmallStringOpt
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename Storage::value_type value_type;
|
||||||
|
typedef value_type* iterator;
|
||||||
|
typedef const value_type* const_iterator;
|
||||||
|
typedef typename Storage::allocator_type allocator_type;
|
||||||
|
typedef typename allocator_type::size_type size_type;
|
||||||
|
typedef typename Storage::reference reference;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum { temp1 = threshold * sizeof(value_type) > sizeof(Storage)
|
||||||
|
? threshold * sizeof(value_type)
|
||||||
|
: sizeof(Storage) };
|
||||||
|
|
||||||
|
enum { temp2 = temp1 > sizeof(Align) ? temp1 : sizeof(Align) };
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum { maxSmallString =
|
||||||
|
(temp2 + sizeof(value_type) - 1) / sizeof(value_type) };
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum { magic = maxSmallString + 1 };
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
mutable value_type buf_[maxSmallString + 1];
|
||||||
|
Align align_;
|
||||||
|
};
|
||||||
|
|
||||||
|
Storage& GetStorage()
|
||||||
|
{
|
||||||
|
assert(buf_[maxSmallString] == magic);
|
||||||
|
Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Storage& GetStorage() const
|
||||||
|
{
|
||||||
|
assert(buf_[maxSmallString] == magic);
|
||||||
|
const Storage *p = reinterpret_cast<const Storage*>(&buf_[0]);
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Small() const
|
||||||
|
{
|
||||||
|
return buf_[maxSmallString] != magic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
SmallStringOpt(const SmallStringOpt& s)
|
||||||
|
{
|
||||||
|
if (s.Small())
|
||||||
|
{
|
||||||
|
flex_string_details::pod_copy(
|
||||||
|
s.buf_,
|
||||||
|
s.buf_ + s.size(),
|
||||||
|
buf_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new(buf_) Storage(s.GetStorage());
|
||||||
|
}
|
||||||
|
buf_[maxSmallString] = s.buf_[maxSmallString];
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallStringOpt(const allocator_type&)
|
||||||
|
{
|
||||||
|
buf_[maxSmallString] = maxSmallString;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallStringOpt(const value_type* s, size_type len, const allocator_type& a)
|
||||||
|
{
|
||||||
|
if (len <= maxSmallString)
|
||||||
|
{
|
||||||
|
flex_string_details::pod_copy(s, s + len, buf_);
|
||||||
|
buf_[maxSmallString] = value_type(maxSmallString - len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new(buf_) Storage(s, len, a);
|
||||||
|
buf_[maxSmallString] = magic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallStringOpt(size_type len, value_type c, const allocator_type& a)
|
||||||
|
{
|
||||||
|
if (len <= maxSmallString)
|
||||||
|
{
|
||||||
|
flex_string_details::pod_fill(buf_, buf_ + len, c);
|
||||||
|
buf_[maxSmallString] = value_type(maxSmallString - len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new(buf_) Storage(len, c, a);
|
||||||
|
buf_[maxSmallString] = magic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallStringOpt& operator=(const SmallStringOpt& rhs)
|
||||||
|
{
|
||||||
|
if (&rhs != this)
|
||||||
|
{
|
||||||
|
reserve(rhs.size());
|
||||||
|
resize(0, 0);
|
||||||
|
append(rhs.data(), rhs.data() + rhs.size());
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~SmallStringOpt()
|
||||||
|
{
|
||||||
|
if (!Small()) GetStorage().~Storage();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
if (Small()) return buf_;
|
||||||
|
return &*GetStorage().begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
if (Small()) return buf_;
|
||||||
|
return &*GetStorage().begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
|
||||||
|
return &*GetStorage().end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
|
||||||
|
return &*GetStorage().end();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type size() const
|
||||||
|
{
|
||||||
|
assert(!Small() || maxSmallString >= buf_[maxSmallString]);
|
||||||
|
return Small()
|
||||||
|
? maxSmallString - buf_[maxSmallString]
|
||||||
|
: GetStorage().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type max_size() const
|
||||||
|
{ return get_allocator().max_size(); }
|
||||||
|
|
||||||
|
size_type capacity() const
|
||||||
|
{ return Small() ? maxSmallString : GetStorage().capacity(); }
|
||||||
|
|
||||||
|
void reserve(size_type res_arg)
|
||||||
|
{
|
||||||
|
if (Small())
|
||||||
|
{
|
||||||
|
if (res_arg <= maxSmallString) return;
|
||||||
|
SmallStringOpt temp(*this);
|
||||||
|
this->~SmallStringOpt();
|
||||||
|
new(buf_) Storage(temp.data(), temp.size(),
|
||||||
|
temp.get_allocator());
|
||||||
|
buf_[maxSmallString] = magic;
|
||||||
|
GetStorage().reserve(res_arg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GetStorage().reserve(res_arg);
|
||||||
|
}
|
||||||
|
assert(capacity() >= res_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class FwdIterator>
|
||||||
|
void append(FwdIterator b, FwdIterator e)
|
||||||
|
{
|
||||||
|
if (!Small())
|
||||||
|
{
|
||||||
|
GetStorage().append(b, e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// append to a small string
|
||||||
|
const size_type
|
||||||
|
sz = std::distance(b, e),
|
||||||
|
neededCapacity = maxSmallString - buf_[maxSmallString] + sz;
|
||||||
|
|
||||||
|
if (maxSmallString < neededCapacity)
|
||||||
|
{
|
||||||
|
// need to change storage strategy
|
||||||
|
allocator_type alloc;
|
||||||
|
Storage temp(alloc);
|
||||||
|
temp.reserve(neededCapacity);
|
||||||
|
temp.append(buf_, buf_ + maxSmallString - buf_[maxSmallString]);
|
||||||
|
temp.append(b, e);
|
||||||
|
buf_[maxSmallString] = magic;
|
||||||
|
new(buf_) Storage(temp.get_allocator());
|
||||||
|
GetStorage().swap(temp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::copy(b, e, buf_ + maxSmallString - buf_[maxSmallString]);
|
||||||
|
buf_[maxSmallString] -= value_type(sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(size_type n, value_type c)
|
||||||
|
{
|
||||||
|
if (Small())
|
||||||
|
{
|
||||||
|
if (n > maxSmallString)
|
||||||
|
{
|
||||||
|
// Small string resized to big string
|
||||||
|
SmallStringOpt temp(*this); // can't throw
|
||||||
|
// 11-17-2001: correct exception safety bug
|
||||||
|
Storage newString(temp.data(), temp.size(),
|
||||||
|
temp.get_allocator());
|
||||||
|
newString.resize(n, c);
|
||||||
|
// We make the reasonable assumption that an empty Storage
|
||||||
|
// constructor won't throw
|
||||||
|
this->~SmallStringOpt();
|
||||||
|
new(&buf_[0]) Storage(temp.get_allocator());
|
||||||
|
buf_[maxSmallString] = value_type(magic);
|
||||||
|
GetStorage().swap(newString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Small string resized to small string
|
||||||
|
// 11-17-2001: bug fix: terminating zero not copied
|
||||||
|
size_type toFill = n > size() ? n - size() : 0;
|
||||||
|
flex_string_details::pod_fill(end(), end() + toFill, c);
|
||||||
|
buf_[maxSmallString] = value_type(maxSmallString - n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (n > maxSmallString)
|
||||||
|
{
|
||||||
|
// Big string resized to big string
|
||||||
|
GetStorage().resize(n, c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Big string resized to small string
|
||||||
|
// 11-17=2001: bug fix in the assertion below
|
||||||
|
assert(capacity() > n);
|
||||||
|
SmallStringOpt newObj(data(), n, get_allocator());
|
||||||
|
newObj.swap(*this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(SmallStringOpt& rhs)
|
||||||
|
{
|
||||||
|
if (Small())
|
||||||
|
{
|
||||||
|
if (rhs.Small())
|
||||||
|
{
|
||||||
|
// Small swapped with small
|
||||||
|
std::swap_ranges(buf_, buf_ + maxSmallString + 1,
|
||||||
|
rhs.buf_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Small swapped with big
|
||||||
|
// Make a copy of myself - can't throw
|
||||||
|
SmallStringOpt temp(*this);
|
||||||
|
// Nuke myself
|
||||||
|
this->~SmallStringOpt();
|
||||||
|
// Make an empty storage for myself (likely won't throw)
|
||||||
|
new(buf_) Storage(0, value_type(), rhs.get_allocator());
|
||||||
|
buf_[maxSmallString] = magic;
|
||||||
|
// Recurse to this same function
|
||||||
|
swap(rhs);
|
||||||
|
// Nuke rhs
|
||||||
|
rhs.~SmallStringOpt();
|
||||||
|
// Build the new small string into rhs
|
||||||
|
new(&rhs) SmallStringOpt(temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rhs.Small())
|
||||||
|
{
|
||||||
|
// Big swapped with small
|
||||||
|
// Already implemented, recurse with reversed args
|
||||||
|
rhs.swap(*this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Big swapped with big
|
||||||
|
GetStorage().swap(rhs.GetStorage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const value_type* c_str() const
|
||||||
|
{
|
||||||
|
if (!Small()) return GetStorage().c_str();
|
||||||
|
buf_[maxSmallString - buf_[maxSmallString]] = value_type();
|
||||||
|
return buf_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value_type* data() const
|
||||||
|
{ return Small() ? buf_ : GetStorage().data(); }
|
||||||
|
|
||||||
|
allocator_type get_allocator() const
|
||||||
|
{ return allocator_type(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SMALL_STRING_OPT_INC_
|
189
include/loki/flex/vectorstringstorage.h
Executable file
189
include/loki/flex/vectorstringstorage.h
Executable file
|
@ -0,0 +1,189 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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 VECTOR_STRING_STORAGE_INC_
|
||||||
|
#define VECTOR_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);
|
||||||
|
|
||||||
|
void append(const E* s, size_type sz);
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
void append(InputIterator b, InputIterator 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 <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <cassert>
|
||||||
|
#include <limits>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// class template VectorStringStorage
|
||||||
|
// Uses std::vector
|
||||||
|
// Takes advantage of the Empty Base Optimization if available
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template <typename E, class A = std::allocator<E> >
|
||||||
|
class VectorStringStorage : protected std::vector<E, A>
|
||||||
|
{
|
||||||
|
typedef std::vector<E, A> base;
|
||||||
|
|
||||||
|
public: // protected:
|
||||||
|
typedef E value_type;
|
||||||
|
typedef typename base::iterator iterator;
|
||||||
|
typedef typename base::const_iterator const_iterator;
|
||||||
|
typedef A allocator_type;
|
||||||
|
typedef typename A::size_type size_type;
|
||||||
|
typedef typename A::reference reference;
|
||||||
|
|
||||||
|
VectorStringStorage(const VectorStringStorage& s) : base(s)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
VectorStringStorage(const A& a) : base(1, value_type(), a)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
VectorStringStorage(const value_type* s, size_type len, const A& a)
|
||||||
|
: base(a)
|
||||||
|
{
|
||||||
|
base::reserve(len + 1);
|
||||||
|
base::insert(base::end(), s, s + len);
|
||||||
|
// Terminating zero
|
||||||
|
base::push_back(value_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorStringStorage(size_type len, E c, const A& a)
|
||||||
|
: base(len + 1, c, a)
|
||||||
|
{
|
||||||
|
// Terminating zero
|
||||||
|
base::back() = value_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorStringStorage& operator=(const VectorStringStorage& rhs)
|
||||||
|
{
|
||||||
|
base& v = *this;
|
||||||
|
v = rhs;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{ return base::begin(); }
|
||||||
|
|
||||||
|
const_iterator begin() const
|
||||||
|
{ return base::begin(); }
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{ return base::end() - 1; }
|
||||||
|
|
||||||
|
const_iterator end() const
|
||||||
|
{ return base::end() - 1; }
|
||||||
|
|
||||||
|
size_type size() const
|
||||||
|
{ return base::size() - 1; }
|
||||||
|
|
||||||
|
size_type max_size() const
|
||||||
|
{ return base::max_size() - 1; }
|
||||||
|
|
||||||
|
size_type capacity() const
|
||||||
|
{ return base::capacity() - 1; }
|
||||||
|
|
||||||
|
void reserve(size_type res_arg)
|
||||||
|
{
|
||||||
|
assert(res_arg < max_size());
|
||||||
|
base::reserve(res_arg + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ForwardIterator>
|
||||||
|
void append(ForwardIterator b, ForwardIterator e)
|
||||||
|
{
|
||||||
|
const typename std::iterator_traits<ForwardIterator>::difference_type
|
||||||
|
sz = std::distance(b, e);
|
||||||
|
assert(sz >= 0);
|
||||||
|
if (sz == 0) return;
|
||||||
|
base::reserve(base::size() + sz);
|
||||||
|
const value_type & v = *b;
|
||||||
|
struct OnBlockExit
|
||||||
|
{
|
||||||
|
VectorStringStorage * that;
|
||||||
|
~OnBlockExit()
|
||||||
|
{
|
||||||
|
that->base::push_back(value_type());
|
||||||
|
}
|
||||||
|
} onBlockExit = { this };
|
||||||
|
assert(!base::empty());
|
||||||
|
assert(base::back() == value_type());
|
||||||
|
base::back() = v;
|
||||||
|
base::insert(base::end(), ++b, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(size_type n, E c)
|
||||||
|
{
|
||||||
|
base::reserve(n + 1);
|
||||||
|
base::back() = c;
|
||||||
|
base::resize(n + 1, c);
|
||||||
|
base::back() = E();
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(VectorStringStorage& rhs)
|
||||||
|
{ base::swap(rhs); }
|
||||||
|
|
||||||
|
const E* c_str() const
|
||||||
|
{ return &*begin(); }
|
||||||
|
|
||||||
|
const E* data() const
|
||||||
|
{ return &*begin(); }
|
||||||
|
|
||||||
|
A get_allocator() const
|
||||||
|
{ return base::get_allocator(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // VECTOR_STRING_STORAGE_INC_
|
Loading…
Add table
Add a link
Reference in a new issue