// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//

namespace BALL
{

BALL_INLINE 
String::String()
	: str_()
{
}

BALL_INLINE 
String::String(const String& s)
	: str_(s.c_str())
{
}

BALL_INLINE 
String::String(const string& s)
	: str_(s)
{
}

BALL_INLINE
String::String(String&& s)
	: str_(std::move(s))
{
}

BALL_INLINE
String::String(string&& s)
	: str_(std::move(s))
{
}

BALL_INLINE
String& String::operator=(String&& s)
{
	if (this != &s)
	{
		str_.operator=(std::move(s));
	}

	return *this;
}

BALL_INLINE
String& String::operator=(string&& s)
{
	str_.operator=(std::move(s));

	return *this;
}

BALL_INLINE 
String::String(const unsigned char c)
	: str_(1, (char)c)
{
}

BALL_INLINE 
String::String(const char c, Size len)
	: str_(len, c)
{
}

BALL_INLINE 
String::String(const String& s, Index from, Size len)
	: str_("")
{
	s.validateRange_(from, len);
	if (len > 0)
	{
		assign(s.c_str() + from, len);
	}
}

BALL_INLINE 
void String::set(std::stringstream& s)
{
	s >> (*this);
}

BALL_INLINE 
void String::set(char c, Size len)
{
	assign(len, c);
}

BALL_INLINE 
void String::set(unsigned char c)
{
	assign(1, (char)c);
}

BALL_INLINE 
bool String::operator == (const char* char_ptr) const
{
  return (compare(char_ptr) == 0);
}

BALL_INLINE 
bool String::operator != (const char* char_ptr) const
{
  return (compare(char_ptr) != 0);
}

BALL_INLINE 
bool Substring::operator == (const String& s) const
{
	if (bound_ == 0)
	{
		throw UnboundSubstring(__FILE__, __LINE__);
	}

  return (s.compare(bound_->c_str() + from_, 0, to_ - from_ + 1) == 0);
}

BALL_INLINE 
bool Substring::operator != (const String& s) const
{
  if (bound_ == 0)
  {
    throw UnboundSubstring(__FILE__, __LINE__);
	}

  return (s.compare(bound_->c_str() + from_, 0, to_ - from_ + 1) != 0);
}

BALL_INLINE
Size Substring::size() const
{
	if (bound_ == 0)
	{
		return 0;
	}

	return (to_ - from_ + 1);
}

BALL_INLINE 
Substring::operator String() const
{
	if (bound_ == 0)
	{
		throw UnboundSubstring(__FILE__, __LINE__);
	}

  return String(bound_->c_str(), from_, to_ - from_ + 1);
}

/*
BALL_INLINE 
Substring::operator string() const
{
	if (bound_ == 0)
	{
		throw UnboundSubstring(__FILE__, __LINE__);
	}

  return string(bound_->c_str(), from_, to_ - from_ + 1);
}
*/


BALL_INLINE 
void Substring::unbind()
{
  bound_ = 0;
  from_ = to_ = (Index)String::EndPos;
}

BALL_INLINE 
void Substring::destroy()
{
	if (bound_ != 0)
	{
	  bound_->erase(from_, to_ - from_ + 1);
	}

  unbind();
}

BALL_INLINE 
void Substring::clear()
{
	destroy();
}

BALL_INLINE 
String Substring::toString() const
{
	if (bound_ == 0)
	{
		throw UnboundSubstring(__FILE__, __LINE__);
	}

  return String(bound_->c_str(), from_, to_ - from_ + 1);
}

BALL_INLINE 
Substring& Substring::bind(const String& s, Index from, Size len)
{
	s.validateRange_(from, len);

  bound_ = (String *)&s;
  from_ = from;
  to_ = from + (Index)len - 1;

  return *this;
}

BALL_INLINE 
void Substring::set(const String& s)
{
	if (bound_ == 0)
	{
		throw Substring::UnboundSubstring(__FILE__, __LINE__);
	}

  bound_->replace(from_, to_ - from_ + 1, s);
}

BALL_INLINE 
void Substring::set(const Substring& s)
{
	if (bound_ == 0 || s.bound_ == 0)
	{
		throw Substring::UnboundSubstring(__FILE__, __LINE__);
	}

  bound_->replace(from_, to_ - from_ + 1, s.bound_->c_str() + s.from_, s.size());
}

BALL_INLINE 
const Substring& Substring::operator = (const String& s)
{
  set(s);
  return *this;
}

BALL_INLINE 
const Substring& Substring::operator = (const Substring& s)
{
  set(s);
  return *this;
}

BALL_INLINE 
const Substring& Substring::operator = (const char* char_ptr)
{
  set(char_ptr);
  return *this;
}

BALL_INLINE 
String* Substring::getBoundString()
{
  return bound_;
}

BALL_INLINE 
const String* Substring::getBoundString() const
{
  return bound_;
}

BALL_INLINE 
char* Substring::c_str()
{
  if (bound_ == 0)
  {
    throw UnboundSubstring(__FILE__, __LINE__);
	}

  return (char*)&(bound_->c_str()[from_]);
}

BALL_INLINE 
const char* Substring::c_str() const
{
  if (bound_ == 0)
  {
    throw UnboundSubstring(__FILE__, __LINE__);
	}
 
  return &(bound_->c_str()[from_]);
}

BALL_INLINE 
Index Substring::getFirstIndex() const
{
  if (bound_ == 0)
  {
    throw UnboundSubstring(__FILE__, __LINE__);
	}
 
  return from_;
}

BALL_INLINE 
Index Substring::getLastIndex() const
{
  if (bound_ == 0)
  {
    throw UnboundSubstring(__FILE__, __LINE__);
	}
 
  return to_;
}

BALL_INLINE 
char& Substring::operator [] (Index index)
{
  if (bound_ == 0)
  {
    throw UnboundSubstring(__FILE__, __LINE__);
	}
 
	Size len = String::EndPos;
	validateRange_(index, len);

  return (*bound_)[from_ + index];
}

BALL_INLINE 
char Substring::operator [] (Index index) const
{
  if (bound_ == 0)
  {
    throw UnboundSubstring(__FILE__, __LINE__);
	}
 
	Size len = String::EndPos;
	validateRange_(index, len);

  return (*bound_)[from_ + index];
}

BALL_INLINE 
bool Substring::isBound() const
{
  return (bound_ != 0);
}

BALL_INLINE 
bool Substring::isEmpty() const
{
  return (bound_ == 0);
}

BALL_INLINE 
int String::compare(char c, Index from) const
{
	validateIndex_(from);
	return (c_str()[from] - c);
}


BALL_INLINE 
bool Substring::operator == (char c) const
{
  if (bound_ == 0)
  {
    throw UnboundSubstring(__FILE__, __LINE__);
	}
  return (bound_->compare(c, from_, to_ - from_ + 1) == 0);
}

BALL_INLINE 
bool Substring::operator != (char c) const
{
  if (bound_ == 0)
  {
    throw UnboundSubstring(__FILE__, __LINE__);
	}

  return (bound_->compare(c, from_, to_ - from_ + 1) != 0);
}

BALL_INLINE 
bool Substring::isValid() const
{
  return (bound_ != 0 && from_ >= 0 && from_ <= to_ && to_ < (Index)bound_->size()) ;
}

BALL_INLINE 
Substring& Substring::toLower()
{
  if (bound_ == 0)
  {
    throw UnboundSubstring(__FILE__, __LINE__);
	}
	(*bound_).toLower(from_, to_ - from_);
  return *this;
}

BALL_INLINE 
Substring& Substring::toUpper()
{
  if (bound_ == 0)
  {
    throw UnboundSubstring(__FILE__, __LINE__);
	}
	(*bound_).toUpper(from_, to_ - from_);
  return *this;
}

BALL_INLINE 
const String& String::operator = (const String& s)
{
  set(s);
  return *this;
}

BALL_INLINE 
const String& String::operator = (const char* char_ptr)
{
  set(char_ptr, 0);
  return *this;
}

BALL_INLINE 

const String& String::operator = (std::stringstream& s)
{
  set(s);
  return *this;
}

#define BALL_STRING_DEFINE_ASSIGNMENT_METHOD(Type) \
BALL_INLINE \
const String& String::operator = (Type t) \
{ \
  set(t); \
\
  return *this; \
}

BALL_STRING_DEFINE_ASSIGNMENT_METHOD(char)
BALL_STRING_DEFINE_ASSIGNMENT_METHOD(unsigned char)
BALL_STRING_DEFINE_ASSIGNMENT_METHOD(short)
BALL_STRING_DEFINE_ASSIGNMENT_METHOD(unsigned short)
BALL_STRING_DEFINE_ASSIGNMENT_METHOD(int)
BALL_STRING_DEFINE_ASSIGNMENT_METHOD(unsigned int)
BALL_STRING_DEFINE_ASSIGNMENT_METHOD(long)
BALL_STRING_DEFINE_ASSIGNMENT_METHOD(unsigned long)
#ifdef BALL_ALLOW_LONG64_TYPE_OVERLOADS
BALL_STRING_DEFINE_ASSIGNMENT_METHOD(LongIndex)
BALL_STRING_DEFINE_ASSIGNMENT_METHOD(LongSize)
#endif
BALL_STRING_DEFINE_ASSIGNMENT_METHOD(float)
BALL_STRING_DEFINE_ASSIGNMENT_METHOD(double)
#undef BALL_STRING_DEFINE_ASSIGNMENT_METHOD

BALL_INLINE 
void String::setCompareMode(CompareMode mode)
{
  compare_mode_ = mode;
}

BALL_INLINE 
String::CompareMode String::getCompareMode()
{
  return compare_mode_;
}

BALL_INLINE 
char String::toChar() const
{
  return *c_str();
}

BALL_INLINE 
unsigned char String::toUnsignedChar() const
{
  return (unsigned char)*c_str();
}

BALL_INLINE 
Substring String::getSubstring(Index from, Size len) const
{
	validateRange_(from, len);
  return Substring(*this, from, len);
}

BALL_INLINE 
Substring String::operator () (Index from, Size len) const
{
  return getSubstring(from, len);
}

BALL_INLINE 
String& String::trim(const char* trimmed)
{
  return trimRight(trimmed).trimLeft(trimmed);
}

BALL_INLINE 
String String::trim(const char* trimmed) const
{
	String tmp(*this);
	tmp.trimRight(trimmed);
	tmp.trimLeft(trimmed);
  return tmp;
}

BALL_INLINE 
String& String::truncate(Size max_size)
{
  if (max_size < (Size) size())
	{
    resize(max_size);
	}

	return *this;
}

BALL_INLINE 
Substring String::left(Size len) const
{
	if (len > (Size)size())
	{
		len = (Size)size();
	}

  return Substring(*this, 0, len);
}

BALL_INLINE 
Substring String::instr(const String& patterns, Index from) const
{
  string::size_type found = find(patterns, from); 

  return (found == string::npos)
         ? Substring(*this, 0, 0)
         : Substring(*this, (Index)found, (Size)patterns.size());
}

BALL_INLINE 
String operator + (const String& s1, const string& s2)
{
  String result(s1);
  result.append(s2);
  return result;
}

BALL_INLINE 
String operator + (const string& s1, const String& s2)
{
  String result(s1);
  result.append(s2);
  return result;
}

BALL_INLINE
String operator + (const String& s1, const String& s2)
{
  String result(s1);
  result.append(s2);
  return result;
}

BALL_INLINE 
String operator +(const String& s1, const char* char_ptr) 
{
  String result(s1);
  result.append(char_ptr);
  return result;
}

BALL_INLINE 
String operator + (const String& s1, char c)
{
  String result(s1);
  result.append(1, c);
  return result;
}

///	Concatenates two strings
BALL_INLINE
String operator + (String&& s1, const string& s2)
{
	return std::move(s1.append(s2));
}

BALL_INLINE
String operator + (String&& s1, const String& s2)
{
	return std::move(s1.append(s2));
}

BALL_INLINE
String operator + (String&& s1, String&& s2)
{
	return std::move(s1.append(s2));
}

BALL_INLINE
String operator + (const String& s1, string&& s2)
{
	return std::move(s2.insert(0, s1));
}

BALL_INLINE
String operator + (const String& s1, String&& s2)
{
	return std::move(s2.insert(0, s1));
}

BALL_INLINE
String operator + (string&& s1, const String& s2)
{
	return std::move(s1.append(s2));
}

BALL_INLINE
String operator + (const string& s1, String&& s2)
{
	return std::move(s2.insert(0, s1));
}

/// Concatenates a string and a C type string
BALL_INLINE
String operator + (String&& s1, const char* char_ptr)
{
	return std::move(s1.append(char_ptr));
}

/// Concatenates a C type string and a string
BALL_INLINE
String operator + (const char* char_ptr, String&& s)
{
	return std::move(s.insert(0, char_ptr));
}

/// Concatenates a string and a character
BALL_INLINE
String operator + (String&& s, char c)
{
	s.push_back(c);
	return std::move(s);
}

/// Concatenates a character and a string
BALL_INLINE
String operator + (char c, String&& s)
{
	s.insert(s.begin(), c);
	return std::move(s);
}

BALL_INLINE
void String::destroy()
{
  assign("");
}

BALL_INLINE 
bool String::has(char c) const
{
  return ((c != (char)0) && (find(c, 0) != string::npos));
}

BALL_INLINE 
bool String::hasSubstring(const String& s, Index from) const
{
	if (s.size() == 0)
	{
		return true;
	}

  return (find(s, from) != string::npos);
}

BALL_INLINE 
bool String::isEmpty() const
{
  return (size() == 0);
}

BALL_INLINE 
bool String::isAlpha(char c)
{
	return ((c != 0) && ((char*)strchr(CHARACTER_CLASS__ASCII_ALPHA, c) != 0));
}

BALL_INLINE 
bool String::isAlnum(char c)
{
	return ((c != 0) && ((char*)strchr(CHARACTER_CLASS__ASCII_ALPHANUMERIC, c) != 0));
}

BALL_INLINE 
bool String::isDigit(char c)
{
  return ((c != 0) && ((char*)strchr(CHARACTER_CLASS__ASCII_NUMERIC, c) != 0));
}

BALL_INLINE 
bool String::isFloat() const 
{
	char* test;
	char* str = const_cast<char*>(c_str());
  errno = 0;

//Get rid of those friggin warnings
#if defined BALL_COMPILER_GXX && ((BALL_COMPILER_VERSION_MAJOR == 4 && BALL_COMPILER_VERSION_MINOR < 6) || BALL_COMPILER_VERSION_MAJOR < 4)
	double d = 0;
	d = strtod(str, &test);
#else
	strtod(str, &test);
#endif
	return (errno == 0 && *test == '\0');
}

BALL_INLINE 
bool String::isSpace(char c)
{
  return (c == ' ');
}

BALL_INLINE 
bool String::isWhitespace(char c)
{
  return ((c != 0) && ((char*)strchr(CHARACTER_CLASS__WHITESPACE, c) != 0));
}

BALL_INLINE 
bool String::operator < (const char* char_ptr) const
{
  return (compare(char_ptr) < 0);
}

BALL_INLINE
bool String::operator <= (const char* char_ptr) const
{
  return (compare(char_ptr) <= 0);
}

BALL_INLINE 
bool String::operator >= (const char* char_ptr) const
{
  return (compare(char_ptr) >= 0);
}

BALL_INLINE 
bool String::operator > (const char* char_ptr) const
{
  return (compare(char_ptr) > 0);
}

BALL_INLINE 
bool String::operator == (char c) const
{
  return (compare(c) == 0);
}

BALL_INLINE 
bool String::operator != (char c) const
{
  return (compare(c) != 0);
}

BALL_INLINE 
bool String::operator < (char c) const
{
  return (compare(c) < 0);
}

BALL_INLINE 
bool String::operator <= (char c) const
{
  return (compare(c) <= 0);
}

BALL_INLINE 
bool String::operator >= (char c) const
{
  return (compare(c) >= 0);
}

BALL_INLINE 
bool String::operator > (char c) const
{
  return (compare(c) > 0);
}

BALL_INLINE 
bool String::isValid() const
{
  return (c_str() != 0 && size() <= capacity()); 
}

BALL_INLINE 
std::istream& String::getline(std::istream& s,  char delimiter)
{
	clear();
	std::getline(s, *this, delimiter);
	
	return s;
}

BALL_INLINE 
bool operator != (const String& s, const Substring& substring)
{
	return (substring != s);
}

BALL_INLINE 
bool operator == (const String& s, const Substring& substring)
{
	return (substring == s);
}

BALL_INLINE 
void String::swap(String& s)
{
	str_.swap(s);
}

BALL_INLINE
bool operator == (const String& s1, const String& s2)
{
	return (s1.compare(s2) == 0);
}

BALL_INLINE 
bool operator != (const String& s1, const String& s2)
{
  return (s1.compare(s2) != 0);
}

BALL_INLINE 
bool operator < (const String& s1, const String& s2)
{
  return (s1.compare(s2) < 0);
}

BALL_INLINE 
bool operator <= (const String& s1, const String& s2)
{
  return (s1.compare(s2) <= 0);
}

BALL_INLINE 
bool operator >= (const String& s1, const String& s2)
{
  return (s1.compare(s2) >= 0);
}

BALL_INLINE 
bool operator > (const String& s1, const String& s2)
{
  return (s1.compare(s2) > 0);
}

BALL_INLINE 
bool operator == (const char* char_ptr, const String &s)
{
	return (s.compare(char_ptr) == 0);
}

BALL_INLINE 
bool operator != (const char* char_ptr, const String &s)
{
	return (s.compare(char_ptr) != 0);
}

BALL_INLINE 
bool operator < (const char* char_ptr, const String& s)
{
	return (s.compare(char_ptr) > 0);
}

BALL_INLINE 
bool operator <= (const char* char_ptr, const String &s)
{
	return (s.compare(char_ptr) >= 0);
}

BALL_INLINE 
bool operator >= (const char* char_ptr, const String& s)
{
	return (s.compare(char_ptr) <= 0);
}

BALL_INLINE 
bool operator > (const char* char_ptr, const String& s)
{
	return (s.compare(char_ptr) < 0);
}

BALL_INLINE 
bool operator == (char c, const String& s)
{
	return (s.compare(c) == 0);
}

BALL_INLINE 
bool operator != (char c, const String &s)
{
	return (s.compare(c) != 0);
}

BALL_INLINE 
bool operator < (char c, const String& s)
{
	return (s.compare(c) > 0);
}

BALL_INLINE 
bool operator <= (char c, const String &s)
{
	return (s.compare(c) >= 0);
}

BALL_INLINE 
bool operator >= (char c, const String &s)
{
	return (s.compare(c) <= 0);
}

BALL_INLINE 
bool operator > (char c, const String &s)
{
	return (s.compare(c) < 0);
}

// ---------------------------------------------
// std::string compatibility
// ---------------------------------------------

BALL_INLINE
String::iterator String::begin() BALL_NOEXCEPT
{
	return str_.begin();
}

BALL_INLINE
String::const_iterator String::begin() const BALL_NOEXCEPT
{
	return str_.begin();
}

BALL_INLINE
String::iterator String::end() BALL_NOEXCEPT
{
	return str_.end();
}

BALL_INLINE
String::const_iterator String::end() const BALL_NOEXCEPT
{
	return str_.end();
}

BALL_INLINE
String::reverse_iterator String::rbegin() BALL_NOEXCEPT
{
	return str_.rbegin();
}

BALL_INLINE
String::const_reverse_iterator String::rbegin() const BALL_NOEXCEPT
{
	return str_.rbegin();
}

BALL_INLINE
String::reverse_iterator String::rend() BALL_NOEXCEPT
{
	return str_.rend();
}

BALL_INLINE
String::const_reverse_iterator String::rend() const BALL_NOEXCEPT
{
	return str_.rend();
}

BALL_INLINE
String::const_iterator String::cbegin() const BALL_NOEXCEPT
{
	return str_.cbegin();
}

BALL_INLINE
String::const_iterator String::cend() const BALL_NOEXCEPT
{
	return str_.cend();
}

BALL_INLINE
String::const_reverse_iterator String::crbegin() const BALL_NOEXCEPT
{
	return str_.crbegin();
}

BALL_INLINE
String::const_reverse_iterator String::crend() const BALL_NOEXCEPT
{
	return str_.crend();
}

BALL_INLINE
size_t String::size() const BALL_NOEXCEPT
{
	return str_.size();
}

BALL_INLINE
size_t String::length() const BALL_NOEXCEPT
{
	return str_.length();
}

BALL_INLINE
size_t String::max_size() const BALL_NOEXCEPT
{
	return str_.max_size();
}

BALL_INLINE
void String::resize(size_t n)
{
	str_.resize(n);
}

BALL_INLINE
void String::resize(size_t n, char c)
{
	str_.resize(n, c);
}

BALL_INLINE
size_t String::capacity() const BALL_NOEXCEPT
{
	return str_.capacity();
}

BALL_INLINE
void String::reserve(size_t n)
{
	str_.reserve(n);
}

BALL_INLINE
void String::clear() BALL_NOEXCEPT
{
	str_.clear();
}

BALL_INLINE
bool String::empty() const BALL_NOEXCEPT
{
	return str_.empty();
}

BALL_INLINE
void String::shrink_to_fit()
{
	return str_.shrink_to_fit();
}

BALL_INLINE
char& String::operator[] (size_t pos)
{
	return str_[pos];
}

BALL_INLINE
const char& String::operator[] (size_t pos) const
{
	return str_[pos];
}

BALL_INLINE
char& String::at(size_t pos)
{
	return str_.at(pos);
}

BALL_INLINE
const char& String::at(size_t pos) const
{
	return str_.at(pos);
}

BALL_INLINE
char& String::front()
{
	return str_.front();
}

BALL_INLINE
const char& String::front() const
{
	return str_.front();
}

BALL_INLINE
char& String::back()
{
	return str_.back();
}

BALL_INLINE
const char& String::back() const
{
	return str_.back();
}

BALL_INLINE
String& String::operator += (const String& str)
{
	str_ += (string const&)str;
	return *this;
}

BALL_INLINE
String& String::operator += (const string& str)
{
	str_ += str;
	return *this;
}

BALL_INLINE
String& String::operator += (const char* s)
{
	str_ += s;
	return *this;
}

BALL_INLINE
String& String::operator += (char c)
{
	str_ += c;
	return *this;
}

BALL_INLINE
String& String::operator += (std::initializer_list<char> il)
{
	str_ += il;
	return *this;
}

BALL_INLINE
String& String::append(const String& str)
{
	str_.append((string const&)str);
	return *this;
}

BALL_INLINE
String& String::append(const string& str)
{
	str_.append(str);
	return *this;
}

BALL_INLINE
String& String::append(const string& str, size_t subpos, size_t sublen)
{
	str_.append(str, subpos, sublen);
	return *this;
}

BALL_INLINE
String& String::append(const char* s)
{
	str_.append(s);
	return *this;
}

BALL_INLINE
String& String::append(const char* s, size_t n)
{
	str_.append(s, n);
	return *this;
}

BALL_INLINE
String& String::append(size_t n, char c)
{
	str_.append(n, c);
	return *this;
}

template <class InputIterator>
BALL_INLINE
String& String::append(InputIterator first, InputIterator last)
{
	str_.append(first, last);
	return *this;
}

BALL_INLINE
String& String::append(std::initializer_list<char> li)
{
	str_.append(li);
	return *this;
}

BALL_INLINE
void String::push_back(char c)
{
	str_.push_back(c);
}

BALL_INLINE
String& String::assign(const String& str)
{
	str_.assign((string const&)str);
	return *this;
}

BALL_INLINE
String& String::assign(const string& str)
{
	str_.assign(str);
	return *this;
}

BALL_INLINE
String& String::assign(const string& str, size_t subpos, size_t sublen)
{
	str_.assign(str, subpos, sublen);
	return *this;
}

BALL_INLINE
String& String::assign(const char* s)
{
	str_.assign(s);
	return *this;
}

BALL_INLINE
String& String::assign(const char* s, size_t n)
{
	str_.assign(s, n);
	return *this;
}

BALL_INLINE
String& String::assign(size_t n, char c)
{
	str_.assign(n, c);
	return *this;
}

template <class InputIterator>
BALL_INLINE
String& String::assign(InputIterator first, InputIterator last)
{
	str_.assign(first, last);
	return *this;
}

BALL_INLINE
String& String::assign(std::initializer_list<char> li)
{
	str_.assign(li);
	return *this;
}

BALL_INLINE
String& String::assign(string&& str) BALL_NOEXCEPT
{
	str_.assign(str);
	return *this;
}

BALL_INLINE
String& String::insert(size_t pos, const string& str)
{
	str_.insert(pos, str);
	return *this;
}

BALL_INLINE
String& String::insert(size_t pos, const string& str, size_t subpos, size_t sublen)
{
	str_.insert(pos, str, subpos, sublen);
	return *this;
}

BALL_INLINE
String& String::insert(size_t pos, const char* s)
{
	str_.insert(pos, s);
	return *this;
}

BALL_INLINE
String& String::insert(size_t pos, const char* s, size_t n)
{
	str_.insert(pos, s, n);
	return *this;
}

BALL_INLINE
String& String::insert(size_t pos, size_t n, char c)
{
	str_.insert(pos, n, c);
	return *this;
}

#ifdef BALL_HAS_STD_STRING_CONST_ITERATOR_FUNCTIONS
BALL_INLINE
String::iterator String::insert(const_iterator p, size_t n, char c)
{
	return str_.insert(p, n, c);
}

BALL_INLINE
String::iterator String::insert(const_iterator p, char c)
{
	return str_.insert(p, c);
}
#else
BALL_INLINE
void String::insert(iterator p, size_t n, char c)
{
	str_.insert(p, n, c);
}

BALL_INLINE
String::iterator String::insert(iterator p, char c)
{
	return str_.insert(p, c);
}
#endif

template <class InputIterator>
BALL_INLINE
String::iterator String::insert(iterator p, InputIterator first, InputIterator last)
{
	return str_.insert(p, first, last);
}

#ifdef BALL_HAS_STD_STRING_CONST_ITERATOR_INITLIST_INSERT
BALL_INLINE
String& String::insert(const_iterator p, std::initializer_list<char> li)
{
	str_.insert(p, li);
	return *this;
}
#endif

BALL_INLINE
String& String::erase(size_t pos, size_t len)
{
	str_.erase(pos, len);
	return *this;
}

#ifdef BALL_HAS_STD_STRING_CONST_ITERATOR_FUNCTIONS
BALL_INLINE
String::iterator String::erase(const_iterator p)
{
	return str_.erase(p);
}

BALL_INLINE
String::iterator String::erase(const_iterator first, const_iterator last)
{
	return str_.erase(first, last);
}
#else
BALL_INLINE
String::iterator String::erase(iterator p)
{
	return str_.erase(p);
}

BALL_INLINE
String::iterator String::erase(iterator first, iterator last)
{
	return str_.erase(first, last);
}
#endif

BALL_INLINE
String& String::replace(size_t pos, size_t len, const string& str)
{
	str_.replace(pos, len, str);
	return *this;
}

BALL_INLINE
String& String::replace(size_t pos, size_t len, const string& str, size_t subpos, size_t sublen)
{
	str_.replace(pos, len, str, subpos, sublen);
	return *this;
}

BALL_INLINE
String& String::replace(size_t pos, size_t len, const char* s)
{
	str_.replace(pos, len, s);
	return *this;
}

BALL_INLINE
String& String::replace(size_t pos, size_t len, const char* s, size_t n)
{
	str_.replace(pos, len, s, n);
	return *this;
}

BALL_INLINE
String& String::replace(size_t pos, size_t len, size_t n, char c)
{
	str_.replace(pos, len, n, c);
	return *this;
}

#ifdef BALL_HAS_STD_STRING_CONST_ITERATOR_FUNCTIONS
BALL_INLINE
String& String::replace(const_iterator i1, const_iterator i2, const string& str)
{
	str_.replace(i1, i2, str);
	return *this;
}

BALL_INLINE
String& String::replace(const_iterator i1, const_iterator i2, const char* s)
{
	str_.replace(i1, i2, s);
	return *this;
}

BALL_INLINE
String& String::replace(const_iterator i1, const_iterator i2, const char* s, size_t n)
{
	str_.replace(i1, i2, s, n);
	return *this;
}

BALL_INLINE
String& String::replace(const_iterator i1, const_iterator i2, size_t n, char c)
{
	str_.replace(i1, i2, n, c);
	return *this;
}

template <class InputIterator>
BALL_INLINE
String& String::replace(const_iterator i1, const_iterator i2, InputIterator first, InputIterator last)
{
	str_.replace(i1, i2, first, last);
	return *this;
}
#else
BALL_INLINE
String& String::replace(iterator i1, iterator i2, const string& str)
{
	str_.replace(i1, i2, str);
	return *this;
}

BALL_INLINE
String& String::replace(iterator i1, iterator i2, const char* s)
{
	str_.replace(i1, i2, s);
	return *this;
}

BALL_INLINE
String& String::replace(iterator i1, iterator i2, const char* s, size_t n)
{
	str_.replace(i1, i2, s, n);
	return *this;
}

BALL_INLINE
String& String::replace(iterator i1, iterator i2, size_t n, char c)
{
	str_.replace(i1, i2, n, c);
	return *this;
}

template <class InputIterator>
BALL_INLINE
String& String::replace(iterator i1, iterator i2, InputIterator first, InputIterator last)
{
	str_.replace(i1, i2, first, last);
	return *this;
}
#endif

#ifdef BALL_HAS_STD_STRING_CONST_ITERATOR_FUNCTIONS
BALL_INLINE
String& String::replace(const_iterator i1, const_iterator i2, std::initializer_list<char> li)
{
	str_.replace(i1, i2, li);
	return *this;
}
#endif

BALL_INLINE
void String::swap(string& str)
{
	str_.swap(str);
}

BALL_INLINE
void String::pop_back()
{
	str_.pop_back();
}

BALL_INLINE
const char* String::c_str() const BALL_NOEXCEPT
{
	return str_.c_str();
}

BALL_INLINE
const char* String::data() const BALL_NOEXCEPT
{
	return str_.data();
}

BALL_INLINE
String::allocator_type String::get_allocator() const BALL_NOEXCEPT
{
	return str_.get_allocator();
}

BALL_INLINE
size_t String::copy(char* s, size_t len, size_t pos) const 
{
	return str_.copy(s, len, pos);
}

BALL_INLINE
size_t String::find(const string& str, size_t pos) const BALL_NOEXCEPT
{
	return str_.find(str, pos);
}

BALL_INLINE
size_t String::find(const char* s, size_t pos) const
{
	return str_.find(s, pos);
}

BALL_INLINE
size_t String::find(const char* s, size_t pos, size_t n) const
{
	return str_.find(s, pos, n);
}

BALL_INLINE
size_t String::find(char c, size_t pos) const BALL_NOEXCEPT
{
	return str_.find(c, pos);
}

BALL_INLINE
size_t String::rfind(const string& str, size_t pos) const BALL_NOEXCEPT
{
	return str_.rfind(str, pos);
}

BALL_INLINE
size_t String::rfind(const char* s, size_t pos) const
{
	return str_.rfind(s, pos);
}

BALL_INLINE
size_t String::rfind(const char* s, size_t pos, size_t n) const
{
	return str_.rfind(s, pos, n);
}

BALL_INLINE
size_t String::rfind(char c, size_t pos) const BALL_NOEXCEPT
{
	return str_.rfind(c, pos);
}

BALL_INLINE
size_t String::find_first_of(const string& str, size_t pos) const BALL_NOEXCEPT
{
	return str_.find_first_of(str, pos);
}

BALL_INLINE
size_t String::find_first_of(const char* s, size_t pos) const
{
	return str_.find_first_of(s, pos);
}

BALL_INLINE
size_t String::find_first_of(const char* s, size_t pos, size_t n) const
{
	return str_.find_first_of(s, pos, n);
}

BALL_INLINE
size_t String::find_first_of(char c, size_t pos) const BALL_NOEXCEPT
{
	return str_.find_first_of(c, pos);
}

BALL_INLINE
size_t String::find_last_of(const string& str, size_t pos) const BALL_NOEXCEPT
{
	return str_.find_last_of(str, pos);
}

BALL_INLINE
size_t String::find_last_of(const char* s, size_t pos) const
{
	return str_.find_last_of(s, pos);
}

BALL_INLINE
size_t String::find_last_of(const char* s, size_t pos, size_t n) const
{
	return str_.find_last_of(s, pos, n);
}

BALL_INLINE
size_t String::find_last_of(char c, size_t pos) const BALL_NOEXCEPT
{
	return str_.find_last_of(c, pos);
}

BALL_INLINE
size_t String::find_first_not_of(const string& str, size_t pos) const BALL_NOEXCEPT
{
	return str_.find_first_not_of(str, pos);
}

BALL_INLINE
size_t String::find_first_not_of(const char* s, size_t pos) const
{
	return str_.find_first_not_of(s, pos);
}

BALL_INLINE
size_t String::find_first_not_of(const char* s, size_t pos, size_t n) const
{
	return str_.find_first_not_of(s, pos, n);
}

BALL_INLINE
size_t String::find_first_not_of(char c, size_t pos) const BALL_NOEXCEPT
{
	return str_.find_first_not_of(c, pos);
}

BALL_INLINE
size_t String::find_last_not_of(const string& str, size_t pos) const BALL_NOEXCEPT
{
	return str_.find_last_not_of(str, pos);
}

BALL_INLINE
size_t String::find_last_not_of(const char* s, size_t pos) const
{
	return str_.find_last_not_of(s, pos);
}

BALL_INLINE
size_t String::find_last_not_of(const char* s, size_t pos, size_t n) const
{
	return str_.find_last_not_of(s, pos, n);
}

BALL_INLINE
size_t String::find_last_not_of(char c, size_t pos) const BALL_NOEXCEPT
{
	return str_.find_last_not_of(c, pos);
}

BALL_INLINE
string String::substr(size_t pos, size_t len) const
{
	return str_.substr(pos, len);
}

BALL_INLINE
int String::compare(const string& str) const BALL_NOEXCEPT
{
	return str_.compare(str);
}

BALL_INLINE
int String::compare(size_t pos, size_t len, const string& str) const
{
	return str_.compare(pos, len, str);
}

BALL_INLINE
int String::compare(size_t pos, size_t len, const string& str, size_t subpos, size_t sublen) const
{
	return str_.compare(pos, len, str, subpos, sublen);
}

/*
BALL_INLINE
int String::compare(const char* s) const
{
	return str_.compare(s);
}
*/

BALL_INLINE
int String::compare(size_t pos, size_t len, const char* s) const
{
	return str_.compare(pos, len, s);
}

BALL_INLINE
int String::compare(size_t pos, size_t len, const char* s, size_t n) const
{
	return str_.compare(pos, len, s, n);
}

} // namespace BALL

namespace std
{

BALL_INLINE
istream& operator>> (istream& is, BALL::String& str)
{
	return (is >> (string&)str);
}

BALL_INLINE
ostream& operator<< (ostream& os, BALL::String const& str)
{
	return (os << (string const&)str);
}

BALL_INLINE
istream& getline(istream& is, BALL::String& str, char delim)
{
	return getline(is, (string&)str, delim);
}

BALL_INLINE
istream& getline(istream& is, BALL::String& str)
{
	return getline(is, (string&)str);
}

BALL_INLINE
istream& getline(istream& is, BALL::String&& str, char delim)
{
	return getline(is, move((string&)str), delim);
}

BALL_INLINE
istream& getline(istream& is, BALL::String&& str)
{
	return getline(is, move((string&)str));
}

} // namespace std
