1// Short-string-optimized versatile string base -*- C++ -*-
2
3// Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library.  This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file ext/sso_string_base.h
26 *  This file is a GNU extension to the Standard C++ Library.
27 *  This is an internal header file, included by other library headers.
28 *  You should not attempt to use it directly.
29 */
30
31#ifndef _SSO_STRING_BASE_H
32#define _SSO_STRING_BASE_H 1
33
34_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
35
36  template<typename _CharT, typename _Traits, typename _Alloc>
37    class __sso_string_base
38    : protected __vstring_utility<_CharT, _Traits, _Alloc>
39    {
40    public:
41      typedef _Traits					    traits_type;
42      typedef typename _Traits::char_type		    value_type;
43
44      typedef __vstring_utility<_CharT, _Traits, _Alloc>    _Util_Base;
45      typedef typename _Util_Base::_CharT_alloc_type        _CharT_alloc_type;
46      typedef typename _CharT_alloc_type::size_type	    size_type;
47
48    private:
49      // Data Members:
50      typename _Util_Base::template _Alloc_hider<_CharT_alloc_type>
51                                                            _M_dataplus;
52      size_type                                             _M_string_length;
53
54      enum { _S_local_capacity = 15 };
55
56      union
57      {
58	_CharT           _M_local_data[_S_local_capacity + 1];
59	size_type        _M_allocated_capacity;
60      };
61
62      void
63      _M_data(_CharT* __p)
64      { _M_dataplus._M_p = __p; }
65
66      void
67      _M_length(size_type __length)
68      { _M_string_length = __length; }
69
70      void
71      _M_capacity(size_type __capacity)
72      { _M_allocated_capacity = __capacity; }
73
74      bool
75      _M_is_local() const
76      { return _M_data() == _M_local_data; }
77
78      // Create & Destroy
79      _CharT*
80      _M_create(size_type&, size_type);
81
82      void
83      _M_dispose()
84      {
85	if (!_M_is_local())
86	  _M_destroy(_M_allocated_capacity);
87#if __google_stl_debug_string_dangling
88	else {
89          // Wipe local storage for destructed string with 0xCD.
90          // This mimics what DebugAllocation does to free()d memory.
91          __builtin_memset(_M_local_data, 0xcd, sizeof(_M_local_data));
92        }
93#endif
94      }
95
96      void
97      _M_destroy(size_type __size) throw()
98      { _M_get_allocator().deallocate(_M_data(), __size + 1); }
99
100      // _M_construct_aux is used to implement the 21.3.1 para 15 which
101      // requires special behaviour if _InIterator is an integral type
102      template<typename _InIterator>
103        void
104        _M_construct_aux(_InIterator __beg, _InIterator __end,
105			 std::__false_type)
106	{
107          typedef typename iterator_traits<_InIterator>::iterator_category _Tag;
108          _M_construct(__beg, __end, _Tag());
109	}
110
111      // _GLIBCXX_RESOLVE_LIB_DEFECTS
112      // 438. Ambiguity in the "do the right thing" clause
113      template<typename _Integer>
114        void
115        _M_construct_aux(_Integer __beg, _Integer __end, std::__true_type)
116	{ _M_construct(static_cast<size_type>(__beg), __end); }
117
118      template<typename _InIterator>
119        void
120        _M_construct(_InIterator __beg, _InIterator __end)
121	{
122	  typedef typename std::__is_integer<_InIterator>::__type _Integral;
123	  _M_construct_aux(__beg, __end, _Integral());
124        }
125
126      // For Input Iterators, used in istreambuf_iterators, etc.
127      template<typename _InIterator>
128        void
129        _M_construct(_InIterator __beg, _InIterator __end,
130		     std::input_iterator_tag);
131
132      // For forward_iterators up to random_access_iterators, used for
133      // string::iterator, _CharT*, etc.
134      template<typename _FwdIterator>
135        void
136        _M_construct(_FwdIterator __beg, _FwdIterator __end,
137		     std::forward_iterator_tag);
138
139      void
140      _M_construct(size_type __req, _CharT __c);
141
142    public:
143      size_type
144      _M_max_size() const
145      { return (_M_get_allocator().max_size() - 1) / 2; }
146
147      _CharT*
148      _M_data() const
149      { return _M_dataplus._M_p; }
150
151      size_type
152      _M_length() const
153      { return _M_string_length; }
154
155      size_type
156      _M_capacity() const
157      {
158	return _M_is_local() ? size_type(_S_local_capacity)
159	                     : _M_allocated_capacity;
160      }
161
162      bool
163      _M_is_shared() const
164      { return false; }
165
166      void
167      _M_set_leaked() { }
168
169      void
170      _M_leak() { }
171
172      void
173      _M_set_length_no_wipe(size_type __n)
174      {
175	_M_length(__n);
176	traits_type::assign(_M_data()[__n], _CharT());
177      }
178
179      void
180      _M_set_length(size_type __n)
181      {
182#if __google_stl_debug_string_dangling
183	if (__n + 1 < _M_length())
184	  {
185	    // Wipe the storage with 0xCD.
186	    // Also wipes the old NUL terminator.
187	    __builtin_memset(_M_data() + __n + 1, 0xcd, _M_length() - __n);
188	  }
189#endif
190	  _M_set_length_no_wipe(__n);
191      }
192
193      __sso_string_base()
194      : _M_dataplus(_M_local_data)
195      { _M_set_length_no_wipe(0); }
196
197      __sso_string_base(const _Alloc& __a);
198
199      __sso_string_base(const __sso_string_base& __rcs);
200
201#ifdef __GXX_EXPERIMENTAL_CXX0X__
202      __sso_string_base(__sso_string_base&& __rcs);
203#endif
204
205      __sso_string_base(size_type __n, _CharT __c, const _Alloc& __a);
206
207      template<typename _InputIterator>
208        __sso_string_base(_InputIterator __beg, _InputIterator __end,
209			  const _Alloc& __a);
210
211      ~__sso_string_base()
212      { _M_dispose(); }
213
214      _CharT_alloc_type&
215      _M_get_allocator()
216      { return _M_dataplus; }
217
218      const _CharT_alloc_type&
219      _M_get_allocator() const
220      { return _M_dataplus; }
221
222      void
223      _M_swap(__sso_string_base& __rcs);
224
225      void
226      _M_assign(const __sso_string_base& __rcs);
227
228      void
229      _M_reserve(size_type __res);
230
231      void
232      _M_mutate(size_type __pos, size_type __len1, const _CharT* __s,
233		size_type __len2);
234
235      void
236      _M_erase(size_type __pos, size_type __n);
237
238      void
239      _M_clear()
240      { _M_set_length(0); }
241
242      bool
243      _M_compare(const __sso_string_base&) const
244      { return false; }
245    };
246
247  template<typename _CharT, typename _Traits, typename _Alloc>
248    void
249    __sso_string_base<_CharT, _Traits, _Alloc>::
250    _M_swap(__sso_string_base& __rcs)
251    {
252      if (this == &__rcs)
253	return;
254
255      // _GLIBCXX_RESOLVE_LIB_DEFECTS
256      // 431. Swapping containers with unequal allocators.
257      std::__alloc_swap<_CharT_alloc_type>::_S_do_it(_M_get_allocator(),
258						     __rcs._M_get_allocator());
259
260      if (_M_is_local())
261	if (__rcs._M_is_local())
262	  {
263	    if (_M_length() && __rcs._M_length())
264	      {
265		_CharT __tmp_data[_S_local_capacity + 1];
266		traits_type::copy(__tmp_data, __rcs._M_local_data,
267				  _S_local_capacity + 1);
268		traits_type::copy(__rcs._M_local_data, _M_local_data,
269				  _S_local_capacity + 1);
270		traits_type::copy(_M_local_data, __tmp_data,
271				  _S_local_capacity + 1);
272	      }
273	    else if (__rcs._M_length())
274	      {
275		traits_type::copy(_M_local_data, __rcs._M_local_data,
276				  _S_local_capacity + 1);
277		_M_length(__rcs._M_length());
278		__rcs._M_set_length(0);
279		return;
280	      }
281	    else if (_M_length())
282	      {
283		traits_type::copy(__rcs._M_local_data, _M_local_data,
284				  _S_local_capacity + 1);
285		__rcs._M_length(_M_length());
286		_M_set_length(0);
287		return;
288	      }
289	  }
290	else
291	  {
292	    const size_type __tmp_capacity = __rcs._M_allocated_capacity;
293	    traits_type::copy(__rcs._M_local_data, _M_local_data,
294			      _S_local_capacity + 1);
295	    _M_data(__rcs._M_data());
296	    __rcs._M_data(__rcs._M_local_data);
297	    _M_capacity(__tmp_capacity);
298	  }
299      else
300	{
301	  const size_type __tmp_capacity = _M_allocated_capacity;
302	  if (__rcs._M_is_local())
303	    {
304	      traits_type::copy(_M_local_data, __rcs._M_local_data,
305				_S_local_capacity + 1);
306	      __rcs._M_data(_M_data());
307	      _M_data(_M_local_data);
308	    }
309	  else
310	    {
311	      _CharT* __tmp_ptr = _M_data();
312	      _M_data(__rcs._M_data());
313	      __rcs._M_data(__tmp_ptr);
314	      _M_capacity(__rcs._M_allocated_capacity);
315	    }
316	  __rcs._M_capacity(__tmp_capacity);
317	}
318
319      const size_type __tmp_length = _M_length();
320      _M_length(__rcs._M_length());
321      __rcs._M_length(__tmp_length);
322    }
323
324  template<typename _CharT, typename _Traits, typename _Alloc>
325    _CharT*
326    __sso_string_base<_CharT, _Traits, _Alloc>::
327    _M_create(size_type& __capacity, size_type __old_capacity)
328    {
329      // _GLIBCXX_RESOLVE_LIB_DEFECTS
330      // 83.  String::npos vs. string::max_size()
331      if (__capacity > _M_max_size())
332	std::__throw_length_error(__N("__sso_string_base::_M_create"));
333
334      // The below implements an exponential growth policy, necessary to
335      // meet amortized linear time requirements of the library: see
336      // http://gcc.gnu.org/ml/libstdc++/2001-07/msg00085.html.
337      if (__capacity > __old_capacity && __capacity < 2 * __old_capacity)
338	{
339	  __capacity = 2 * __old_capacity;
340	  // Never allocate a string bigger than max_size.
341	  if (__capacity > _M_max_size())
342	    __capacity = _M_max_size();
343	}
344
345      // NB: Need an array of char_type[__capacity], plus a terminating
346      // null char_type() element.
347      return _M_get_allocator().allocate(__capacity + 1);
348    }
349
350  template<typename _CharT, typename _Traits, typename _Alloc>
351    __sso_string_base<_CharT, _Traits, _Alloc>::
352    __sso_string_base(const _Alloc& __a)
353    : _M_dataplus(__a, _M_local_data)
354    { _M_set_length_no_wipe(0); }
355
356  template<typename _CharT, typename _Traits, typename _Alloc>
357    __sso_string_base<_CharT, _Traits, _Alloc>::
358    __sso_string_base(const __sso_string_base& __rcs)
359    : _M_dataplus(__rcs._M_get_allocator(), _M_local_data)
360    { _M_construct(__rcs._M_data(), __rcs._M_data() + __rcs._M_length()); }
361
362#ifdef __GXX_EXPERIMENTAL_CXX0X__
363  template<typename _CharT, typename _Traits, typename _Alloc>
364    __sso_string_base<_CharT, _Traits, _Alloc>::
365    __sso_string_base(__sso_string_base&& __rcs)
366    : _M_dataplus(__rcs._M_get_allocator(), _M_local_data)
367    {
368      if (__rcs._M_is_local())
369	{
370	  if (__rcs._M_length())
371	    traits_type::copy(_M_local_data, __rcs._M_local_data,
372			      _S_local_capacity + 1);
373	}
374      else
375	{
376	  _M_data(__rcs._M_data());
377	  _M_capacity(__rcs._M_allocated_capacity);
378	}
379
380      _M_length(__rcs._M_length());
381      __rcs._M_length(0);
382      __rcs._M_data(__rcs._M_local_data);
383    }
384#endif
385
386  template<typename _CharT, typename _Traits, typename _Alloc>
387    __sso_string_base<_CharT, _Traits, _Alloc>::
388    __sso_string_base(size_type __n, _CharT __c, const _Alloc& __a)
389    : _M_dataplus(__a, _M_local_data)
390    { _M_construct(__n, __c); }
391
392  template<typename _CharT, typename _Traits, typename _Alloc>
393    template<typename _InputIterator>
394    __sso_string_base<_CharT, _Traits, _Alloc>::
395    __sso_string_base(_InputIterator __beg, _InputIterator __end,
396		      const _Alloc& __a)
397    : _M_dataplus(__a, _M_local_data)
398    { _M_construct(__beg, __end); }
399
400  // NB: This is the special case for Input Iterators, used in
401  // istreambuf_iterators, etc.
402  // Input Iterators have a cost structure very different from
403  // pointers, calling for a different coding style.
404  template<typename _CharT, typename _Traits, typename _Alloc>
405    template<typename _InIterator>
406      void
407      __sso_string_base<_CharT, _Traits, _Alloc>::
408      _M_construct(_InIterator __beg, _InIterator __end,
409		   std::input_iterator_tag)
410      {
411	size_type __len = 0;
412	size_type __capacity = size_type(_S_local_capacity);
413
414	while (__beg != __end && __len < __capacity)
415	  {
416	    _M_data()[__len++] = *__beg;
417	    ++__beg;
418	  }
419
420	__try
421	  {
422	    while (__beg != __end)
423	      {
424		if (__len == __capacity)
425		  {
426		    // Allocate more space.
427		    __capacity = __len + 1;
428		    _CharT* __another = _M_create(__capacity, __len);
429		    this->_S_copy(__another, _M_data(), __len);
430		    _M_dispose();
431		    _M_data(__another);
432		    _M_capacity(__capacity);
433		  }
434		_M_data()[__len++] = *__beg;
435		++__beg;
436	      }
437	  }
438	__catch(...)
439	  {
440	    _M_dispose();
441	    __throw_exception_again;
442	  }
443
444	_M_set_length_no_wipe(__len);
445      }
446
447  template<typename _CharT, typename _Traits, typename _Alloc>
448    template<typename _InIterator>
449      void
450      __sso_string_base<_CharT, _Traits, _Alloc>::
451      _M_construct(_InIterator __beg, _InIterator __end,
452		   std::forward_iterator_tag)
453      {
454	// NB: Not required, but considered best practice.
455	if (__builtin_expect(__is_null_pointer(__beg) && __beg != __end, 0))
456	  std::__throw_logic_error(__N("__sso_string_base::"
457				       "_M_construct NULL not valid"));
458
459	size_type __dnew = static_cast<size_type>(std::distance(__beg, __end));
460
461	if (__dnew > size_type(_S_local_capacity))
462	  {
463	    _M_data(_M_create(__dnew, size_type(0)));
464	    _M_capacity(__dnew);
465	  }
466
467	// Check for out_of_range and length_error exceptions.
468	__try
469	  { this->_S_copy_chars(_M_data(), __beg, __end); }
470	__catch(...)
471	  {
472	    _M_dispose();
473	    __throw_exception_again;
474	  }
475
476	_M_set_length_no_wipe(__dnew);
477      }
478
479  template<typename _CharT, typename _Traits, typename _Alloc>
480    void
481    __sso_string_base<_CharT, _Traits, _Alloc>::
482    _M_construct(size_type __n, _CharT __c)
483    {
484      if (__n > size_type(_S_local_capacity))
485	{
486	  _M_data(_M_create(__n, size_type(0)));
487	  _M_capacity(__n);
488	}
489
490      if (__n)
491	this->_S_assign(_M_data(), __n, __c);
492
493      _M_set_length_no_wipe(__n);
494    }
495
496  template<typename _CharT, typename _Traits, typename _Alloc>
497    void
498    __sso_string_base<_CharT, _Traits, _Alloc>::
499    _M_assign(const __sso_string_base& __rcs)
500    {
501      if (this != &__rcs)
502	{
503	  const size_type __rsize = __rcs._M_length();
504	  const size_type __capacity = _M_capacity();
505
506	  if (__rsize > __capacity)
507	    {
508	      size_type __new_capacity = __rsize;
509	      _CharT* __tmp = _M_create(__new_capacity, __capacity);
510	      _M_dispose();
511	      _M_data(__tmp);
512	      _M_capacity(__new_capacity);
513	    }
514
515	  if (__rsize)
516	    this->_S_copy(_M_data(), __rcs._M_data(), __rsize);
517
518	  _M_set_length(__rsize);
519	}
520    }
521
522  template<typename _CharT, typename _Traits, typename _Alloc>
523    void
524    __sso_string_base<_CharT, _Traits, _Alloc>::
525    _M_reserve(size_type __res)
526    {
527      // Make sure we don't shrink below the current size.
528      if (__res < _M_length())
529	__res = _M_length();
530
531      const size_type __capacity = _M_capacity();
532      if (__res != __capacity)
533	{
534	  if (__res > __capacity
535	      || __res > size_type(_S_local_capacity))
536	    {
537	      _CharT* __tmp = _M_create(__res, __capacity);
538	      this->_S_copy(__tmp, _M_data(), _M_length() + 1);
539	      _M_dispose();
540	      _M_data(__tmp);
541	      _M_capacity(__res);
542	    }
543	  else if (!_M_is_local())
544	    {
545	      this->_S_copy(_M_local_data, _M_data(), _M_length() + 1);
546	      _M_destroy(__capacity);
547	      _M_data(_M_local_data);
548	    }
549	}
550    }
551
552  template<typename _CharT, typename _Traits, typename _Alloc>
553    void
554    __sso_string_base<_CharT, _Traits, _Alloc>::
555    _M_mutate(size_type __pos, size_type __len1, const _CharT* __s,
556	      const size_type __len2)
557    {
558      const size_type __how_much = _M_length() - __pos - __len1;
559
560      size_type __new_capacity = _M_length() + __len2 - __len1;
561      _CharT* __r = _M_create(__new_capacity, _M_capacity());
562
563      if (__pos)
564	this->_S_copy(__r, _M_data(), __pos);
565      if (__s && __len2)
566	this->_S_copy(__r + __pos, __s, __len2);
567      if (__how_much)
568	this->_S_copy(__r + __pos + __len2,
569		_M_data() + __pos + __len1, __how_much);
570
571      _M_dispose();
572      _M_data(__r);
573      _M_capacity(__new_capacity);
574    }
575
576  template<typename _CharT, typename _Traits, typename _Alloc>
577    void
578    __sso_string_base<_CharT, _Traits, _Alloc>::
579    _M_erase(size_type __pos, size_type __n)
580    {
581      const size_type __how_much = _M_length() - __pos - __n;
582
583      if (__how_much && __n)
584	this->_S_move(_M_data() + __pos, _M_data() + __pos + __n,
585		__how_much);
586
587      _M_set_length(_M_length() - __n);
588    }
589
590_GLIBCXX_END_NAMESPACE
591
592#endif /* _SSO_STRING_BASE_H */
593