文章标题 SGI的base_string解析
2017-06-19 21:34
183 查看
SGI的base_string解析
首先介绍一下SGI的base_string。我用的版本sgi-stl-2.91.57,base_string有两个文件一个std/bastring.h一个std/bastring.cc。base_string使用引用计数节约内存的消耗,这也使得编程变得麻烦一些。base_string内有一个内部类Rep,整个base_string 只有一个静态的Rep成员(用于空字符串)和一个dat(base_string实际字符内存的首地址),对于非空字符串base_string使用隐藏的Rep来实现(在构造base_string时实际上的内存为sizeof(Rep)+base_string的字符容量,也就是Rep数据成员之后就是dat指向的地址)Rep的数据成员是len、res、ref 、selfish(base_string的长度、容量、引用计数、是否为私有标记)<我不懂replace函数为什么不用有的不需要重新分配内存呢?有会的给我讲讲啊!!!>1. 首先看一下base_string的模板的参数
template <class charT, class traits = string_char_traits<charT>, class Allocator = alloc > class basic_string{//...}
关于Alloc这里就不说了,string_char_traits是一个模板,他有两个特化版本参数分别为char和wchar_t。再看base_string有必要看看string_char_traits。因为他用到了string_char_traits里的一些函数。代码很简单直接就能看懂
#ifndef __STRING_CHAR_TRAITS__ #define __STRING_CHAR_TRAITS__ #ifdef __GNUG__ // For string_char_traits <char> #pragma interface "std/straits.h" #endif #include <cstddef> extern "C++" { template <class charT> struct string_char_traits { typedef charT char_type; // for users to acquire the basic character type // constraints static void assign (char_type& c1, const char_type& c2) { c1 = c2; } static bool eq (const char_type& c1, const char_type& c2) { return (c1 == c2); } static bool ne (const char_type& c1, const char_type& c2) { return !(c1 == c2); } static bool lt (const char_type& c1, const char_type& c2) { return (c1 < c2); } static char_type eos () { return char_type(); } // the null character static bool is_del(char_type a) { return 0; } // characteristic function for delimiters of charT // speed-up functions static int compare (const char_type* s1, const char_type* s2, size_t n) { size_t i; for (i = 0; i < n; ++i) if (ne (s1[i], s2[i])) return lt (s1[i], s2[i]) ? -1 : 1; return 0; } static size_t length (const char_type* s) { size_t l = 0; while (ne (*s++, eos ())) ++l; return l; } static char_type* copy (char_type* s1, const char_type* s2, size_t n) { for (; n--; ) assign (s1 , s2 ); return s1; } static char_type* move (char_type* s1, const char_type* s2, size_t n) { char_type a ; size_t i; for (i = 0; i < n; ++i) assign (a[i], s2[i]); for (i = 0; i < n; ++i) assign (s1[i], a[i]); return s1; } static char_type* set (char_type* s1, const char_type& c, size_t n) { for (; n--; ) assign (s1 , c); return s1; } }; class istream; class ostream; #include <cctype> #include <cstring> struct string_char_traits <char> { typedef char char_type; static void assign (char_type& c1, const char_type& c2) { c1 = c2; } static bool eq (const char_type & c1, const char_type& c2) { return (c1 == c2); } static bool ne (const char_type& c1, const char_type& c2) { return (c1 != c2); } static bool lt (const char_type& c1, const char_type& c2) { return (c1 < c2); } static char_type eos () { return 0; } static bool is_del(char_type a) { return isspace(a); } static int compare (const char_type* s1, const char_type* s2, size_t n) { return memcmp (s1, s2, n); } static size_t length (const char_type* s) { return strlen (s); } static char_type* copy (char_type* s1, const char_type* s2, size_t n) { return (char_type*) memcpy (s1, s2, n); } static char_type* move (char_type* s1, const char_type* s2, size_t n) { return (char_type*) memmove (s1, s2, n); } static char_type* set (char_type* s1, const char_type& c, size_t n) { return (char_type*) memset (s1, c, n); } }; #if 0 #include <cwctype> struct string_char_traits <wchar_t> { typedef wchar_t char_type; static void assign (char_type& c1, const char_type& c2) { c1 = c2; } static bool eq (const char_type & c1, const char_type& c2) { return (c1 == c2); } static bool ne (const char_type& c1, const char_type& c2) { return (c1 != c2); } static bool lt (const char_type& c1, const char_type& c2) { return (c1 < c2); } static char_type eos () { return 0; } static bool is_del(char_type a) { return iswspace(a); } static int compare (const char_type* s1, const char_type* s2, size_t n) { return wmemcmp (s1, s2, n); } static size_t length (const char_type* s) { return wcslen (s); } static char_type* copy (char_type* s1, const char_type* s2, size_t n) { return wmemcpy (s1, s2, n); } static char_type* set (char_type* s1, const char_type& c, size_t n) { return wmemset (s1, c, n); } }; #endif } // extern "C++" #endif
base-string的头文件
#ifndef __BASTRING__ #define __BASTRING__ #ifdef __GNUG__ #pragma interface #endif #include <cstddef> #include <std/straits.h> // NOTE : This does NOT conform to the draft standard and is likely to change #include <alloc.h> extern "C++" { class istream; class ostream; #include <iterator> #ifdef __STL_USE_EXCEPTIONS //外部函数声明 extern void __out_of_range (const char *); extern void __length_error (const char *); //这两个宏用于判断cond; cond必须要能转化为bool类型 //如果cond为真则调用对应的函数 #define OUTOFRANGE(cond) \ do { if (cond) __out_of_range (#cond); } while (0) #define LENGTHERROR(cond) \ do { if (cond) __length_error (#cond); } while (0) #else #include <cassert> #define OUTOFRANGE(cond) assert (!(cond)) #define LENGTHERROR(cond) assert (!(cond)) #endif //注意这里的 string_char_traits alloc template <class charT, class traits = string_char_traits<charT>, class Allocator = alloc > class basic_string { private: //内部类 struct Rep { size_t len, res, ref;//string的字符长度、容量、引用技术 bool selfish;//是否为私有的标记 charT* data () { return reinterpret_cast<charT *>(this + 1); }//返回string的字符首地址 相当于&(*this)+sizeof(Rep) charT& operator[] (size_t s) { return data () [s]; }//返回string的第s+1个字符 //如果为私有则返回clone() ,否则增加引用计数、返回string元素首地址 charT* grab () { if (selfish) return clone (); ++ref; return data (); } void release () { if (--ref == 0) delete this; } //重载operator new(这里不是placement new),而是分配sizeof(Rep)+string的字符所需要的字节数 inline static void * operator new (size_t, size_t); //收回分配的内存 inline static void operator delete (void *); inline static Rep* create (size_t); charT* clone (); inline void copy (size_t, const charT *, size_t); inline void move (size_t, const charT *, size_t); inline void set (size_t, const charT, size_t); inline static bool excess_slop (size_t, size_t); inline static size_t frob_size (size_t); private: Rep &operator= (const Rep &);//禁止复制操作符 }; public: // types: typedef traits traits_type; typedef typename traits::char_type value_type; typedef Allocator allocator_type; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef charT& reference; typedef const charT& const_reference; typedef charT* pointer; typedef const charT* const_pointer; typedef pointer iterator;//这里看出迭代器只是char*或wchar_t* typedef const_pointer const_iterator; typedef ::reverse_iterator<iterator> reverse_iterator; typedef ::reverse_iterator<const_iterator> const_reverse_iterator; static const size_type npos = static_cast<size_type>(-1); private: //由Rep的data()知道这里是Rep的首地址 Rep *rep() const { return reinterpret_cast<Rep *>(dat)-1; } void repup (Rep *p) { rep ()->release (); dat = p->data (); } public: const charT* data 1ab91 () const { return rep ()->data(); } size_type length () const { return rep ()->len; } size_type size () const { return rep ()->len; } size_type capacity () const { return rep ()->res; } size_type max_size () const { return (npos - 1)/sizeof (charT); } // XXX bool empty () const { return size () == 0; } // _lib.string.cons_ construct/copy/destroy: basic_string& operator= (const basic_string& str) { if (&str != this) { rep ()->release (); dat = str.rep ()->grab (); } return *this; } //构造函数 explicit basic_string (): dat (nilRep.grab ()) { } basic_string (const basic_string& str): dat (str.rep ()->grab ()) { } basic_string (const basic_string& str, size_type pos, size_type n = npos) : dat (nilRep.grab ()) { assign (str, pos, n); } basic_string (const charT* s, size_type n) : dat (nilRep.grab ()) { assign (s, n); } basic_string (const charT* s) : dat (nilRep.grab ()) { assign (s); } basic_string (size_type n, charT c) : dat (nilRep.grab ()) { assign (n, c); } #ifdef __STL_MEMBER_TEMPLATES template<class InputIterator> basic_string(InputIterator begin, InputIterator end) #else basic_string(const_iterator begin, const_iterator end) #endif : dat (nilRep.grab ()) { assign (begin, end); } //析构函数 ~basic_string () { rep ()->release (); } //这里看出交换string只是交换dat数据成员,避免大量的复制 void swap (basic_string &s) { charT *d = dat; dat = s.dat; s.dat = d; } //append函数 调用replace实现 basic_string& append (const basic_string& str, size_type pos = 0, size_type n = npos) { return replace (length (), 0, str, pos, n); } basic_string& append (const charT* s, size_type n) { return replace (length (), 0, s, n); } basic_string& append (const charT* s) { return append (s, traits::length (s)); } basic_string& append (size_type n, charT c) { return replace (length (), 0, n, c); } #ifdef __STL_MEMBER_TEMPLATES template<class InputIterator> basic_string& append(InputIterator first, InputIterator last) #else basic_string& append(const_iterator first, const_iterator last) #endif { return replace (iend (), iend (), first, last); } //assign函数 调用replace实现 basic_string& assign (const basic_string& str, size_type pos = 0, size_type n = npos) { return replace (0, npos, str, pos, n); } basic_string& assign (const charT* s, size_type n) { return replace (0, npos, s, n); } basic_string& assign (const charT* s) { return assign (s, traits::length (s)); } basic_string& assign (size_type n, charT c) { return replace (0, npos, n, c); } #ifdef __STL_MEMBER_TEMPLATES template<class InputIterator> basic_string& assign(InputIterator first, InputIterator last) #else basic_string& assign(const_iterator first, const_iterator last) #endif { return replace (ibegin (), iend (), first, last); } basic_string& operator= (const charT* s) { return assign (s); } basic_string& operator= (charT c) { return assign (1, c); } basic_string& operator+= (const basic_string& rhs) { return append (rhs); } basic_string& operator+= (const charT* s) { return append (s); } basic_string& operator+= (charT c) { return append (1, c); } basic_string& insert (size_type pos1, const basic_string& str, size_type pos2 = 0, size_type n = npos) { return replace (pos1, 0, str, pos2, n); } basic_string& insert (size_type pos, const charT* s, size_type n) { return replace (pos, 0, s, n); } basic_string& insert (size_type pos, const charT* s) { return insert (pos, s, traits::length (s)); } basic_string& insert (size_type pos, size_type n, charT c) { return replace (pos, 0, n, c); } iterator insert(iterator p, charT c) { size_type __o = p - ibegin (); insert (p - ibegin (), 1, c); selfish (); return ibegin () + __o; } iterator insert(iterator p, size_type n, charT c) { size_type __o = p - ibegin (); insert (p - ibegin (), n, c); selfish (); return ibegin () + __o; } #ifdef __STL_MEMBER_TEMPLATES template<class InputIterator> void insert(iterator p, InputIterator first, InputIterator last) #else void insert(iterator p, const_iterator first, const_iterator last) #endif { replace (p, p, first, last); } basic_string& erase (size_type pos = 0, size_type n = npos) { return replace (pos, n, (size_type)0, (charT)0); } iterator erase(iterator p) { size_type __o = p - begin(); replace (__o, 1, (size_type)0, (charT)0); selfish (); return ibegin() + __o; } iterator erase(iterator f, iterator l) { size_type __o = f - ibegin(); replace (__o, l-f, (size_type)0, (charT)0);selfish (); return ibegin() + __o; } basic_string& replace (size_type pos1, size_type n1, const basic_string& str, size_type pos2 = 0, size_type n2 = npos); basic_string& replace (size_type pos, size_type n1, const charT* s, size_type n2); basic_string& replace (size_type pos, size_type n1, const charT* s) { return replace (pos, n1, s, traits::length (s)); } basic_string& replace (size_type pos, size_type n1, size_type n2, charT c); basic_string& replace (size_type pos, size_type n, charT c) { return replace (pos, n, 1, c); } basic_string& replace (iterator i1, iterator i2, const basic_string& str) { return replace (i1 - ibegin (), i2 - i1, str); } basic_string& replace (iterator i1, iterator i2, const charT* s, size_type n) { return replace (i1 - ibegin (), i2 - i1, s, n); } basic_string& replace (iterator i1, iterator i2, const charT* s) { return replace (i1 - ibegin (), i2 - i1, s); } basic_string& replace (iterator i1, iterator i2, size_type n, charT c) { return replace (i1 - ibegin (), i2 - i1, n, c); } #ifdef __STL_MEMBER_TEMPLATES template<class InputIterator> basic_string& replace(iterator i1, iterator i2, InputIterator j1, InputIterator j2); #else basic_string& replace(iterator i1, iterator i2, const_iterator j1, const_iterator j2); #endif private: //返回char() 或 wchar_t() static charT eos () { return traits::eos (); } void unique () { if (rep ()->ref > 1) alloc (length (), true); } void selfish () { unique (); rep ()->selfish = true; }//很重要的函数 public: charT operator[] (size_type pos) const { if (pos == length ()) return eos (); return data ()[pos];//不明白为什么不用dat } //返回reference所以需要selfish() reference operator[] (size_type pos) { selfish (); return (*rep ())[pos]; }//注意上面的data()、这里的*rep()、下面的*this //这里有两种情况:1、当ref = 1 时三个应该是一样的 //2、当ref > 1时 selfish() -> unique()当ref>1时 -> alloc()重新分配内存 -> repup()用于更新dat //(*rep ())[pos]会调用Rep::operator []哪里最后就会用到更新的dat reference at (size_type pos) { OUTOFRANGE (pos >= length ()); return (*this)[pos];//调用上面的因为第一个为const,所以这里不需要selfish() } const_reference at (size_type pos) const { OUTOFRANGE (pos >= length ()); return data ()[pos]; } private: void terminate () const//应该就是给string最后一个字符的后面赋值为cahr() 或 wchar_t() //basic_string内部字符串的有效范围是[0, length) // 这里仅仅是在字符串的外面修改了一个“本来随机”的字符串为“结尾符”, // 并没有修改原本有效的数据,也没有修改字符串的有效长度! { traits::assign ((*rep ())[length ()], eos ()); } public: const charT* c_str () const//返回C的字符串 { if (length () == 0) return ""; terminate (); return data (); } void resize (size_type n, charT c); void resize (size_type n) { resize (n, eos ()); } void reserve (size_type) { } size_type copy (charT* s, size_type n, size_type pos = 0) const; size_type find (const basic_string& str, size_type pos = 0) const { return find (str.data(), pos, str.length()); } size_type find (const charT* s, size_type pos, size_type n) const; size_type find (const charT* s, size_type pos = 0) const { return find (s, pos, traits::length (s)); } size_type find (charT c, size_type pos = 0) const; size_type rfind (const basic_string& str, size_type pos = npos) const { return rfind (str.data(), pos, str.length()); } size_type rfind (const charT* s, size_type pos, size_type n) const; size_type rfind (const charT* s, size_type pos = npos) const { return rfind (s, pos, traits::length (s)); } size_type rfind (charT c, size_type pos = npos) const; size_type find_first_of (const basic_string& str, size_type pos = 0) const { return find_first_of (str.data(), pos, str.length()); } size_type find_first_of (const charT* s, size_type pos, size_type n) const; size_type find_first_of (const charT* s, size_type pos = 0) const { return find_first_of (s, pos, traits::length (s)); } size_type find_first_of (charT c, size_type pos = 0) const { return find (c, pos); } size_type find_last_of (const basic_string& str, size_type pos = npos) const { return find_last_of (str.data(), pos, str.length()); } size_type find_last_of (const charT* s, size_type pos, size_type n) const; size_type find_last_of (const charT* s, size_type pos = npos) const { return find_last_of (s, pos, traits::length (s)); } size_type find_last_of (charT c, size_type pos = npos) const { return rfind (c, pos); } size_type find_first_not_of (const basic_string& str, size_type pos = 0) const { return find_first_not_of (str.data(), pos, str.length()); } size_type find_first_not_of (const charT* s, size_type pos, size_type n) const; size_type find_first_not_of (const charT* s, size_type pos = 0) const { return find_first_not_of (s, pos, traits::length (s)); } size_type find_first_not_of (charT c, size_type pos = 0) const; size_type find_last_not_of (const basic_string& str, size_type pos = npos) const { return find_last_not_of (str.data(), pos, str.length()); } size_type find_last_not_of (const charT* s, size_type pos, size_type n) const; size_type find_last_not_of (const charT* s, size_type pos = npos) const { return find_last_not_of (s, pos, traits::length (s)); } size_type find_last_not_of (charT c, size_type pos = npos) const; basic_string substr (size_type pos = 0, size_type n = npos) const { return basic_string (*this, pos, n); }//调用构造函数 int compare (const basic_string& str, size_type pos = 0, size_type n = npos) const; // There is no 'strncmp' equivalent for charT pointers. int compare (const charT* s, size_type pos, size_type n) const; int compare (const charT* s, size_type pos = 0) const { return compare (s, pos, traits::length (s)); } iterator begin () { selfish (); return &(*this)[0]; }//为啥不直接return &(*this)[0]呢?里面也有 selfish ()啊 iterator end () { selfish (); return &(*this)[length ()]; } private: iterator ibegin () const { return &(*rep ())[0]; } iterator iend () const { return &(*rep ())[length ()]; } public: const_iterator begin () const { return ibegin (); } const_iterator end () const { return iend (); } reverse_iterator rbegin() { return reverse_iterator (end ()); } const_reverse_iterator rbegin() const { return const_reverse_iterator (end ()); } reverse_iterator rend() { return reverse_iterator (begin ()); } const_reverse_iterator rend() const { return const_reverse_iterator (begin ()); } private: void alloc (size_type size, bool save);//重新分配内存 static size_type _find (const charT* ptr, charT c, size_type xpos, size_type len); inline bool check_realloc (size_type s) const;//是否需要重新分配内存 static Rep nilRep;//静态Rep用于空string charT *dat;//唯一的一个数据成员 }; //replace 的一个实现 #ifdef __STL_MEMBER_TEMPLATES template <class charT, class traits, class Allocator> template <class InputIterator> basic_string <charT, traits, Allocator>& basic_string <charT, traits, Allocator>:: replace (iterator i1, iterator i2, InputIterator j1, InputIterator j2) #else template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>& basic_string <charT, traits, Allocator>:: replace (iterator i1, iterator i2, const_iterator j1, const_iterator j2) #endif { //将[i1 i2) 换成[j1 j2)的内容 const size_type len = length ();//string的长度 size_type pos = i1 - ibegin ();//replace的偏移地址 size_type n1 = i2 - i1;//replace的个数 size_type n2 = j2 - j1; OUTOFRANGE (pos > len); if (n1 > len - pos) n1 = len - pos;//replace的个数大于实际可以replace的个数的时候 实际replace (len-pos)个字符 LENGTHERROR (len - n1 > max_size () - n2);//保证replace后的字符个数不会大于max_size() size_t newlen = len - n1 + n2; if (check_realloc (newlen))//是否要重新分配内存 { Rep *p = Rep::create (newlen); p->copy (0, data (), pos); p->copy (pos + n2, data () + pos + n1, len - (pos + n1)); for (; j1 != j2; ++j1, ++pos) traits::assign ((*p)[pos], *j1); repup (p); } else { rep ()->move (pos + n2, data () + pos + n1, len - (pos + n1)); for (; j1 != j2; ++j1, ++pos) traits::assign ((*rep ())[pos], *j1); } rep ()->len = newlen; return *this; } template <class charT, class traits, class Allocator> inline basic_string <charT, traits, Allocator> operator+ (const basic_string <charT, traits, Allocator>& lhs, const basic_string <charT, traits, Allocator>& rhs) { basic_string <charT, traits, Allocator> str (lhs); str.append (rhs); return str; } template <class charT, class traits, class Allocator> inline basic_string <charT, traits, Allocator> operator+ (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs) { basic_string <charT, traits, Allocator> str (lhs); str.append (rhs); return str; } template <class charT, class traits, class Allocator> inline basic_string <charT, traits, Allocator> operator+ (charT lhs, const basic_string <charT, traits, Allocator>& rhs) { basic_string <charT, traits, Allocator> str (1, lhs); str.append (rhs); return str; } template <class charT, class traits, class Allocator> inline basic_string <charT, traits, Allocator> operator+ (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs) { basic_string <charT, traits, Allocator> str (lhs); str.append (rhs); return str; } template <class charT, class traits, class Allocator> inline basic_string <charT, traits, Allocator> operator+ (const basic_string <charT, traits, Allocator>& lhs, charT rhs) { basic_string <charT, traits, Allocator> str (lhs); str.append (1, rhs); return str; } template <class charT, class traits, class Allocator> inline bool operator== (const basic_string <charT, traits, Allocator>& lhs, const basic_string <charT, traits, Allocator>& rhs) { return (lhs.compare (rhs) == 0); } template <class charT, class traits, class Allocator> inline bool operator== (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs) { return (rhs.compare (lhs) == 0); } template <class charT, class traits, class Allocator> inline bool operator== (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs) { return (lhs.compare (rhs) == 0); } template <class charT, class traits, class Allocator> inline bool operator!= (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs) { return (rhs.compare (lhs) != 0); } template <class charT, class traits, class Allocator> inline bool operator!= (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs) { return (lhs.compare (rhs) != 0); } template <class charT, class traits, class Allocator> inline bool operator< (const basic_string <charT, traits, Allocator>& lhs, const basic_string <charT, traits, Allocator>& rhs) { return (lhs.compare (rhs) < 0); } template <class charT, class traits, class Allocator> inline bool operator< (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs) { return (rhs.compare (lhs) > 0); } template <class charT, class traits, class Allocator> inline bool operator< (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs) { return (lhs.compare (rhs) < 0); } template <class charT, class traits, class Allocator> inline bool operator> (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs) { return (rhs.compare (lhs) < 0); } template <class charT, class traits, class Allocator> inline bool operator> (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs) { return (lhs.compare (rhs) > 0); } template <class charT, class traits, class Allocator> inline bool operator<= (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs) { return (rhs.compare (lhs) >= 0); } template <class charT, class traits, class Allocator> inline bool operator<= (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs) { return (lhs.compare (rhs) <= 0); } template <class charT, class traits, class Allocator> inline bool operator>= (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs) { return (rhs.compare (lhs) <= 0); } template <class charT, class traits, class Allocator> inline bool operator>= (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs) { return (lhs.compare (rhs) >= 0); } template <class charT, class traits, class Allocator> inline bool operator!= (const basic_string <charT, traits, Allocator>& lhs, const basic_string <charT, traits, Allocator>& rhs) { return (lhs.compare (rhs) != 0); } template <class charT, class traits, class Allocator> inline bool operator> (const basic_string <charT, traits, Allocator>& lhs, const basic_string <charT, traits, Allocator>& rhs) { return (lhs.compare (rhs) > 0); } template <class charT, class traits, class Allocator> inline bool operator<= (const basic_string <charT, traits, Allocator>& lhs, const basic_string <charT, traits, Allocator>& rhs) { return (lhs.compare (rhs) <= 0); } template <class charT, class traits, class Allocator> inline bool operator>= (const basic_string <charT, traits, Allocator>& lhs, const basic_string <charT, traits, Allocator>& rhs) { return (lhs.compare (rhs) >= 0); } class istream; class ostream; template <class charT, class traits, class Allocator> istream& operator>> (istream&, basic_string <charT, traits, Allocator>&); template <class charT, class traits, class Allocator> ostream& operator<< (ostream&, const basic_string <charT, traits, Allocator>&); template <class charT, class traits, class Allocator> istream& getline (istream&, basic_string <charT, traits, Allocator>&, charT delim = '\n'); } // extern "C++" #include <std/bastring.cc> #endif
base_string的源文件
extern "C++" { template <class charT, class traits, class Allocator> inline void * basic_string <charT, traits, Allocator>::Rep:: operator new (size_t s, size_t extra) {//分配内存 Rep的大小 + string的字符 return Allocator::allocate(s + extra * sizeof (charT)); } template <class charT, class traits, class Allocator> inline void basic_string <charT, traits, Allocator>::Rep:: operator delete (void * ptr) {//归还上面分配的内存 Allocator::deallocate(ptr, sizeof(Rep) + reinterpret_cast<Rep *>(ptr)->res * sizeof (charT)); } template <class charT, class traits, class Allocator> inline size_t basic_string <charT, traits, Allocator>::Rep:: frob_size (size_t s) {//string字符容量分配的大小 size_t i = 16; while (i < s) i *= 2; return i; } template <class charT, class traits, class Allocator> inline basic_string <charT, traits, Allocator>::Rep * basic_string <charT, traits, Allocator>::Rep:: create (size_t extra) { extra = frob_size (extra + 1); Rep *p = new (extra) Rep;//调用上面的operator new p->res = extra;//初始化,len会在new (extra) Rep调用Rep的构造函数是初始化为0 p->ref = 1; p->selfish = false; return p; } template <class charT, class traits, class Allocator> charT * basic_string <charT, traits, Allocator>::Rep:: clone () { Rep *p = Rep::create (len); p->copy (0, data (), len); p->len = len; return p->data (); } template <class charT, class traits, class Allocator> inline bool basic_string <charT, traits, Allocator>::Rep:: excess_slop (size_t s, size_t r) { return 2 * (s <= 16 ? 16 : s) < r; } template <class charT, class traits, class Allocator> inline bool basic_string <charT, traits, Allocator>:: check_realloc (basic_string::size_type s) const { s += sizeof (charT); rep ()->selfish = false; return (rep ()->ref > 1//ref大于1 || s > capacity ()//新的分配的字符内存大于容量 || Rep::excess_slop (s, capacity ()));//新分配的字符内存*2还小于容量(用于减小多余的内存) }//重新分配内存的三个条件 template <class charT, class traits, class Allocator> void basic_string <charT, traits, Allocator>:: alloc (basic_string::size_type size, bool save) { if (! check_realloc (size)) return; Rep *p = Rep::create (size); if (save) { p->copy (0, data (), length ()); p->len = length (); } else p->len = 0; repup (p); } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>& basic_string <charT, traits, Allocator>:: replace (size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2) { const size_t len2 = str.length (); if (pos1 == 0 && n1 >= length () && pos2 == 0 && n2 >= len2) return operator= (str);//正好满足operator= 的条件 OUTOFRANGE (pos2 > len2); if (n2 > len2 - pos2) n2 = len2 - pos2; return replace (pos1, n1, str.data () + pos2, n2); } template <class charT, class traits, class Allocator> inline void basic_string <charT, traits, Allocator>::Rep:: copy (size_t pos, const charT *s, size_t n) { if (n) traits::copy (data () + pos, s, n); } template <class charT, class traits, class Allocator> inline void basic_string <charT, traits, Allocator>::Rep:: move (size_t pos, const charT *s, size_t n) { if (n) traits::move (data () + pos, s, n); } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>& basic_string <charT, traits, Allocator>:: replace (size_type pos, size_type n1, const charT* s, size_type n2) { const size_type len = length (); OUTOFRANGE (pos > len); if (n1 > len - pos) n1 = len - pos; LENGTHERROR (len - n1 > max_size () - n2); size_t newlen = len - n1 + n2; if (check_realloc (newlen)) { Rep *p = Rep::create (newlen); p->copy (0, data (), pos); p->copy (pos + n2, data () + pos + n1, len - (pos + n1)); p->copy (pos, s, n2); repup (p); } else { rep ()->move (pos + n2, data () + pos + n1, len - (pos + n1)); rep ()->copy (pos, s, n2); } rep ()->len = newlen; return *this; } template <class charT, class traits, class Allocator> inline void basic_string <charT, traits, Allocator>::Rep:: set (size_t pos, const charT c, size_t n) { traits::set (data () + pos, c, n); } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>& basic_string <charT, traits, Allocator>:: replace (size_type pos, size_type n1, size_type n2, charT c) { const size_t len = length (); OUTOFRANGE (pos > len); if (n1 > len - pos) n1 = len - pos; LENGTHERROR (len - n1 > max_size () - n2); size_t newlen = len - n1 + n2; if (check_realloc (newlen)) { Rep *p = Rep::create (newlen); p->copy (0, data (), pos); p->copy (pos + n2, data () + pos + n1, len - (pos + n1)); p->set (pos, c, n2); repup (p); } else { rep ()->move (pos + n2, data () + pos + n1, len - (pos + n1)); rep ()->set (pos, c, n2); } rep ()->len = newlen; return *this; } template <class charT, class traits, class Allocator> void basic_string <charT, traits, Allocator>:: resize (size_type n, charT c) { LENGTHERROR (n > max_size ()); if (n > length ()) append (n - length (), c); else erase (n); } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>::size_type basic_string <charT, traits, Allocator>:: copy (charT* s, size_type n, size_type pos) const { OUTOFRANGE (pos > length ()); if (n > length () - pos) n = length () - pos; traits::copy (s, data () + pos, n); return n; } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>::size_type basic_string <charT, traits, Allocator>:: find (const charT* s, size_type pos, size_type n) const { size_t xpos = pos; for (; xpos + n <= length (); ++xpos) if (traits::eq (data () [xpos], *s) && traits::compare (data () + xpos, s, n) == 0) return xpos; return npos; } template <class charT, class traits, class Allocator> inline basic_string <charT, traits, Allocator>::size_type basic_string <charT, traits, Allocator>:: _find (const charT* ptr, charT c, size_type xpos, size_type len) { for (; xpos < len; ++xpos) if (traits::eq (ptr [xpos], c)) return xpos; return npos; } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>::size_type basic_string <charT, traits, Allocator>:: find (charT c, size_type pos) const { return _find (data (), c, pos, length ()); } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>::size_type basic_string <charT, traits, Allocator>:: rfind (const charT* s, size_type pos, size_type n) const { if (n > length ()) return npos; size_t xpos = length () - n; if (xpos > pos) xpos = pos; for (++xpos; xpos-- > 0; ) if (traits::eq (data () [xpos], *s) && traits::compare (data () + xpos, s, n) == 0) return xpos; return npos; } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>::size_type basic_string <charT, traits, Allocator>:: rfind (charT c, size_type pos) const { if (1 > length ()) return npos; size_t xpos = length () - 1; if (xpos > pos) xpos = pos; for (++xpos; xpos-- > 0; ) if (traits::eq (data () [xpos], c)) return xpos; return npos; } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>::size_type basic_string <charT, traits, Allocator>:: find_first_of (const charT* s, size_type pos, size_type n) const { size_t xpos = pos; for (; xpos < length (); ++xpos) if (_find (s, data () [xpos], 0, n) != npos) return xpos; return npos; } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>::size_type basic_string <charT, traits, Allocator>:: find_last_of (const charT* s, size_type pos, size_type n) const { if (length() == 0) return npos; size_t xpos = length () - 1; if (xpos > pos) xpos = pos; for (++xpos; xpos-- > 0;) if (_find (s, data () [xpos], 0, n) != npos) return xpos; return npos; } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>::size_type basic_string <charT, traits, Allocator>:: find_first_not_of (const charT* s, size_type pos, size_type n) const { size_t xpos = pos; for (; xpos < length (); ++xpos) if (_find (s, data () [xpos], 0, n) == npos) return xpos; return npos; } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>::size_type basic_string <charT, traits, Allocator>:: find_first_not_of (charT c, size_type pos) const { size_t xpos = pos; for (; xpos < length (); ++xpos) if (traits::ne (data () [xpos], c)) return xpos; return npos; } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>::size_type basic_string <charT, traits, Allocator>:: find_last_not_of (const charT* s, size_type pos, size_type n) const { if (length() == 0) return npos; size_t xpos = length () - 1; if (xpos > pos) xpos = pos; for (++xpos; xpos-- > 0;) if (_find (s, data () [xpos], 0, n) == npos) return xpos; return npos; } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>::size_type basic_string <charT, traits, Allocator>:: find_last_not_of (charT c, size_type pos) const { if (length() == 0) return npos; size_t xpos = length () - 1; if (xpos > pos) xpos = pos; for (++xpos; xpos-- > 0;) if (traits::ne (data () [xpos], c)) return xpos; return npos; } template <class charT, class traits, class Allocator> int basic_string <charT, traits, Allocator>:: compare (const basic_string& str, size_type pos, size_type n) const { OUTOFRANGE (pos > length ()); size_t rlen = length () - pos; if (rlen > n) rlen = n; if (rlen > str.length ()) rlen = str.length (); int r = traits::compare (data () + pos, str.data (), rlen); if (r != 0) return r; if (rlen == n) return 0; return (length () - pos) - str.length (); } template <class charT, class traits, class Allocator> int basic_string <charT, traits, Allocator>:: compare (const charT* s, size_type pos, size_type n) const { OUTOFRANGE (pos > length ()); size_t rlen = length () - pos; if (rlen > n) rlen = n; int r = traits::compare (data () + pos, s, rlen); if (r != 0) return r; return (length () - pos) - n; } #include <iostream.h> template <class charT, class traits, class Allocator> istream & operator>> (istream &is, basic_string <charT, traits, Allocator> &s) { int w = is.width (0); if (is.ipfx0 ()) { register streambuf *sb = is.rdbuf (); s.resize (0); while (1) { int ch = sb->sbumpc (); if (ch == EOF) { is.setstate (ios::eofbit); break; } else if (traits::is_del (ch)) { sb->sungetc (); break; } s += ch; if (--w == 1) break; } } is.isfx (); if (s.length () == 0) is.setstate (ios::failbit); return is; } template <class charT, class traits, class Allocator> ostream & operator<< (ostream &o, const basic_string <charT, traits, Allocator>& s) { return o.write (s.data (), s.length ()); } template <class charT, class traits, class Allocator> istream& getline (istream &is, basic_string <charT, traits, Allocator>& s, charT delim) { if (is.ipfx1 ()) { _IO_size_t count = 0; streambuf *sb = is.rdbuf (); s.resize (0); while (1) { int ch = sb->sbumpc (); if (ch == EOF) { is.setstate (count == 0 ? (ios::failbit|ios::eofbit) : ios::eofbit); break; } ++count; if (ch == delim) break; s += ch; if (s.length () == s.npos - 1) { is.setstate (ios::failbit); break; } } } // We need to be friends with istream to do this. // is._gcount = count; is.isfx (); return is; } template <class charT, class traits, class Allocator> basic_string <charT, traits, Allocator>::Rep basic_string<charT, traits, Allocator>::nilRep = { 0, 0, 1, false }; template <class charT, class traits, class Allocator> const basic_string <charT, traits, Allocator>::size_type basic_string <charT, traits, Allocator>::npos; } // extern "C++"