📄 flex_string.hpp
字号:
{
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)
{
reserve(rhs.size());
resize(0, 0);
append(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
{
BOOST_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);
}
BOOST_ASSERT(capacity() >= res_arg);
}
void append(const value_type* s, size_type sz)
{
if (!Small())
{
GetStorage().append(s, sz);
}
else
{
// append to a small string
const size_type 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_, maxSmallString - buf_[maxSmallString]);
temp.append(s, sz);
buf_[maxSmallString] = magic;
new(buf_) Storage(temp.get_allocator());
GetStorage().swap(temp);
}
else
{
flex_string_details::pod_move(s, s + sz,
buf_ + maxSmallString - buf_[maxSmallString]);
buf_[maxSmallString] -= value_type(sz);
}
}
}
template <class InputIterator>
void append(InputIterator b, InputIterator e)
{
// @@@ todo: optimize this depending on iterator type
for (; b != e; ++b)
{
*this += *b;
}
}
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 BOOST_ASSERTion below
BOOST_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(); }
};
////////////////////////////////////////////////////////////////////////////////
// class template CowString
// Implements Copy on Write over any storage
////////////////////////////////////////////////////////////////////////////////
template <
typename Storage,
typename Align = BOOST_DEDUCED_TYPENAME Storage::value_type*
>
class CowString
{
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;
private:
union
{
mutable char buf_[sizeof(Storage)];
Align align_;
};
Storage& Data() const
{ return *reinterpret_cast<Storage*>(buf_); }
RefCountType GetRefs() const
{
const Storage& d = Data();
BOOST_ASSERT(d.size() > 0);
BOOST_ASSERT(static_cast<RefCountType>(*d.begin()) != 0);
return *d.begin();
}
RefCountType& Refs()
{
Storage& d = Data();
BOOST_ASSERT(d.size() > 0);
return reinterpret_cast<RefCountType&>(*d.begin());
}
void MakeUnique() const
{
BOOST_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:
CowString(const CowString& 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();
}
BOOST_ASSERT(Data().size() > 0);
}
CowString(const allocator_type& a)
{
new(buf_) Storage(1, 1, a);
}
CowString(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, len);
}
CowString(size_type len, E c, const allocator_type& a)
{
new(buf_) Storage(len + 1, c, a);
Refs() = 1;
}
CowString& operator=(const CowString& rhs)
{
// CowString(rhs).swap(*this);
if (--Refs() == 0) Data().~Storage();
if (rhs.GetRefs() == (std::numeric_limits<RefCountType>::max)())
{
// must make a brand new copy
new(buf_) Storage(rhs.Data()); // non shallow
Refs() = 1;
}
else
{
new(buf_) Storage(rhs.Data(), flex_string_details::Shallow());
++Refs();
}
BOOST_ASSERT(Data().size() > 0);
return *this;
}
~CowString()
{
BOOST_ASSERT(Data().size() > 0);
if (--Refs() == 0) Data().~Storage();
}
iterator begin()
{
BOOST_ASSERT(Data().size() > 0);
MakeUnique();
return Data().begin() + 1;
}
const_iterator begin() const
{
BOOST_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
{
BOOST_ASSERT(Data().size() > 0);
return Data().size() - 1;
}
size_type max_size() const
{
BOOST_ASSERT(Data().max_size() > 0);
return Data().max_size() - 1;
}
size_type capacity() const
{
BOOST_ASSERT(Data().capacity() > 0);
return Data().capacity() - 1;
}
void resize(size_type n, E c)
{
BOOST_ASSERT(Data().size() > 0);
MakeUnique();
Data().resize(n + 1, c);
}
void append(const E* s, size_type sz)
{
MakeUnique();
Data().append(s, sz);
}
template <class InputIterator>
void append(InputIterator b, InputIterator e)
{
MakeUnique();
// @@@ todo: optimize this depending on iterator type
for (; b != e; ++b)
{
*this += *b;
}
}
void reserve(size_type res_arg)
{
if (capacity() > res_arg) return;
MakeUnique();
Data().reserve(res_arg + 1);
}
void swap(CowString& rhs)
{
Data().swap(rhs.Data());
}
const E* c_str() const
{
BOOST_ASSERT(Data().size() > 0);
return Data().c_str() + 1;
}
const E* data() const
{
BOOST_ASSERT(Data().size() > 0);
return Data().data() + 1;
}
allocator_type get_allocator() const
{
return Data().get_allocator();
}
};
////////////////////////////////////////////////////////////////////////////////
// class template flex_string
// a std::basic_string compatible implementation
// Uses a Storage policy
////////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -