|
NCBI Home IEB Home C++ Toolkit docs C Toolkit source browser C Toolkit source browser (2) |
NCBI C++ Toolkit Cross ReferenceC++/src/util/strbuffer.cpp |
source navigation diff markup identifier search freetext search file search |
1 /* $Id: strbuffer.cpp 171185 2009-09-22 15:43:51Z gouriano $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Eugene Vasilchenko
27 *
28 * File Description:
29 * Input buffer
30 */
31
32 #include <ncbi_pch.hpp>
33 #include <corelib/ncbistre.hpp>
34 #include <corelib/ncbi_limits.hpp>
35 #include <util/strbuffer.hpp>
36 #include <util/bytesrc.hpp>
37 #include <util/error_codes.hpp>
38 #include <algorithm>
39
40
41 #define NCBI_USE_ERRCODE_X Util_Stream
42
43 BEGIN_NCBI_SCOPE
44
45 static const size_t KInitialBufferSize = 4096;
46
47 static inline
48 size_t BiggerBufferSize(size_t size) THROWS1_NONE
49 {
50 return size * 2;
51 }
52
53 CIStreamBuffer::CIStreamBuffer(void)
54 THROWS1((bad_alloc))
55 : m_Error(0), m_BufferPos(0),
56 m_BufferSize(0), m_Buffer(0),
57 m_CurrentPos(0), m_DataEndPos(0),
58 m_Line(1),
59 m_CollectPos(0)
60 {
61 }
62
63 CIStreamBuffer::CIStreamBuffer(const char* buffer, size_t size)
64 : m_Error(0), m_BufferPos(0),
65 m_BufferSize(0), m_Buffer(const_cast<char*>(buffer)),
66 m_CurrentPos(buffer), m_DataEndPos(buffer+size),
67 m_Line(1),
68 m_CollectPos(0)
69 {
70 }
71
72 CIStreamBuffer::~CIStreamBuffer(void)
73 {
74 try {
75 Close();
76 }
77 catch ( exception& exc ) {
78 ERR_POST_X(1, Warning <<
79 "~CIStreamBuffer: exception while closing: " << exc.what());
80 }
81 if ( m_BufferSize ) {
82 delete[] m_Buffer;
83 }
84 }
85
86 void CIStreamBuffer::Open(CByteSourceReader& reader)
87 {
88 Close();
89 if ( !m_BufferSize ) {
90 m_BufferSize = KInitialBufferSize;
91 m_CurrentPos = m_DataEndPos = m_Buffer = new char[m_BufferSize];
92 }
93 m_Input = &reader;
94 m_Error = 0;
95 }
96
97 void CIStreamBuffer::Open(const char* buffer, size_t size)
98 {
99 Close();
100 if ( m_BufferSize ) {
101 delete[] m_Buffer;
102 }
103 m_BufferSize = 0;
104 m_Buffer = const_cast<char*>(buffer);
105 m_CurrentPos = buffer;
106 m_DataEndPos = buffer + size;
107 m_Error = 0;
108 }
109
110 void CIStreamBuffer::Close(void)
111 {
112 if ( m_Input ) {
113 size_t unused = m_DataEndPos - m_CurrentPos;
114 if ( unused ) {
115 m_Input->Pushback(m_CurrentPos, unused);
116 }
117 m_Input.Reset();
118 }
119 m_BufferPos = 0;
120 m_CurrentPos = m_Buffer;
121 m_DataEndPos = m_Buffer;
122 m_Line = 1;
123 m_Error = 0;
124 }
125
126 void CIStreamBuffer::StartSubSource(void)
127 {
128 if ( m_Collector ) {
129 // update current collector data
130 _ASSERT(m_CollectPos);
131 size_t count = m_CurrentPos - m_CollectPos;
132 if ( count )
133 m_Collector->AddChunk(m_CollectPos, count);
134 }
135 m_CollectPos = m_CurrentPos;
136 if ( m_Input ) {
137 m_Collector =
138 m_Input->SubSource(m_DataEndPos - m_CurrentPos, m_Collector);
139 }
140 else {
141 m_Collector =
142 new CMemorySourceCollector(m_Collector);
143 }
144 }
145
146 CRef<CByteSource> CIStreamBuffer::EndSubSource(void)
147 {
148 _ASSERT(m_Collector);
149 _ASSERT(m_CollectPos);
150
151 _ASSERT(m_CollectPos <= m_CurrentPos);
152 size_t count = m_CurrentPos - m_CollectPos;
153 if ( count )
154 m_Collector->AddChunk(m_CollectPos, count);
155
156 CRef<CByteSource> source = m_Collector->GetSource();
157
158 CRef<CSubSourceCollector> parent = m_Collector->GetParentCollector();
159 if ( parent ) {
160 m_Collector = parent;
161 m_CollectPos = m_CurrentPos;
162 }
163 else {
164 m_Collector = null;
165 m_CollectPos = 0;
166 }
167
168 return source;
169 }
170
171 // this method is highly optimized
172 char CIStreamBuffer::SkipSpaces(void)
173 THROWS1((CIOException))
174 {
175 // cache pointers
176 const char* pos = m_CurrentPos;
177 const char* end = m_DataEndPos;
178 // make sure thire is at least one char in buffer
179 if ( pos == end ) {
180 // fill buffer
181 pos = FillBuffer(pos);
182 // cache m_DataEndPos
183 end = m_DataEndPos;
184 }
185 // main cycle
186 // at the beginning:
187 // pos == m_CurrentPos
188 // end == m_DataEndPos
189 // pos < end
190 for (;;) {
191 // we use do{}while() cycle because
192 // condition is true at the beginning ( pos < end )
193 do {
194 // cache current char
195 char c = *pos;
196 if ( c != ' ' ) { // it's not space (' ')
197 // point m_CurrentPos to first non space char
198 m_CurrentPos = pos;
199 // return char value
200 return c;
201 }
202 // skip space char
203 } while ( ++pos < end );
204 // here pos == end == m_DataEndPos
205 // point m_CurrentPos to end of buffer
206 m_CurrentPos = pos;
207 // fill next portion
208 pos = FillBuffer(pos);
209 // cache m_DataEndPos
210 end = m_DataEndPos;
211 }
212 }
213
214 // this method is highly optimized
215 void CIStreamBuffer::FindChar(char c)
216 THROWS1((CIOException))
217 {
218 // cache pointers
219 const char* pos = m_CurrentPos;
220 const char* end = m_DataEndPos;
221 // make sure thire is at least one char in buffer
222 if ( pos == end ) {
223 // fill buffer
224 pos = FillBuffer(pos);
225 // cache m_DataEndPos
226 end = m_DataEndPos;
227 }
228 // main cycle
229 // at the beginning:
230 // pos == m_CurrentPos
231 // end == m_DataEndPos
232 // pos < end
233 for (;;) {
234 const void* found = memchr(pos, c, end - pos);
235 if ( found ) {
236 m_CurrentPos = static_cast<const char*>(found);
237 return;
238 }
239 // point m_CurrentPos to end of buffer
240 m_CurrentPos = end;
241 // fill next portion
242 pos = FillBuffer(end);
243 // cache m_DataEndPos
244 end = m_DataEndPos;
245 }
246 }
247
248 // this method is highly optimized
249 size_t CIStreamBuffer::PeekFindChar(char c, size_t limit)
250 THROWS1((CIOException))
251 {
252 _ASSERT(limit > 0);
253 PeekCharNoEOF(limit - 1);
254 // cache pointers
255 const char* pos = m_CurrentPos;
256 size_t bufferSize = m_DataEndPos - pos;
257 if ( bufferSize != 0 ) {
258 const void* found = memchr(pos, c, min(limit, bufferSize));
259 if ( found )
260 return static_cast<const char*>(found) - pos;
261 }
262 return limit;
263 }
264
265 const char* CIStreamBuffer::FillBuffer(const char* pos, bool noEOF)
266 THROWS1((CIOException, bad_alloc))
267 {
268 _ASSERT(pos >= m_DataEndPos);
269 // remove unused portion of buffer at the beginning
270 _ASSERT(m_CurrentPos >= m_Buffer);
271 if ( m_BufferSize == 0 ) {
272 // buffer is external -> no more data
273 if ( noEOF ) {
274 return pos;
275 }
276 else {
277 m_Error = "end of file";
278 NCBI_THROW(CEofException,eEof,m_Error);
279 }
280 }
281 size_t newPosOffset = pos - m_Buffer;
282 if ( newPosOffset >= m_BufferSize || m_DataEndPos == m_CurrentPos ) {
283 // if new position is out of buffer, or if there is no data left
284 // move pointers to the beginning
285 size_t erase = m_CurrentPos - m_Buffer;
286 if ( erase > 0 ) {
287 const char* newPos = m_CurrentPos - erase;
288 if ( m_Collector ) {
289 _ASSERT(m_CollectPos);
290 size_t count = m_CurrentPos - m_CollectPos;
291 if ( count > 0 )
292 m_Collector->AddChunk(m_CollectPos, count);
293 m_CollectPos = newPos;
294 }
295 size_t copy_count = m_DataEndPos - m_CurrentPos;
296 if ( copy_count )
297 memmove(const_cast<char*>(newPos), m_CurrentPos, copy_count);
298 m_CurrentPos = newPos;
299 m_DataEndPos -= erase;
300 m_BufferPos += CT_OFF_TYPE(erase);
301 pos -= erase;
302 newPosOffset -= erase;
303 }
304 }
305 size_t dataSize = m_DataEndPos - m_Buffer;
306 if ( newPosOffset >= m_BufferSize ) {
307 // reallocate buffer
308 size_t newSize = BiggerBufferSize(m_BufferSize);
309 while ( newPosOffset >= newSize ) {
310 newSize = BiggerBufferSize(newSize);
311 }
312 char* newBuffer = new char[newSize];
313 memcpy(newBuffer, m_Buffer, dataSize);
314 m_CurrentPos = newBuffer + (m_CurrentPos - m_Buffer);
315 if ( m_CollectPos )
316 m_CollectPos = newBuffer + (m_CollectPos - m_Buffer);
317 pos = newBuffer + newPosOffset;
318 m_DataEndPos = newBuffer + dataSize;
319 delete[] m_Buffer;
320 m_Buffer = newBuffer;
321 m_BufferSize = newSize;
322 }
323 size_t load = m_BufferSize - dataSize;
324 while ( load > 0 && pos >= m_DataEndPos ) {
325 if ( !m_Input ) {
326 if ( noEOF ) {
327 return pos;
328 }
329 m_Error = "end of file";
330 NCBI_THROW(CEofException,eEof,m_Error);
331 }
332 size_t count = m_Input->Read(const_cast<char*>(m_DataEndPos), load);
333 if ( count == 0 ) {
334 if ( pos < m_DataEndPos )
335 return pos;
336 if ( m_Input->EndOfData() ) {
337 if ( noEOF ) {
338 // ignore EOF
339 _ASSERT(m_Buffer <= m_CurrentPos);
340 _ASSERT(m_CurrentPos <= pos);
341 _ASSERT(m_DataEndPos <= m_Buffer + m_BufferSize);
342 _ASSERT(!m_CollectPos ||
343 (m_CollectPos>=m_Buffer &&
344 m_CollectPos<=m_CurrentPos));
345 return pos;
346 }
347 m_Error = "end of file";
348 NCBI_THROW(CEofException,eEof,m_Error);
349 }
350 else {
351 m_Error = "read fault";
352 NCBI_THROW(CIOException,eRead,m_Error);
353 }
354 }
355 m_DataEndPos += count;
356 load -= count;
357 }
358 _ASSERT(m_Buffer <= m_CurrentPos);
359 _ASSERT(m_CurrentPos <= pos);
360 _ASSERT(pos < m_DataEndPos);
361 _ASSERT(m_DataEndPos <= m_Buffer + m_BufferSize);
362 _ASSERT(!m_CollectPos ||
363 (m_CollectPos>=m_Buffer && m_CollectPos<=m_CurrentPos));
364 return pos;
365 }
366
367 char CIStreamBuffer::FillBufferNoEOF(const char* pos)
368 {
369 pos = FillBuffer(pos, true);
370 if ( pos >= m_DataEndPos )
371 return 0;
372 else
373 return *pos;
374 }
375
376 bool CIStreamBuffer::TryToFillBuffer(void)
377 {
378 return FillBuffer(m_CurrentPos, true) < m_DataEndPos;
379 }
380
381 void CIStreamBuffer::GetChars(char* buffer, size_t count)
382 THROWS1((CIOException))
383 {
384 // cache pos
385 const char* pos = m_CurrentPos;
386 for ( ;; ) {
387 size_t c = m_DataEndPos - pos;
388 if ( c >= count ) {
389 // all data is already in buffer -> copy it
390 memcpy(buffer, pos, count);
391 m_CurrentPos = pos + count;
392 return;
393 }
394 else {
395 memcpy(buffer, pos, c);
396 buffer += c;
397 count -= c;
398 m_CurrentPos = pos += c;
399 pos = FillBuffer(pos);
400 }
401 }
402 }
403
404 void CIStreamBuffer::GetChars(string& str, size_t count)
405 THROWS1((CIOException))
406 {
407 // cache pos
408 const char* pos = m_CurrentPos;
409 size_t in_buffer = m_DataEndPos - pos;
410 if ( in_buffer >= count ) {
411 // simplest case - plain copy
412 str.assign(pos, count);
413 m_CurrentPos = pos + count;
414 return;
415 }
416 str.reserve(count);
417 str.assign(pos, in_buffer);
418 for ( ;; ) {
419 count -= in_buffer;
420 m_CurrentPos = pos += in_buffer;
421 pos = FillBuffer(pos);
422 in_buffer = m_DataEndPos - pos;
423 if ( in_buffer >= count ) {
424 // all data is already in buffer -> copy it
425 str.append(pos, count);
426 m_CurrentPos = pos + count;
427 return;
428 }
429 str.append(pos, in_buffer);
430 }
431 }
432
433 void CIStreamBuffer::GetChars(size_t count)
434 THROWS1((CIOException))
435 {
436 // cache pos
437 const char* pos = m_CurrentPos;
438 for ( ;; ) {
439 size_t c = m_DataEndPos - pos;
440 if ( c >= count ) {
441 // all data is already in buffer -> skip it
442 m_CurrentPos = pos + count;
443 return;
444 }
445 else {
446 count -= c;
447 m_CurrentPos = pos += c;
448 pos = FillBuffer(pos);
449 }
450 }
451 }
452
453 void CIStreamBuffer::SkipEndOfLine(char lastChar)
454 THROWS1((CIOException))
455 {
456 _ASSERT(lastChar == '\n' || lastChar == '\r');
457 _ASSERT(m_CurrentPos > m_Buffer && m_CurrentPos[-1] == lastChar);
458 m_Line++;
459 char nextChar = PeekCharNoEOF();
460 // lastChar either '\r' or \n'
461 // if nextChar is compliment, skip it
462 if ( (lastChar + nextChar) == ('\r' + '\n') )
463 SkipChar();
464 }
465
466 size_t CIStreamBuffer::ReadLine(char* buff, size_t size)
467 THROWS1((CIOException))
468 {
469 size_t count = 0;
470 try {
471 while ( size > 0 ) {
472 char c = *buff++ = GetChar();
473 count++;
474 size--;
475 switch ( c ) {
476 case '\r':
477 // replace leading '\r' by '\n'
478 buff[-1] = '\n';
479 if ( PeekChar() == '\n' )
480 SkipChar();
481 return count;
482 case '\n':
483 if ( PeekChar() == '\r' )
484 SkipChar();
485 return count;
486 }
487 }
488 return count;
489 }
490 catch ( CEofException& /*ignored*/ ) {
491 return count;
492 }
493 }
494
495 void CIStreamBuffer::BadNumber(void)
496 THROWS1((CUtilException))
497 {
498 m_Error = "bad number";
499 NCBI_THROW_FMT(CUtilException, eWrongData,
500 "bad number in line " << GetLine());
501 }
502
503 void CIStreamBuffer::NumberOverflow(void)
504 THROWS1((CUtilException))
505 {
506 m_Error = "number overflow";
507 NCBI_THROW_FMT(CUtilException, eWrongData,
508 "number overflow in line " << GetLine());
509 }
510
511 void CIStreamBuffer::SetStreamOffset(CNcbiStreampos pos)
512 {
513 SetStreamPos(pos);
514 }
515
516 void CIStreamBuffer::SetStreamPos(CNcbiStreampos pos)
517 {
518 if ( m_Input ) {
519 m_Input->Seekg(pos);
520 m_BufferPos = pos;
521 m_DataEndPos = m_Buffer;
522 m_CurrentPos = m_Buffer;
523 m_Line = 1;
524 }
525 else {
526 if ( pos < 0 || pos > m_DataEndPos - m_Buffer ) {
527 NCBI_THROW(CIOException,eRead,"stream position is out of buffer");
528 }
529 m_BufferPos = pos;
530 m_CurrentPos = m_Buffer + pos;
531 m_Line = 1;
532 }
533 }
534
535 char CIStreamBuffer::SkipWs(void)
536 {
537 char c;
538 while (isspace((unsigned char)(c = GetChar())))
539 ;
540 return c;
541 }
542
543 Int4 CIStreamBuffer::GetInt4(void)
544 THROWS1((CIOException,CUtilException))
545 {
546 bool sign;
547 char c = SkipWs();
548 switch ( c ) {
549 case '-':
550 sign = true;
551 c = GetChar();
552 break;
553 case '+':
554 sign = false;
555 c = GetChar();
556 break;
557 default:
558 sign = false;
559 break;
560 }
561
562 Uint4 n = c - '0';
563 if ( n > 9 )
564 BadNumber();
565
566 // overflow limits
567 const Uint4 kMaxBeforeMul = kMax_I4/10;
568 const Uint1 kMaxLimitAdd = Uint1(kMax_I4%10 + sign);
569
570 for ( ;; ) {
571 Uint1 d = PeekCharNoEOF() - '0';
572 if ( d > 9 )
573 break;
574 SkipChar();
575
576 // check multiplication overflow
577 if ( n > kMaxBeforeMul || n == kMaxBeforeMul && d > kMaxLimitAdd )
578 NumberOverflow();
579
580 n = n * 10 + d;
581 }
582 if ( sign )
583 return -Int4(n);
584 else
585 return n;
586 }
587
588 Uint4 CIStreamBuffer::GetUint4(void)
589 THROWS1((CIOException,CUtilException))
590 {
591 char c = SkipWs();
592 if ( c == '+' )
593 c = GetChar();
594
595 Uint4 n = c - '0';
596 if ( n > 9 )
597 BadNumber();
598
599 // overflow limits
600 const Uint4 kMaxBeforeMul = kMax_UI4/10;
601 const Uint1 kMaxLimitAdd = Uint1(kMax_UI4%10);
602
603 for ( ;; ) {
604 Uint1 d = PeekCharNoEOF() - '0';
605 if ( d > 9 )
606 break;
607 SkipChar();
608
609 // check multiplication overflow
610 if ( n > kMaxBeforeMul || n == kMaxBeforeMul && d > kMaxLimitAdd )
611 NumberOverflow();
612
613 n = n * 10 + d;
614 }
615 return n;
616 }
617
618 Int8 CIStreamBuffer::GetInt8(void)
619 THROWS1((CIOException,CUtilException))
620 {
621 bool sign;
622 char c = SkipWs();
623 switch ( c ) {
624 case '-':
625 sign = true;
626 c = GetChar();
627 break;
628 case '+':
629 sign = false;
630 c = GetChar();
631 break;
632 default:
633 sign = false;
634 break;
635 }
636
637 Uint8 n = c - '0';
638 if ( n > 9 )
639 BadNumber();
640
641 // overflow limits
642 const Uint8 kMaxBeforeMul = kMax_I8/10;
643 const Uint1 kMaxLimitAdd = Uint1(kMax_I8%10 + sign);
644
645 for ( ;; ) {
646 Uint1 d = PeekCharNoEOF() - '0';
647 if ( d > 9 )
648 break;
649 SkipChar();
650
651 // check multiplication overflow
652 if ( n > kMaxBeforeMul || n == kMaxBeforeMul && d > kMaxLimitAdd )
653 NumberOverflow();
654
655 n = n * 10 + d;
656 }
657 if ( sign )
658 return -Int8(n);
659 else
660 return n;
661 }
662
663 Uint8 CIStreamBuffer::GetUint8(void)
664 THROWS1((CIOException))
665 {
666 char c = SkipWs();
667 if ( c == '+' )
668 c = GetChar();
669 Uint1 d = c - '0';
670 if ( d > 9 )
671 BadNumber();
672
673 Uint8 n = d;
674
675 // overflow limits
676 const Uint8 kMaxBeforeMul = kMax_UI8/10;
677
678 for ( ;; ) {
679 d = PeekCharNoEOF() - '0';
680 if ( d > 9 )
681 break;
682 SkipChar();
683
684 // check multiplication overflow
685 if ( n > kMaxBeforeMul )
686 NumberOverflow();
687
688 n = n * 10 + d;
689
690 if ( n < d )
691 NumberOverflow();
692 }
693 return n;
694 }
695
696 COStreamBuffer::COStreamBuffer(CNcbiOstream& out, bool deleteOut)
697 THROWS1((bad_alloc))
698 : m_Output(out), m_DeleteOutput(deleteOut), m_Error(0),
699 m_IndentLevel(0), m_BufferPos(0),
700 m_Buffer(new char[KInitialBufferSize]),
701 m_CurrentPos(m_Buffer),
702 m_BufferEnd(m_Buffer + KInitialBufferSize),
703 m_Line(1), m_LineLength(0),
704 m_BackLimit(0), m_UseIndentation(true)
705 {
706 }
707
708 COStreamBuffer::~COStreamBuffer(void)
709 {
710 try {
711 Close();
712 }
713 catch ( exception& exc ) {
714 ERR_POST_X(2, Warning <<
715 "~COStreamBuffer: exception while closing: " << exc.what());
716 }
717 delete[] m_Buffer;
718 }
719
720 void COStreamBuffer::Close(void)
721 {
722 if ( m_Output ) {
723 FlushBuffer();
724 if ( m_DeleteOutput ) {
725 Flush();
726 delete &m_Output;
727 m_DeleteOutput = false;
728 }
729 }
730 m_Error = 0;
731 m_IndentLevel = 0;
732 m_CurrentPos = m_Buffer;
733 m_Line = 1;
734 m_LineLength = 0;
735 }
736
737 void COStreamBuffer::FlushBuffer(bool fullBuffer)
738 THROWS1((CIOException))
739 {
740 size_t used = GetUsedSpace();
741 size_t count;
742 size_t leave;
743 if ( fullBuffer ) {
744 count = used;
745 leave = 0;
746 }
747 else {
748 leave = m_BackLimit;
749 if ( used < leave )
750 return; // none to flush
751 count = used - leave;
752 }
753 if ( count != 0 ) {
754 if ( !m_Output.write(m_Buffer, count) ) {
755 m_Error = "write fault";
756 NCBI_THROW(CIOException,eWrite,m_Error);
757 }
758 if ( leave != 0 ) {
759 memmove(m_Buffer, m_Buffer + count, leave);
760 m_CurrentPos -= count;
761 }
762 else {
763 m_CurrentPos = m_Buffer;
764 }
765 m_BufferPos += CT_OFF_TYPE(count);
766 }
767 }
768
769
770 void COStreamBuffer::Flush(void)
771 THROWS1((CIOException))
772 {
773 FlushBuffer();
774 IOS_BASE::iostate state = m_Output.rdstate();
775 m_Output.clear();
776 try {
777 if ( !m_Output.flush() ) {
778 NCBI_THROW(CIOException,eFlush,"COStreamBuffer::Flush: failed");
779 }
780 }
781 catch (...) {
782 m_Output.clear(state);
783 throw;
784 }
785 m_Output.clear(state);
786 }
787
788
789 char* COStreamBuffer::DoReserve(size_t count)
790 THROWS1((CIOException, bad_alloc))
791 {
792 FlushBuffer(false);
793 size_t usedSize = m_CurrentPos - m_Buffer;
794 size_t needSize = usedSize + count;
795 size_t bufferSize = m_BufferEnd - m_Buffer;
796 if ( bufferSize < needSize ) {
797 // realloc too small buffer
798 do {
799 bufferSize = BiggerBufferSize(bufferSize);
800 } while ( bufferSize < needSize );
801 if ( usedSize == 0 ) {
802 delete[] m_Buffer;
803 m_CurrentPos = m_Buffer = new char[bufferSize];
804 m_BufferEnd = m_Buffer + bufferSize;
805 }
806 else {
807 char* oldBuffer = m_Buffer;
808 m_Buffer = new char[bufferSize];
809 m_BufferEnd = m_Buffer + bufferSize;
810 memcpy(m_Buffer, oldBuffer, usedSize);
811 delete[] oldBuffer;
812 m_CurrentPos = m_Buffer + usedSize;
813 }
814 }
815 return m_CurrentPos;
816 }
817
818 void COStreamBuffer::PutInt4(Int4 v)
819 THROWS1((CIOException, bad_alloc))
820 {
821 const size_t BSIZE = (sizeof(v)*CHAR_BIT) / 3 + 2;
822 char b[BSIZE];
823 Int4 n = v;
824 if ( n < 0 ) {
825 n = -n;
826 }
827 char* pos = b + BSIZE;
828 do {
829 Int4 a = '0'+n;
830 *--pos = a-10*(n/=Uint4(10));
831 } while ( n );
832 if ( v < 0 ) {
833 *--pos = '-';
834 }
835 int len = b + BSIZE - pos;
836 char* dst = Skip(len);
837 for ( int i = 0; i < len; ++i ) {
838 dst[i] = pos[i];
839 }
840 }
841
842 void COStreamBuffer::PutUint4(Uint4 v)
843 THROWS1((CIOException, bad_alloc))
844 {
845 const size_t BSIZE = (sizeof(v)*CHAR_BIT) / 3 + 2;
846 char b[BSIZE];
847 Uint4 n = v;
848 char* pos = b + BSIZE;
849 do {
850 Uint4 a = '0'+n;
851 *--pos = a-10*(n/=Uint4(10));
852 } while ( n );
853 int len = b + BSIZE - pos;
854 char* dst = Skip(len);
855 for ( int i = 0; i < len; ++i ) {
856 dst[i] = pos[i];
857 }
858 }
859
860 // On some platforms division of Int8 is very slow,
861 // so will try to optimize it working with chunks.
862 // Works only for radix base == 10.
863
864 #define PRINT_INT8_CHUNK 1000000000
865 #define PRINT_INT8_CHUNK_SIZE 9
866
867 void COStreamBuffer::PutInt8(Int8 v)
868 THROWS1((CIOException, bad_alloc))
869 {
870 const size_t BSIZE = (sizeof(v)*CHAR_BIT) / 3 + 2;
871 char b[BSIZE];
872 Int8 n = v;
873 if ( n < 0 ) {
874 n = -n;
875 }
876 char* pos = b + BSIZE;
877 #ifdef PRINT_INT8_CHUNK
878 // while n doesn't fit in Int4 process it by 9-digit chunks with 32 bits
879 while ( n & ~Uint8(Uint4(~0)) ) {
880 Uint4 m = Uint4(n);
881 m -= PRINT_INT8_CHUNK*Uint4(n/=Uint8(PRINT_INT8_CHUNK));
882 char* end = pos - PRINT_INT8_CHUNK_SIZE;
883 do {
884 Uint4 a = '0'+m;
885 *--pos = a-10*(m/=10);
886 } while ( pos != end );
887 }
888 // process all remaining digits in 32-bit number
889 Uint4 m = Uint4(n);
890 do {
891 Uint4 a = '0'+m;
892 *--pos = a-10*(m/=10);
893 } while ( m );
894 #else
895 do {
896 Uint8 a = '0'+n;
897 *--pos = char(a-10*(n/=Uint8(10)));
898 } while ( n );
899 #endif
900 if ( v < 0 ) {
901 *--pos = '-';
902 }
903 int len = b + BSIZE - pos;
904 char* dst = Skip(len);
905 for ( int i = 0; i < len; ++i ) {
906 dst[i] = pos[i];
907 }
908 }
909
910 void COStreamBuffer::PutUint8(Uint8 v)
911 THROWS1((CIOException, bad_alloc))
912 {
913 const size_t BSIZE = (sizeof(v)*CHAR_BIT) / 3 + 2;
914 char b[BSIZE];
915 Uint8 n = v;
916 char* pos = b + BSIZE;
917 #ifdef PRINT_INT8_CHUNK
918 // while n doesn't fit in Uint4 process it by 9-digit chunks with 32 bits
919 while ( n & ~Uint8(Uint4(~0)) ) {
920 Uint4 m = Uint4(n);
921 m -= PRINT_INT8_CHUNK*Uint4(n/=Uint8(PRINT_INT8_CHUNK));
922 char* end = pos - PRINT_INT8_CHUNK_SIZE;
923 do {
924 Uint4 a = '0'+m;
925 *--pos = a-10*(m/=10);
926 } while ( pos != end );
927 }
928 // process all remaining digits in 32-bit number
929 Uint4 m = Uint4(n);
930 do {
931 Uint4 a = '0'+m;
932 *--pos = a-10*(m/=10);
933 } while ( m );
934 #else
935 do {
936 Uint8 a = '0'+n;
937 *--pos = char(a-10*(n/=10));
938 } while ( n );
939 #endif
940 int len = b + BSIZE - pos;
941 char* dst = Skip(len);
942 for ( int i = 0; i < len; ++i ) {
943 dst[i] = pos[i];
944 }
945 }
946
947 void COStreamBuffer::PutEolAtWordEnd(size_t lineLength)
948 THROWS1((CIOException, bad_alloc))
949 {
950 Reserve(1);
951 size_t linePos = m_LineLength;
952 char* pos = m_CurrentPos;
953 bool goodPlace = false;
954 while ( pos > m_Buffer && linePos > 0 ) {
955 --pos;
956 --linePos;
957 if ( linePos <= lineLength && (isspace((unsigned char) (*pos)) ||
958 *pos == '\'') ) {
959 goodPlace = true;
960 break;
961 }
962 else if ( *pos == '\n' || *pos == '"' ) {
963 // no suitable space found
964 break;
965 }
966 }
967
968 // Prevent insertion of more than one '\n'
969 if (pos > m_Buffer && *(pos-1) == '\n') {
970 goodPlace = false;
971 }
972
973 if ( !goodPlace ) {
974 // no suitable space found
975 if ( linePos < lineLength ) {
976 pos += lineLength - linePos;
977 linePos = lineLength;
978 }
979 // assure we will not break double ""
980 while ( pos > m_Buffer && *(pos - 1) == '"' ) {
981 --pos;
982 --linePos;
983 }
984 if ( pos == m_Buffer ) {
985 // it's possible that we already put some " before...
986 while ( pos < m_CurrentPos && *pos == '"' ) {
987 ++pos;
988 ++linePos;
989 }
990 }
991 }
992 // split there
993 // insert '\n'
994 size_t count = m_CurrentPos - pos;
995 memmove(pos + 1, pos, count);
996 m_LineLength = count;
997 ++m_CurrentPos;
998 *pos = '\n';
999 ++m_Line;
1000 }
1001
1002 void COStreamBuffer::Write(const char* data, size_t dataLength)
1003 THROWS1((CIOException, bad_alloc))
1004 {
1005 while ( dataLength > 0 ) {
1006 size_t available = GetAvailableSpace();
1007 if ( available == 0 ) {
1008 FlushBuffer(false);
1009 available = GetAvailableSpace();
1010 }
1011 if ( available >= dataLength )
1012 break; // current chunk will fit in buffer
1013 memcpy(m_CurrentPos, data, available);
1014 m_CurrentPos += available;
1015 data += available;
1016 dataLength -= available;
1017 }
1018 memcpy(m_CurrentPos, data, dataLength);
1019 m_CurrentPos += dataLength;
1020 }
1021
1022 void COStreamBuffer::Write(CByteSourceReader& reader)
1023 THROWS1((CIOException, bad_alloc))
1024 {
1025 for ( ;; ) {
1026 size_t available = GetAvailableSpace();
1027 if ( available == 0 ) {
1028 FlushBuffer(false);
1029 available = GetAvailableSpace();
1030 }
1031 size_t count = reader.Read(m_CurrentPos, available);
1032 if ( count == 0 ) {
1033 if ( reader.EndOfData() )
1034 return;
1035 else
1036 NCBI_THROW(CIOException,eRead,"buffer read fault");
1037 }
1038 m_CurrentPos += count;
1039 }
1040 }
1041
1042 END_NCBI_SCOPE
1043 |
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more information. |