1 // ---------------------------------------------------------------------------- 2 // alt_sstream_impl.hpp : alternative stringstream, templates implementation 3 // ---------------------------------------------------------------------------- 4 5 // Copyright Samuel Krempp 2003. Use, modification, and distribution are 6 // subject to the Boost Software License, Version 1.0. (See accompanying 7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 9 // See http://www.boost.org/libs/format for library home page 10 11 // ---------------------------------------------------------------------------- 12 13 #ifndef BOOST_SK_ALT_SSTREAM_IMPL_HPP 14 #define BOOST_SK_ALT_SSTREAM_IMPL_HPP 15 16 namespace boost { 17 namespace io { 18 // --- Implementation ------------------------------------------------------// 19 20 template<class Ch, class Tr, class Alloc> 21 void basic_altstringbuf<Ch, Tr, Alloc>:: clear_buffer()22 clear_buffer () { 23 const Ch * p = pptr(); 24 const Ch * b = pbase(); 25 if(p != NULL && p != b) { 26 seekpos(0, ::std::ios_base::out); 27 } 28 p = gptr(); 29 b = eback(); 30 if(p != NULL && p != b) { 31 seekpos(0, ::std::ios_base::in); 32 } 33 } 34 35 template<class Ch, class Tr, class Alloc> 36 void basic_altstringbuf<Ch, Tr, Alloc>:: str(const string_type & s)37 str (const string_type& s) { 38 size_type sz=s.size(); 39 if(sz != 0 && mode_ & (::std::ios_base::in | ::std::ios_base::out) ) { 40 #ifdef _RWSTD_NO_CLASS_PARTIAL_SPEC 41 void *vd_ptr = alloc_.allocate(sz, is_allocated_? eback() : 0); 42 Ch *new_ptr = static_cast<Ch *>(vd_ptr); 43 #else 44 Ch *new_ptr = alloc_.allocate(sz, is_allocated_? eback() : 0); 45 #endif 46 // if this didnt throw, we're safe, update the buffer 47 dealloc(); 48 sz = s.copy(new_ptr, sz); 49 putend_ = new_ptr + sz; 50 if(mode_ & ::std::ios_base::in) 51 streambuf_t::setg(new_ptr, new_ptr, new_ptr + sz); 52 if(mode_ & ::std::ios_base::out) { 53 streambuf_t::setp(new_ptr, new_ptr + sz); 54 if(mode_ & (::std::ios_base::app | ::std::ios_base::ate)) 55 streambuf_t::pbump(static_cast<int>(sz)); 56 if(gptr() == NULL) 57 streambuf_t::setg(new_ptr, NULL, new_ptr); 58 } 59 is_allocated_ = true; 60 } 61 else 62 dealloc(); 63 } 64 template<class Ch, class Tr, class Alloc> 65 Ch* basic_altstringbuf<Ch, Tr, Alloc>:: 66 begin () const { 67 if(mode_ & ::std::ios_base::out && pptr() != NULL) 68 return pbase(); 69 else if(mode_ & ::std::ios_base::in && gptr() != NULL) 70 return eback(); 71 return NULL; 72 } 73 74 template<class Ch, class Tr, class Alloc> 75 typename std::basic_string<Ch,Tr,Alloc>::size_type 76 basic_altstringbuf<Ch, Tr, Alloc>:: size() const77 size () const { 78 if(mode_ & ::std::ios_base::out && pptr()) 79 return static_cast<size_type>(pend() - pbase()); 80 else if(mode_ & ::std::ios_base::in && gptr()) 81 return static_cast<size_type>(egptr() - eback()); 82 else 83 return 0; 84 } 85 86 template<class Ch, class Tr, class Alloc> 87 typename std::basic_string<Ch,Tr,Alloc>::size_type 88 basic_altstringbuf<Ch, Tr, Alloc>:: cur_size() const89 cur_size () const { 90 if(mode_ & ::std::ios_base::out && pptr()) 91 return static_cast<streamsize>( pptr() - pbase()); 92 else if(mode_ & ::std::ios_base::in && gptr()) 93 return static_cast<streamsize>( gptr() - eback()); 94 else 95 return 0; 96 } 97 98 template<class Ch, class Tr, class Alloc> 99 typename basic_altstringbuf<Ch, Tr, Alloc>::pos_type 100 basic_altstringbuf<Ch, Tr, Alloc>:: seekoff(off_type off,::std::ios_base::seekdir way,::std::ios_base::openmode which)101 seekoff (off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which) { 102 if(pptr() != NULL && putend_ < pptr()) 103 putend_ = pptr(); 104 if(which & ::std::ios_base::in && gptr() != NULL) { 105 // get area 106 if(way == ::std::ios_base::end) 107 off += static_cast<off_type>(putend_ - gptr()); 108 else if(way == ::std::ios_base::beg) 109 off += static_cast<off_type>(eback() - gptr()); 110 else if(way != ::std::ios_base::cur || (which & ::std::ios_base::out) ) 111 // (altering in&out is only supported if way is beg or end, not cur) 112 return pos_type(off_type(-1)); 113 if(eback() <= off+gptr() && off+gptr() <= putend_ ) { 114 // set gptr 115 streambuf_t::gbump(static_cast<int>(off)); 116 if(which & ::std::ios_base::out && pptr() != NULL) 117 // update pptr to match gptr 118 streambuf_t::pbump(static_cast<int>(gptr()-pptr())); 119 } 120 else 121 off = off_type(-1); 122 } 123 else if(which & ::std::ios_base::out && pptr() != NULL) { 124 // put area 125 if(way == ::std::ios_base::end) 126 off += static_cast<off_type>(putend_ - pptr()); 127 else if(way == ::std::ios_base::beg) 128 off += static_cast<off_type>(pbase() - pptr()); 129 else if(way != ::std::ios_base::beg) 130 return pos_type(off_type(-1)); 131 if(pbase() <= off+pptr() && off+pptr() <= putend_) 132 // set pptr 133 streambuf_t::pbump(static_cast<int>(off)); 134 else 135 off = off_type(-1); 136 } 137 else // neither in nor out 138 off = off_type(-1); 139 return (pos_type(off)); 140 } 141 //- end seekoff(..) 142 143 144 template<class Ch, class Tr, class Alloc> 145 typename basic_altstringbuf<Ch, Tr, Alloc>::pos_type 146 basic_altstringbuf<Ch, Tr, Alloc>:: seekpos(pos_type pos,::std::ios_base::openmode which)147 seekpos (pos_type pos, ::std::ios_base::openmode which) { 148 off_type off = off_type(pos); // operation guaranteed by 27.4.3.2 table 88 149 if(pptr() != NULL && putend_ < pptr()) 150 putend_ = pptr(); 151 if(off != off_type(-1)) { 152 if(which & ::std::ios_base::in && gptr() != NULL) { 153 // get area 154 if(0 <= off && off <= putend_ - eback()) { 155 streambuf_t::gbump(static_cast<int>(eback() - gptr() + off)); 156 if(which & ::std::ios_base::out && pptr() != NULL) { 157 // update pptr to match gptr 158 streambuf_t::pbump(static_cast<int>(gptr()-pptr())); 159 } 160 } 161 else 162 off = off_type(-1); 163 } 164 else if(which & ::std::ios_base::out && pptr() != NULL) { 165 // put area 166 if(0 <= off && off <= putend_ - eback()) 167 streambuf_t::pbump(static_cast<int>(eback() - pptr() + off)); 168 else 169 off = off_type(-1); 170 } 171 else // neither in nor out 172 off = off_type(-1); 173 return (pos_type(off)); 174 } 175 else { 176 BOOST_ASSERT(0); // �27.4.3.2 allows undefined-behaviour here 177 return pos_type(off_type(-1)); 178 } 179 } 180 // -end seekpos(..) 181 182 183 template<class Ch, class Tr, class Alloc> 184 typename basic_altstringbuf<Ch, Tr, Alloc>::int_type 185 basic_altstringbuf<Ch, Tr, Alloc>:: underflow()186 underflow () { 187 if(gptr() == NULL) // no get area -> nothing to get. 188 return (compat_traits_type::eof()); 189 else if(gptr() < egptr()) // ok, in buffer 190 return (compat_traits_type::to_int_type(*gptr())); 191 else if(mode_ & ::std::ios_base::in && pptr() != NULL 192 && (gptr() < pptr() || gptr() < putend_) ) 193 { // expand get area 194 if(putend_ < pptr()) 195 putend_ = pptr(); // remember pptr reached this far 196 streambuf_t::setg(eback(), gptr(), putend_); 197 return (compat_traits_type::to_int_type(*gptr())); 198 } 199 else // couldnt get anything. EOF. 200 return (compat_traits_type::eof()); 201 } 202 // -end underflow(..) 203 204 205 template<class Ch, class Tr, class Alloc> 206 typename basic_altstringbuf<Ch, Tr, Alloc>::int_type 207 basic_altstringbuf<Ch, Tr, Alloc>:: pbackfail(int_type meta)208 pbackfail (int_type meta) { 209 if(gptr() != NULL && (eback() < gptr()) 210 && (mode_ & (::std::ios_base::out) 211 || compat_traits_type::eq_int_type(compat_traits_type::eof(), meta) 212 || compat_traits_type::eq(compat_traits_type::to_char_type(meta), gptr()[-1]) ) ) { 213 streambuf_t::gbump(-1); // back one character 214 if(!compat_traits_type::eq_int_type(compat_traits_type::eof(), meta)) 215 // put-back meta into get area 216 *gptr() = compat_traits_type::to_char_type(meta); 217 return (compat_traits_type::not_eof(meta)); 218 } 219 else 220 return (compat_traits_type::eof()); // failed putback 221 } 222 // -end pbackfail(..) 223 224 225 template<class Ch, class Tr, class Alloc> 226 typename basic_altstringbuf<Ch, Tr, Alloc>::int_type 227 basic_altstringbuf<Ch, Tr, Alloc>:: overflow(int_type meta)228 overflow (int_type meta) { 229 #ifdef BOOST_MSVC 230 #pragma warning(push) 231 #pragma warning(disable:4996) 232 #endif 233 if(compat_traits_type::eq_int_type(compat_traits_type::eof(), meta)) 234 return compat_traits_type::not_eof(meta); // nothing to do 235 else if(pptr() != NULL && pptr() < epptr()) { 236 streambuf_t::sputc(compat_traits_type::to_char_type(meta)); 237 return meta; 238 } 239 else if(! (mode_ & ::std::ios_base::out)) 240 // no write position, and cant make one 241 return compat_traits_type::eof(); 242 else { // make a write position available 243 std::size_t prev_size = pptr() == NULL ? 0 : epptr() - eback(); 244 std::size_t new_size = prev_size; 245 // exponential growth : size *= 1.5 246 std::size_t add_size = new_size / 2; 247 if(add_size < alloc_min) 248 add_size = alloc_min; 249 Ch * newptr = NULL, *oldptr = eback(); 250 251 // make sure adding add_size wont overflow size_t 252 while (0 < add_size && ((std::numeric_limits<std::size_t>::max)() 253 - add_size < new_size) ) 254 add_size /= 2; 255 if(0 < add_size) { 256 new_size += add_size; 257 #ifdef _RWSTD_NO_CLASS_PARTIAL_SPEC 258 void *vdptr = alloc_.allocate(new_size, is_allocated_? oldptr : 0); 259 newptr = static_cast<Ch *>(vdptr); 260 #else 261 newptr = alloc_.allocate(new_size, is_allocated_? oldptr : 0); 262 #endif 263 } 264 265 if(0 < prev_size) 266 compat_traits_type::copy(newptr, oldptr, prev_size); 267 if(is_allocated_) 268 alloc_.deallocate(oldptr, prev_size); 269 is_allocated_=true; 270 271 if(prev_size == 0) { // first allocation 272 putend_ = newptr; 273 streambuf_t::setp(newptr, newptr + new_size); 274 if(mode_ & ::std::ios_base::in) 275 streambuf_t::setg(newptr, newptr, newptr + 1); 276 else 277 streambuf_t::setg(newptr, 0, newptr); 278 } 279 else { // update pointers 280 putend_ = putend_ - oldptr + newptr; 281 int pptr_count = static_cast<int>(pptr()-pbase()); 282 int gptr_count = static_cast<int>(gptr()-eback()); 283 streambuf_t::setp(pbase() - oldptr + newptr, newptr + new_size); 284 streambuf_t::pbump(pptr_count); 285 if(mode_ & ::std::ios_base::in) 286 streambuf_t::setg(newptr, newptr + gptr_count, pptr() + 1); 287 else 288 streambuf_t::setg(newptr, 0, newptr); 289 } 290 streambuf_t::sputc(compat_traits_type::to_char_type(meta)); 291 return meta; 292 } 293 #ifdef BOOST_MSVC 294 #pragma warning(pop) 295 #endif 296 } 297 // -end overflow(..) 298 299 template<class Ch, class Tr, class Alloc> dealloc()300 void basic_altstringbuf<Ch, Tr, Alloc>:: dealloc() { 301 if(is_allocated_) 302 alloc_.deallocate(eback(), (pptr() != NULL ? epptr() : egptr()) - eback()); 303 is_allocated_ = false; 304 streambuf_t::setg(0, 0, 0); 305 streambuf_t::setp(0, 0); 306 putend_ = NULL; 307 } 308 309 }// N.S. io 310 } // N.S. boost 311 312 #endif // include guard 313 314