1// Main templates for the -*- C++ -*- string classes.
2// Copyright (C) 1994, 1995, 1999 Free Software Foundation
3
4// This file is part of the GNU ANSI C++ Library.  This library is free
5// software; you can redistribute it and/or modify it under the
6// terms of the GNU General Public License as published by the
7// Free Software Foundation; either version 2, or (at your option)
8// any later version.
9
10// This library is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14
15// You should have received a copy of the GNU General Public License
16// along with this library; see the file COPYING.  If not, write to the Free
17// Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19// As a special exception, if you link this library with files
20// compiled with a GNU compiler to produce an executable, this does not cause
21// the resulting executable to be covered by the GNU General Public License.
22// This exception does not however invalidate any other reasons why
23// the executable file might be covered by the GNU General Public License.
24
25// Written by Jason Merrill based upon the specification by Takanori Adachi
26// in ANSI X3J16/94-0013R2.
27
28#ifndef __BASTRING__
29#define __BASTRING__
30
31#ifdef __GNUG__
32#pragma interface
33#endif
34
35#include <cstddef>
36#include <std/straits.h>
37
38// NOTE : This does NOT conform to the draft standard and is likely to change
39#include <alloc.h>
40
41#ifdef __HAIKU__
42#	include <config/types.h>
43#endif
44
45extern "C++" {
46class istream; class ostream;
47
48#include <iterator>
49
50#ifdef __STL_USE_EXCEPTIONS
51
52extern void __out_of_range (const char *);
53extern void __length_error (const char *);
54
55#define OUTOFRANGE(cond) \
56  do { if (cond) __out_of_range (#cond); } while (0)
57#define LENGTHERROR(cond) \
58  do { if (cond) __length_error (#cond); } while (0)
59
60#else
61
62#include <cassert>
63#define OUTOFRANGE(cond) assert (!(cond))
64#define LENGTHERROR(cond) assert (!(cond))
65
66#endif
67
68#ifdef __HAIKU__
69extern "C" __haiku_int32 atomic_add(__haiku_int32* value,
70	__haiku_int32 addvalue);
71#endif	/* __HAIKU__ */
72
73template <class charT, class traits = string_char_traits<charT>,
74	  class Allocator = alloc >
75class basic_string
76{
77private:
78  struct Rep {
79    size_t len, res, ref;
80    bool selfish;
81
82    charT* data () { return reinterpret_cast<charT *>(this + 1); }
83    charT& operator[] (size_t s) { return data () [s]; }
84#ifdef __HAIKU__
85    charT* grab () { if (selfish) return clone (); atomic_add((__haiku_int32*) &ref, 1); return data (); }
86    void release() { if (atomic_add((__haiku_int32*) &ref, -1) == 1) delete this; }
87#else
88    charT* grab () { if (selfish) return clone (); ++ref; return data (); }
89#if defined __i486__ || defined __i586__ || defined __i686__
90    void release ()
91      {
92	size_t __val;
93	// This opcode exists as a .byte instead of as a mnemonic for the
94	// benefit of SCO OpenServer 5.  The system assembler (which is
95	// essentially required on this target) can't assemble xaddl in
96	//COFF mode.
97	asm (".byte 0xf0, 0x0f, 0xc1, 0x02" // lock; xaddl %eax, (%edx)
98	    : "=a" (__val)
99	    : "0" (-1), "m" (ref), "d" (&ref)
100	    : "memory");
101
102	if (__val == 1)
103	  delete this;
104      }
105#elif defined __sparcv9__
106    void release ()
107      {
108	size_t __newval, __oldval = ref;
109	do
110	  {
111	    __newval = __oldval - 1;
112	    __asm__ ("cas	[%4], %2, %0"
113		     : "=r" (__oldval), "=m" (ref)
114		     : "r" (__oldval), "m" (ref), "r"(&(ref)), "0" (__newval));
115	  }
116	while (__newval != __oldval);
117
118	if (__oldval == 0)
119	  delete this;
120      }
121#else
122    void release () { if (--ref == 0) delete this; }
123#endif
124#endif /* __HAIKU__ */
125    inline static void * operator new (size_t, size_t);
126    inline static void operator delete (void *);
127    inline static Rep* create (size_t);
128    charT* clone ();
129
130    inline void copy (size_t, const charT *, size_t);
131    inline void move (size_t, const charT *, size_t);
132    inline void set  (size_t, const charT,   size_t);
133
134    inline static bool excess_slop (size_t, size_t);
135    inline static size_t frob_size (size_t);
136
137  private:
138    Rep &operator= (const Rep &);
139  };
140
141public:
142// types:
143  typedef	   traits		traits_type;
144  typedef typename traits::char_type	value_type;
145  typedef	   Allocator		allocator_type;
146
147  typedef size_t size_type;
148  typedef ptrdiff_t difference_type;
149  typedef charT& reference;
150  typedef const charT& const_reference;
151  typedef charT* pointer;
152  typedef const charT* const_pointer;
153  typedef pointer iterator;
154  typedef const_pointer const_iterator;
155  typedef ::reverse_iterator<iterator> reverse_iterator;
156  typedef ::reverse_iterator<const_iterator> const_reverse_iterator;
157  static const size_type npos = static_cast<size_type>(-1);
158
159private:
160  Rep *rep () const { return reinterpret_cast<Rep *>(dat) - 1; }
161  void repup (Rep *p) { rep ()->release (); dat = p->data (); }
162
163public:
164  const charT* data () const
165    { return rep ()->data(); }
166  size_type length () const
167    { return rep ()->len; }
168  size_type size () const
169    { return rep ()->len; }
170  size_type capacity () const
171    { return rep ()->res; }
172  size_type max_size () const
173    { return (npos - 1)/sizeof (charT); }		// XXX
174  bool empty () const
175    { return size () == 0; }
176
177// _lib.string.cons_ construct/copy/destroy:
178  basic_string& operator= (const basic_string& str)
179    {
180      if (&str != this) { rep ()->release (); dat = str.rep ()->grab (); }
181      return *this;
182    }
183
184  explicit basic_string (): dat (nilRep.grab ()) { }
185  basic_string (const basic_string& _str): dat (_str.rep ()->grab ()) { }
186  basic_string (const basic_string& _str, size_type pos, size_type n = npos)
187    : dat (nilRep.grab ()) { assign (_str, pos, n); }
188  basic_string (const charT* s, size_type n)
189    : dat (nilRep.grab ()) { assign (s, n); }
190  basic_string (const charT* s)
191    : dat (nilRep.grab ()) { assign (s); }
192  basic_string (size_type n, charT c)
193    : dat (nilRep.grab ()) { assign (n, c); }
194#ifdef __STL_MEMBER_TEMPLATES
195  template<class InputIterator>
196    basic_string(InputIterator __begin, InputIterator __end)
197#else
198  basic_string(const_iterator __begin, const_iterator __end)
199#endif
200    : dat (nilRep.grab ()) { assign (__begin, __end); }
201
202  ~basic_string ()
203    { rep ()->release (); }
204
205  void swap (basic_string &s) { charT *d = dat; dat = s.dat; s.dat = d; }
206
207  basic_string& append (const basic_string& _str, size_type pos = 0,
208			size_type n = npos)
209    { return replace (length (), 0, _str, pos, n); }
210  basic_string& append (const charT* s, size_type n)
211    { return replace (length (), 0, s, n); }
212  basic_string& append (const charT* s)
213    { return append (s, traits::length (s)); }
214  basic_string& append (size_type n, charT c)
215    { return replace (length (), 0, n, c); }
216#ifdef __STL_MEMBER_TEMPLATES
217  template<class InputIterator>
218    basic_string& append(InputIterator first, InputIterator last)
219#else
220  basic_string& append(const_iterator first, const_iterator last)
221#endif
222    { return replace (iend (), iend (), first, last); }
223
224  void push_back(charT __c)
225  { append(1, __c); }
226
227  basic_string& assign (const basic_string& str, size_type pos = 0,
228			size_type n = npos)
229    { return replace (0, npos, str, pos, n); }
230  basic_string& assign (const charT* s, size_type n)
231    { return replace (0, npos, s, n); }
232  basic_string& assign (const charT* s)
233    { return assign (s, traits::length (s)); }
234  basic_string& assign (size_type n, charT c)
235    { return replace (0, npos, n, c); }
236#ifdef __STL_MEMBER_TEMPLATES
237  template<class InputIterator>
238    basic_string& assign(InputIterator first, InputIterator last)
239#else
240  basic_string& assign(const_iterator first, const_iterator last)
241#endif
242    { return replace (ibegin (), iend (), first, last); }
243
244  basic_string& operator= (const charT* s)
245    { return assign (s); }
246  basic_string& operator= (charT c)
247    { return assign (1, c); }
248
249  basic_string& operator+= (const basic_string& rhs)
250    { return append (rhs); }
251  basic_string& operator+= (const charT* s)
252    { return append (s); }
253  basic_string& operator+= (charT c)
254    { return append (1, c); }
255
256  basic_string& insert (size_type pos1, const basic_string& str,
257			size_type pos2 = 0, size_type n = npos)
258    { return replace (pos1, 0, str, pos2, n); }
259  basic_string& insert (size_type pos, const charT* s, size_type n)
260    { return replace (pos, 0, s, n); }
261  basic_string& insert (size_type pos, const charT* s)
262    { return insert (pos, s, traits::length (s)); }
263  basic_string& insert (size_type pos, size_type n, charT c)
264    { return replace (pos, 0, n, c); }
265  iterator insert(iterator p, charT c)
266    { size_type __o = p - ibegin ();
267      insert (p - ibegin (), 1, c); selfish ();
268      return ibegin () + __o; }
269  iterator insert(iterator p, size_type n, charT c)
270    { size_type __o = p - ibegin ();
271      insert (p - ibegin (), n, c); selfish ();
272      return ibegin () + __o; }
273#ifdef __STL_MEMBER_TEMPLATES
274  template<class InputIterator>
275    void insert(iterator p, InputIterator first, InputIterator last)
276#else
277  void insert(iterator p, const_iterator first, const_iterator last)
278#endif
279    { replace (p, p, first, last); }
280
281  basic_string& erase (size_type pos = 0, size_type n = npos)
282    { return replace (pos, n, (size_type)0, (charT)0); }
283  iterator erase(iterator p)
284    { size_type __o = p - begin();
285      replace (__o, 1, (size_type)0, (charT)0); selfish ();
286      return ibegin() + __o; }
287  iterator erase(iterator f, iterator l)
288    { size_type __o = f - ibegin();
289      replace (__o, l-f, (size_type)0, (charT)0);selfish ();
290      return ibegin() + __o; }
291
292  void clear()
293    { erase(begin(), end()); }
294  basic_string& replace (size_type pos1, size_type n1, const basic_string& str,
295			 size_type pos2 = 0, size_type n2 = npos);
296  basic_string& replace (size_type pos, size_type n1, const charT* s,
297			 size_type n2);
298  basic_string& replace (size_type pos, size_type n1, const charT* s)
299    { return replace (pos, n1, s, traits::length (s)); }
300  basic_string& replace (size_type pos, size_type n1, size_type n2, charT c);
301  basic_string& replace (size_type pos, size_type n, charT c)
302    { return replace (pos, n, 1, c); }
303  basic_string& replace (iterator i1, iterator i2, const basic_string& str)
304    { return replace (i1 - ibegin (), i2 - i1, str); }
305  basic_string& replace (iterator i1, iterator i2, const charT* s, size_type n)
306    { return replace (i1 - ibegin (), i2 - i1, s, n); }
307  basic_string& replace (iterator i1, iterator i2, const charT* s)
308    { return replace (i1 - ibegin (), i2 - i1, s); }
309  basic_string& replace (iterator i1, iterator i2, size_type n, charT c)
310    { return replace (i1 - ibegin (), i2 - i1, n, c); }
311#ifdef __STL_MEMBER_TEMPLATES
312  template<class InputIterator>
313    basic_string& replace(iterator i1, iterator i2,
314			  InputIterator j1, InputIterator j2);
315#else
316  basic_string& replace(iterator i1, iterator i2,
317			const_iterator j1, const_iterator j2);
318#endif
319
320private:
321  static charT eos () { return traits::eos (); }
322  void unique () { if (rep ()->ref > 1) alloc (length (), true); }
323  void selfish () { unique (); rep ()->selfish = true; }
324
325public:
326  charT operator[] (size_type pos) const
327    {
328      if (pos == length ())
329	return eos ();
330      return data ()[pos];
331    }
332
333  reference operator[] (size_type pos)
334    { selfish (); return (*rep ())[pos]; }
335
336  reference at (size_type pos)
337    {
338      OUTOFRANGE (pos >= length ());
339      return (*this)[pos];
340    }
341  const_reference at (size_type pos) const
342    {
343      OUTOFRANGE (pos >= length ());
344      return data ()[pos];
345    }
346
347private:
348  void terminate () const
349    { traits::assign ((*rep ())[length ()], eos ()); }
350
351public:
352  const charT* c_str () const
353    {
354	  static const charT null_str[1] = {0};
355	  if (length () == 0) return null_str; terminate (); return data ();
356	}
357  void resize (size_type n, charT c);
358  void resize (size_type n)
359    { resize (n, eos ()); }
360  void reserve (size_type) { }
361
362  size_type copy (charT* s, size_type n, size_type pos = 0) const;
363
364  size_type find (const basic_string& str, size_type pos = 0) const
365    { return find (str.data(), pos, str.length()); }
366  size_type find (const charT* s, size_type pos, size_type n) const;
367  size_type find (const charT* _s, size_type pos = 0) const
368    { return find (_s, pos, traits::length (_s)); }
369  size_type find (charT c, size_type pos = 0) const;
370
371  size_type rfind (const basic_string& str, size_type pos = npos) const
372    { return rfind (str.data(), pos, str.length()); }
373  size_type rfind (const charT* s, size_type pos, size_type n) const;
374  size_type rfind (const charT* s, size_type pos = npos) const
375    { return rfind (s, pos, traits::length (s)); }
376  size_type rfind (charT c, size_type pos = npos) const;
377
378  size_type find_first_of (const basic_string& str, size_type pos = 0) const
379    { return find_first_of (str.data(), pos, str.length()); }
380  size_type find_first_of (const charT* s, size_type pos, size_type n) const;
381  size_type find_first_of (const charT* s, size_type pos = 0) const
382    { return find_first_of (s, pos, traits::length (s)); }
383  size_type find_first_of (charT c, size_type pos = 0) const
384    { return find (c, pos); }
385
386  size_type find_last_of (const basic_string& str, size_type pos = npos) const
387    { return find_last_of (str.data(), pos, str.length()); }
388  size_type find_last_of (const charT* s, size_type pos, size_type n) const;
389  size_type find_last_of (const charT* s, size_type pos = npos) const
390    { return find_last_of (s, pos, traits::length (s)); }
391  size_type find_last_of (charT c, size_type pos = npos) const
392    { return rfind (c, pos); }
393
394  size_type find_first_not_of (const basic_string& str, size_type pos = 0) const
395    { return find_first_not_of (str.data(), pos, str.length()); }
396  size_type find_first_not_of (const charT* s, size_type pos, size_type n) const;
397  size_type find_first_not_of (const charT* s, size_type pos = 0) const
398    { return find_first_not_of (s, pos, traits::length (s)); }
399  size_type find_first_not_of (charT c, size_type pos = 0) const;
400
401  size_type find_last_not_of (const basic_string& str, size_type pos = npos) const
402    { return find_last_not_of (str.data(), pos, str.length()); }
403  size_type find_last_not_of (const charT* s, size_type pos, size_type n) const;
404  size_type find_last_not_of (const charT* s, size_type pos = npos) const
405    { return find_last_not_of (s, pos, traits::length (s)); }
406  size_type find_last_not_of (charT c, size_type pos = npos) const;
407
408  basic_string substr (size_type pos = 0, size_type n = npos) const
409    { return basic_string (*this, pos, n); }
410
411
412  // BeOS bogus versions
413  int compare (const charT* s, size_type pos, size_type n) const;
414  int compare (const basic_string& str, size_type pos = 0, size_type n = npos) const;
415  // There is no 'strncmp' equivalent for charT pointers.
416
417  // Correct std C++ prototypes
418  int compare (size_type pos, size_type n, const basic_string& str) const
419	{ return compare(str, pos, n); }
420  int compare (size_type pos, size_type n, const charT* s) const
421    { return compare(s, pos, n); }
422  int compare (size_type pos, size_type n, const charT* s, size_type n2) const
423    { if (n > n2) n = n2; return compare(s, pos, n); }
424  int compare (const charT* s, size_type pos = 0) const
425    { return compare (s, pos, traits::length (s)); }
426
427  iterator begin () { selfish (); return &(*this)[0]; }
428  iterator end () { selfish (); return &(*this)[length ()]; }
429
430private:
431  iterator ibegin () const { return &(*rep ())[0]; }
432  iterator iend () const { return &(*rep ())[length ()]; }
433
434public:
435  const_iterator begin () const { return ibegin (); }
436  const_iterator end () const { return iend (); }
437
438  reverse_iterator       rbegin() { return reverse_iterator (end ()); }
439  const_reverse_iterator rbegin() const
440    { return const_reverse_iterator (end ()); }
441  reverse_iterator       rend() { return reverse_iterator (begin ()); }
442  const_reverse_iterator rend() const
443    { return const_reverse_iterator (begin ()); }
444
445private:
446  void alloc (size_type size, bool save);
447  static size_type _find (const charT* ptr, charT c, size_type xpos, size_type len);
448  inline bool check_realloc (size_type s) const;
449
450  static Rep nilRep;
451  charT *dat;
452};
453
454#ifdef __STL_MEMBER_TEMPLATES
455template <class charT, class traits, class Allocator> template <class InputIterator>
456basic_string <charT, traits, Allocator>& basic_string <charT, traits, Allocator>::
457replace (iterator i1, iterator i2, InputIterator j1, InputIterator j2)
458#else
459template <class charT, class traits, class Allocator>
460basic_string <charT, traits, Allocator>& basic_string <charT, traits, Allocator>::
461replace (iterator i1, iterator i2, const_iterator j1, const_iterator j2)
462#endif
463{
464  const size_type len = length ();
465  size_type pos = i1 - ibegin ();
466  size_type n1 = i2 - i1;
467  size_type n2 = j2 - j1;
468
469  OUTOFRANGE (pos > len);
470  if (n1 > len - pos)
471    n1 = len - pos;
472  LENGTHERROR (len - n1 > max_size () - n2);
473  size_t newlen = len - n1 + n2;
474
475  if (check_realloc (newlen))
476    {
477      Rep *p = Rep::create (newlen);
478      p->copy (0, data (), pos);
479      p->copy (pos + n2, data () + pos + n1, len - (pos + n1));
480      for (; j1 != j2; ++j1, ++pos)
481	traits::assign ((*p)[pos], *j1);
482      repup (p);
483    }
484  else
485    {
486      rep ()->move (pos + n2, data () + pos + n1, len - (pos + n1));
487      for (; j1 != j2; ++j1, ++pos)
488	traits::assign ((*rep ())[pos], *j1);
489    }
490  rep ()->len = newlen;
491
492  return *this;
493}
494
495template <class charT, class traits, class Allocator>
496inline basic_string <charT, traits, Allocator>
497operator+ (const basic_string <charT, traits, Allocator>& lhs,
498	   const basic_string <charT, traits, Allocator>& rhs)
499{
500  basic_string <charT, traits, Allocator> _str (lhs);
501  _str.append (rhs);
502  return _str;
503}
504
505template <class charT, class traits, class Allocator>
506inline basic_string <charT, traits, Allocator>
507operator+ (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
508{
509  basic_string <charT, traits, Allocator> _str (lhs);
510  _str.append (rhs);
511  return _str;
512}
513
514template <class charT, class traits, class Allocator>
515inline basic_string <charT, traits, Allocator>
516operator+ (charT lhs, const basic_string <charT, traits, Allocator>& rhs)
517{
518  basic_string <charT, traits, Allocator> _str (1, lhs);
519  _str.append (rhs);
520  return _str;
521}
522
523template <class charT, class traits, class Allocator>
524inline basic_string <charT, traits, Allocator>
525operator+ (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
526{
527  basic_string <charT, traits, Allocator> _str (lhs);
528  _str.append (rhs);
529  return _str;
530}
531
532template <class charT, class traits, class Allocator>
533inline basic_string <charT, traits, Allocator>
534operator+ (const basic_string <charT, traits, Allocator>& lhs, charT rhs)
535{
536  basic_string <charT, traits, Allocator> str (lhs);
537  str.append (1, rhs);
538  return str;
539}
540
541template <class charT, class traits, class Allocator>
542inline bool
543operator== (const basic_string <charT, traits, Allocator>& lhs,
544	    const basic_string <charT, traits, Allocator>& rhs)
545{
546  return (lhs.compare (rhs) == 0);
547}
548
549template <class charT, class traits, class Allocator>
550inline bool
551operator== (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
552{
553  return (rhs.compare (lhs) == 0);
554}
555
556template <class charT, class traits, class Allocator>
557inline bool
558operator== (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
559{
560  return (lhs.compare (rhs) == 0);
561}
562
563template <class charT, class traits, class Allocator>
564inline bool
565operator!= (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
566{
567  return (rhs.compare (lhs) != 0);
568}
569
570template <class charT, class traits, class Allocator>
571inline bool
572operator!= (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
573{
574  return (lhs.compare (rhs) != 0);
575}
576
577template <class charT, class traits, class Allocator>
578inline bool
579operator< (const basic_string <charT, traits, Allocator>& lhs,
580	    const basic_string <charT, traits, Allocator>& rhs)
581{
582  return (lhs.compare (rhs) < 0);
583}
584
585template <class charT, class traits, class Allocator>
586inline bool
587operator< (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
588{
589  return (rhs.compare (lhs) > 0);
590}
591
592template <class charT, class traits, class Allocator>
593inline bool
594operator< (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
595{
596  return (lhs.compare (rhs) < 0);
597}
598
599template <class charT, class traits, class Allocator>
600inline bool
601operator> (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
602{
603  return (rhs.compare (lhs) < 0);
604}
605
606template <class charT, class traits, class Allocator>
607inline bool
608operator> (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
609{
610  return (lhs.compare (rhs) > 0);
611}
612
613template <class charT, class traits, class Allocator>
614inline bool
615operator<= (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
616{
617  return (rhs.compare (lhs) >= 0);
618}
619
620template <class charT, class traits, class Allocator>
621inline bool
622operator<= (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
623{
624  return (lhs.compare (rhs) <= 0);
625}
626
627template <class charT, class traits, class Allocator>
628inline bool
629operator>= (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
630{
631  return (rhs.compare (lhs) <= 0);
632}
633
634template <class charT, class traits, class Allocator>
635inline bool
636operator>= (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
637{
638  return (lhs.compare (rhs) >= 0);
639}
640
641template <class charT, class traits, class Allocator>
642inline bool
643operator!= (const basic_string <charT, traits, Allocator>& lhs,
644	    const basic_string <charT, traits, Allocator>& rhs)
645{
646  return (lhs.compare (rhs) != 0);
647}
648
649template <class charT, class traits, class Allocator>
650inline bool
651operator> (const basic_string <charT, traits, Allocator>& lhs,
652	   const basic_string <charT, traits, Allocator>& rhs)
653{
654  return (lhs.compare (rhs) > 0);
655}
656
657template <class charT, class traits, class Allocator>
658inline bool
659operator<= (const basic_string <charT, traits, Allocator>& lhs,
660	    const basic_string <charT, traits, Allocator>& rhs)
661{
662  return (lhs.compare (rhs) <= 0);
663}
664
665template <class charT, class traits, class Allocator>
666inline bool
667operator>= (const basic_string <charT, traits, Allocator>& lhs,
668	    const basic_string <charT, traits, Allocator>& rhs)
669{
670  return (lhs.compare (rhs) >= 0);
671}
672
673class istream; class ostream;
674template <class charT, class traits, class Allocator> istream&
675operator>> (istream&, basic_string <charT, traits, Allocator>&);
676template <class charT, class traits, class Allocator> ostream&
677operator<< (ostream&, const basic_string <charT, traits, Allocator>&);
678template <class charT, class traits, class Allocator> istream&
679getline (istream&, basic_string <charT, traits, Allocator>&, charT delim = '\n');
680
681} // extern "C++"
682
683#include <std/bastring.cc>
684
685#endif
686