Bug #2666059: cap buffer size to 126.

git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@1001 7ec92016-0320-0410-acc4-a06ded1c099a
This commit is contained in:
jfbastien 2009-03-05 22:04:56 +00:00
parent a34780ce1e
commit 12a3a50e8e

View file

@ -31,7 +31,7 @@ class StoragePolicy
typedef @ const_iterator; typedef @ const_iterator;
typedef A allocator_type; typedef A allocator_type;
typedef @ size_type; typedef @ size_type;
StoragePolicy(const StoragePolicy& s); StoragePolicy(const StoragePolicy& s);
StoragePolicy(const A&); StoragePolicy(const A&);
StoragePolicy(const E* s, size_type len, const A&); StoragePolicy(const E* s, size_type len, const A&);
@ -42,7 +42,7 @@ class StoragePolicy
const_iterator begin() const; const_iterator begin() const;
iterator end(); iterator end();
const_iterator end() const; const_iterator end() const;
size_type size() const; size_type size() const;
size_type max_size() const; size_type max_size() const;
size_type capacity() const; size_type capacity() const;
@ -50,17 +50,17 @@ class StoragePolicy
void reserve(size_type res_arg); void reserve(size_type res_arg);
void append(const E* s, size_type sz); void append(const E* s, size_type sz);
template <class InputIterator> template <class InputIterator>
void append(InputIterator b, InputIterator e); void append(InputIterator b, InputIterator e);
void resize(size_type newSize, E fill); void resize(size_type newSize, E fill);
void swap(StoragePolicy& rhs); void swap(StoragePolicy& rhs);
const E* c_str() const; const E* c_str() const;
const E* data() const; const E* data() const;
A get_allocator() const; A get_allocator() const;
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -74,12 +74,24 @@ class StoragePolicy
#include <stdexcept> #include <stdexcept>
#include "flex_string_details.h" #include "flex_string_details.h"
namespace SmallStringOptImpl
{
// The threshold for SmallStringOpt cannot be greater than 126. See Loki bug #2666059 for more details:
// https://sourceforge.net/tracker2/?func=detail&aid=2666059&group_id=29557&atid=396644
template<int Expression> struct BufferSizeCannotBeGreaterThan126;
template<> struct BufferSizeCannotBeGreaterThan126<true> { };
#define LOKI_FLEX_STRING_BUFFERSIZECANNOTBEGREATERTHAN126(expression) \
{ SmallStringOptImpl::BufferSizeCannotBeGreaterThan126<((expression) != 0)> \
bufferSizeCannotBeGreaterThan126; (void)bufferSizeCannotBeGreaterThan126; }
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// class template SmallStringOpt // class template SmallStringOpt
// Builds the small string optimization over any other storage // Builds the small string optimization over any other storage
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <class Storage, unsigned int threshold, template <class Storage, unsigned int threshold,
typename Align = typename Storage::value_type*> typename Align = typename Storage::value_type*>
class SmallStringOpt class SmallStringOpt
{ {
@ -90,54 +102,56 @@ public:
typedef typename Storage::allocator_type allocator_type; typedef typename Storage::allocator_type allocator_type;
typedef typename allocator_type::size_type size_type; typedef typename allocator_type::size_type size_type;
typedef typename Storage::reference reference; typedef typename Storage::reference reference;
private: private:
enum { temp1 = threshold * sizeof(value_type) > sizeof(Storage) enum { temp1 = threshold * sizeof(value_type) > sizeof(Storage)
? threshold * sizeof(value_type) ? threshold * sizeof(value_type)
: sizeof(Storage) }; : sizeof(Storage) };
enum { temp2 = temp1 > sizeof(Align) ? temp1 : sizeof(Align) }; enum { temp2 = temp1 > sizeof(Align) ? temp1 : sizeof(Align) };
public: public:
enum { maxSmallString = enum { maxSmallString =
(temp2 + sizeof(value_type) - 1) / sizeof(value_type) }; (temp2 + sizeof(value_type) - 1) / sizeof(value_type) };
private: private:
enum { magic = maxSmallString + 1 }; enum { magic = maxSmallString + 1 };
union union
{ {
mutable value_type buf_[maxSmallString + 1]; mutable value_type buf_[maxSmallString + 1];
Align align_; Align align_;
}; };
Storage& GetStorage() Storage& GetStorage()
{ {
assert(buf_[maxSmallString] == magic); assert(buf_[maxSmallString] == magic);
Storage* p = reinterpret_cast<Storage*>(&buf_[0]); Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
return *p; return *p;
} }
const Storage& GetStorage() const const Storage& GetStorage() const
{ {
assert(buf_[maxSmallString] == magic); assert(buf_[maxSmallString] == magic);
const Storage *p = reinterpret_cast<const Storage*>(&buf_[0]); const Storage *p = reinterpret_cast<const Storage*>(&buf_[0]);
return *p; return *p;
} }
bool Small() const bool Small() const
{ {
return buf_[maxSmallString] != magic; return buf_[maxSmallString] != magic;
} }
public: public:
SmallStringOpt(const SmallStringOpt& s) SmallStringOpt(const SmallStringOpt& s)
{ {
LOKI_FLEX_STRING_BUFFERSIZECANNOTBEGREATERTHAN126(maxSmallString <= 126)
if (s.Small()) if (s.Small())
{ {
flex_string_details::pod_copy( flex_string_details::pod_copy(
s.buf_, s.buf_,
s.buf_ + s.size(), s.buf_ + s.size(),
buf_); buf_);
} }
else else
@ -146,12 +160,12 @@ public:
} }
buf_[maxSmallString] = s.buf_[maxSmallString]; buf_[maxSmallString] = s.buf_[maxSmallString];
} }
SmallStringOpt(const allocator_type&) SmallStringOpt(const allocator_type&)
{ {
buf_[maxSmallString] = maxSmallString; buf_[maxSmallString] = maxSmallString;
} }
SmallStringOpt(const value_type* s, size_type len, const allocator_type& a) SmallStringOpt(const value_type* s, size_type len, const allocator_type& a)
{ {
if (len <= maxSmallString) if (len <= maxSmallString)
@ -179,7 +193,7 @@ public:
buf_[maxSmallString] = magic; buf_[maxSmallString] = magic;
} }
} }
// Fix suggested by Andrew Barnert on 07/03/2007 // Fix suggested by Andrew Barnert on 07/03/2007
SmallStringOpt& operator=(const SmallStringOpt& rhs) SmallStringOpt& operator=(const SmallStringOpt& rhs)
{ {
@ -228,32 +242,32 @@ public:
iterator begin() iterator begin()
{ {
if (Small()) return buf_; if (Small()) return buf_;
return &*GetStorage().begin(); return &*GetStorage().begin();
} }
const_iterator begin() const const_iterator begin() const
{ {
if (Small()) return buf_; if (Small()) return buf_;
return &*GetStorage().begin(); return &*GetStorage().begin();
} }
iterator end() iterator end()
{ {
if (Small()) return buf_ + maxSmallString - buf_[maxSmallString]; if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
return &*GetStorage().end(); return &*GetStorage().end();
} }
const_iterator end() const const_iterator end() const
{ {
if (Small()) return buf_ + maxSmallString - buf_[maxSmallString]; if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
return &*GetStorage().end(); return &*GetStorage().end();
} }
size_type size() const size_type size() const
{ {
assert(!Small() || maxSmallString >= buf_[maxSmallString]); assert(!Small() || maxSmallString >= buf_[maxSmallString]);
return Small() return Small()
? maxSmallString - buf_[maxSmallString] ? maxSmallString - buf_[maxSmallString]
: GetStorage().size(); : GetStorage().size();
} }
@ -270,7 +284,7 @@ public:
if (res_arg <= maxSmallString) return; if (res_arg <= maxSmallString) return;
SmallStringOpt temp(*this); SmallStringOpt temp(*this);
this->~SmallStringOpt(); this->~SmallStringOpt();
new(buf_) Storage(temp.data(), temp.size(), new(buf_) Storage(temp.data(), temp.size(),
temp.get_allocator()); temp.get_allocator());
buf_[maxSmallString] = magic; buf_[maxSmallString] = magic;
GetStorage().reserve(res_arg); GetStorage().reserve(res_arg);
@ -281,7 +295,7 @@ public:
} }
assert(capacity() >= res_arg); assert(capacity() >= res_arg);
} }
template <class FwdIterator> template <class FwdIterator>
void append(FwdIterator b, FwdIterator e) void append(FwdIterator b, FwdIterator e)
{ {
@ -292,7 +306,7 @@ public:
else else
{ {
// append to a small string // append to a small string
const size_type const size_type
sz = std::distance(b, e), sz = std::distance(b, e),
neededCapacity = maxSmallString - buf_[maxSmallString] + sz; neededCapacity = maxSmallString - buf_[maxSmallString] + sz;
@ -325,7 +339,7 @@ public:
// Small string resized to big string // Small string resized to big string
SmallStringOpt temp(*this); // can't throw SmallStringOpt temp(*this); // can't throw
// 11-17-2001: correct exception safety bug // 11-17-2001: correct exception safety bug
Storage newString(temp.data(), temp.size(), Storage newString(temp.data(), temp.size(),
temp.get_allocator()); temp.get_allocator());
newString.resize(n, c); newString.resize(n, c);
// We make the reasonable assumption that an empty Storage // We make the reasonable assumption that an empty Storage
@ -379,7 +393,7 @@ public:
if (rhs.Small()) if (rhs.Small())
{ {
// Small swapped with small // Small swapped with small
std::swap_ranges(buf_, buf_ + maxSmallString + 1, std::swap_ranges(buf_, buf_ + maxSmallString + 1,
rhs.buf_); rhs.buf_);
} }
else else
@ -415,17 +429,17 @@ public:
} }
} }
} }
const value_type* c_str() const const value_type* c_str() const
{ {
if (!Small()) return GetStorage().c_str(); if (!Small()) return GetStorage().c_str();
buf_[maxSmallString - buf_[maxSmallString]] = value_type(); buf_[maxSmallString - buf_[maxSmallString]] = value_type();
return buf_; return buf_;
} }
const value_type* data() const const value_type* data() const
{ return Small() ? buf_ : GetStorage().data(); } { return Small() ? buf_ : GetStorage().data(); }
allocator_type get_allocator() const allocator_type get_allocator() const
{ return allocator_type(); } { return allocator_type(); }
}; };