📄 flex_string.hpp
字号:
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_ = typename SimpleStringStorage<E, A>::Data();
//{
// const_cast<E*>(SimpleStringStorage<E, A>::emptyString_.buffer_),
// const_cast<E*>(SimpleStringStorage<E, A>::emptyString_.buffer_),
// { E() }
//};
////////////////////////////////////////////////////////////////////////////////
// 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)
{
BOOST_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(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);
}
void append(const E* s, size_type sz)
{
const size_type neededCapacity = size() + sz;
if (capacity() < neededCapacity)
{
const iterator b = begin();
static std::less_equal<const E*> le;
if (le(b, s) && le(s, end()))
{
// aliased
const size_type offset = s - b;
reserve(neededCapacity);
s = begin() + offset;
}
else
{
reserve(neededCapacity);
}
}
flex_string_details::pod_copy(s, s + sz, 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; }
};
////////////////////////////////////////////////////////////////////////////////
// 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;
VectorStringStorage(const VectorStringStorage& s) : base(s)
{ }
VectorStringStorage(const A& a) : base(1, E(), a)
{ }
VectorStringStorage(const E* s, size_type len, const A& a)
: base(a)
{
base::reserve(len + 1);
base::insert(base::end(), s, s + len);
// Terminating zero
base::insert(base::end(), E());
}
VectorStringStorage(size_type len, E c, const A& a)
: base(len + 1, c, a)
{
// Terminating zero
base::back() = E();
}
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)
{
BOOST_ASSERT(res_arg < max_size());
base::reserve(res_arg + 1);
}
void append(const E* s, size_type sz)
{
// Check for aliasing because std::vector doesn't do it.
static std::less_equal<const E*> le;
if (!base::empty())
{
const E* start = &base::front();
if (le(start, s) && le(s, start + size()))
{
// aliased
const size_type offset = s - start;
reserve(size() + sz);
s = &base::front() + offset;
}
}
base::insert(end(), s, s + sz);
}
template <class InputIterator>
void append(InputIterator b, InputIterator e)
{
base::insert(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(); }
};
////////////////////////////////////////////////////////////////////////////////
// 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;
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()
{
BOOST_ASSERT(buf_[maxSmallString] == magic);
Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
return *p;
}
const Storage& GetStorage() const
{
BOOST_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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -