1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5//
6
7#ifndef _SBUFFER_INL_
8#define _SBUFFER_INL_
9
10#include "sbuffer.h"
11
12#if defined(_MSC_VER)
13#pragma inline_depth (20)
14#endif
15
16#ifdef _MSC_VER
17#pragma warning(push)
18#pragma warning(disable:4702) // Disable bogus unreachable code warning
19#endif // _MSC_VER
20
21inline SBuffer::SBuffer(PreallocFlag flag, void *buffer, COUNT_T size)
22 : m_size(0),
23 m_allocation(NULL),
24 m_flags(0),
25 m_buffer(NULL)
26{
27 CONTRACT_VOID
28 {
29 CONSTRUCTOR_CHECK;
30 PRECONDITION(CheckPointer(buffer));
31 PRECONDITION(CheckSize(size));
32 NOTHROW;
33 GC_NOTRIGGER;
34 SUPPORTS_DAC_HOST_ONLY;
35 }
36 CONTRACT_END;
37
38 m_buffer = UseBuffer((BYTE *) buffer, &size);
39 m_allocation = size;
40
41#ifdef _DEBUG
42 m_revision = 0;
43#endif
44
45 RETURN;
46}
47
48inline SBuffer::SBuffer()
49 : m_size(0),
50 m_allocation(0),
51 m_flags(0),
52 m_buffer(NULL)
53{
54 CONTRACT_VOID
55 {
56 CONSTRUCTOR_CHECK;
57 NOTHROW;
58 GC_NOTRIGGER;
59 }
60 CONTRACT_END;
61
62#ifdef _DEBUG
63 m_revision = 0;
64#endif
65
66 RETURN;
67}
68
69inline SBuffer::SBuffer(COUNT_T size)
70 : m_size(0),
71 m_allocation(0),
72 m_flags(0),
73 m_buffer(NULL)
74{
75 CONTRACT_VOID
76 {;
77 CONSTRUCTOR_CHECK;
78 PRECONDITION(CheckSize(size));
79 THROWS;
80 GC_NOTRIGGER;
81 }
82 CONTRACT_END;
83
84 Resize(size);
85
86#ifdef _DEBUG
87 m_revision = 0;
88#endif
89
90 RETURN;
91}
92
93inline SBuffer::SBuffer(const SBuffer &buffer)
94 : m_size(0),
95 m_allocation(0),
96 m_flags(0),
97 m_buffer(NULL)
98{
99 CONTRACT_VOID
100 {
101 CONSTRUCTOR_CHECK;
102 PRECONDITION(buffer.Check());
103 POSTCONDITION(Equals(buffer));
104 THROWS;
105 GC_NOTRIGGER;
106 }
107 CONTRACT_END;
108
109 Set(buffer);
110
111#ifdef _DEBUG
112 m_revision = 0;
113#endif
114
115 RETURN;
116}
117
118inline SBuffer::SBuffer(const BYTE *buffer, COUNT_T size)
119 : m_size(0),
120 m_allocation(0),
121 m_flags(0),
122 m_buffer(NULL)
123{
124 CONTRACT_VOID
125 {
126 CONSTRUCTOR_CHECK;
127 PRECONDITION(CheckPointer(buffer));
128 PRECONDITION(CheckSize(size));
129 POSTCONDITION(Equals(buffer, size));
130 THROWS;
131 GC_NOTRIGGER;
132 }
133 CONTRACT_END;
134
135 Set(buffer, size);
136
137#ifdef _DEBUG
138 m_revision = 0;
139#endif
140
141 RETURN;
142}
143
144
145inline SBuffer::SBuffer(ImmutableFlag immutable, const BYTE *buffer, COUNT_T size)
146 : m_size(size),
147 m_allocation(size),
148 m_flags(IMMUTABLE),
149 m_buffer(const_cast<BYTE*>(buffer))
150{
151 CONTRACT_VOID
152 {
153 CONSTRUCTOR_CHECK;
154 PRECONDITION(CheckPointer(buffer));
155 PRECONDITION(CheckSize(size));
156 POSTCONDITION(Equals(buffer, size));
157 NOTHROW;
158 GC_NOTRIGGER;
159 SO_TOLERANT;
160 SUPPORTS_DAC_HOST_ONLY;
161 }
162 CONTRACT_END;
163
164#ifdef _DEBUG
165 m_revision = 0;
166#endif
167
168 RETURN;
169}
170
171inline SBuffer::~SBuffer()
172{
173 CONTRACT_VOID
174 {
175 NOTHROW;
176 DESTRUCTOR_CHECK;
177 SO_TOLERANT;
178 GC_NOTRIGGER;
179 SO_TOLERANT;
180 SUPPORTS_DAC_HOST_ONLY;
181 }
182 CONTRACT_END;
183 VALIDATE_BACKOUT_STACK_CONSUMPTION;
184
185 if (IsAllocated())
186 {
187 DeleteBuffer(m_buffer, m_allocation);
188 }
189
190 RETURN;
191}
192
193inline void SBuffer::Set(const SBuffer &buffer)
194{
195 CONTRACT_VOID
196 {
197 INSTANCE_CHECK;
198 PRECONDITION(buffer.Check());
199 POSTCONDITION(Equals(buffer));
200 THROWS;
201 GC_NOTRIGGER;
202 SUPPORTS_DAC_HOST_ONLY;
203 }
204 CONTRACT_END;
205
206 if (buffer.IsImmutable()
207 && (IsImmutable() || m_allocation < buffer.GetSize()))
208 {
209 // Share immutable block rather than reallocate and copy
210 // (Note that we prefer to copy to our buffer if we
211 // don't have to reallocate it.)
212
213 if (IsAllocated())
214 DeleteBuffer(m_buffer, m_allocation);
215
216 m_size = buffer.m_size;
217 m_allocation = buffer.m_allocation;
218 m_buffer = buffer.m_buffer;
219 m_flags = buffer.m_flags;
220
221#if _DEBUG
222 // Increment our revision to invalidate iterators
223 m_revision++;
224#endif
225
226 }
227 else
228 {
229 Resize(buffer.m_size, DONT_PRESERVE);
230 EnsureMutable();
231
232 // PreFix seems to think it can choose m_allocation==0 and buffer.m_size > 0 here.
233 // From the code for Resize and EnsureMutable, this is clearly impossible.
234 PREFIX_ASSUME( (this->m_buffer != NULL) || (buffer.m_size == 0) );
235
236 MoveMemory(m_buffer, buffer.m_buffer, buffer.m_size);
237 }
238
239 RETURN;
240}
241
242inline void SBuffer::Set(const BYTE *buffer, COUNT_T size)
243{
244 CONTRACT_VOID
245 {
246 INSTANCE_CHECK;
247 PRECONDITION(CheckPointer(buffer, size == 0 ? NULL_OK : NULL_NOT_OK));
248 PRECONDITION(CheckSize(size));
249 POSTCONDITION(Equals(buffer, size));
250 THROWS;
251 GC_NOTRIGGER;
252 }
253 CONTRACT_END;
254
255 Resize(size);
256 EnsureMutable();
257
258 // PreFix seems to think it can choose m_allocation==0 and size > 0 here.
259 // From the code for Resize, this is clearly impossible.
260 PREFIX_ASSUME( (this->m_buffer != NULL) || (size == 0) );
261
262 MoveMemory(m_buffer, buffer, size);
263
264 RETURN;
265}
266
267inline void SBuffer::SetImmutable(const BYTE *buffer, COUNT_T size)
268{
269 CONTRACT_VOID
270 {
271 INSTANCE_CHECK;
272 PRECONDITION(CheckPointer(buffer, size == 0 ? NULL_OK : NULL_NOT_OK));
273 PRECONDITION(CheckSize(size));
274 POSTCONDITION(Equals(buffer, size));
275 NOTHROW;
276 GC_NOTRIGGER;
277 SUPPORTS_DAC_HOST_ONLY;
278
279 }
280 CONTRACT_END;
281
282 SBuffer temp(Immutable, buffer, size);
283
284 {
285 // This can't really throw
286 CONTRACT_VIOLATION(ThrowsViolation);
287 Set(temp);
288 }
289
290 RETURN;
291}
292
293inline COUNT_T SBuffer::GetSize() const
294{
295 LIMITED_METHOD_CONTRACT;
296 SUPPORTS_DAC;
297
298 return m_size;
299}
300
301inline void SBuffer::SetSize(COUNT_T size)
302{
303 CONTRACT_VOID
304 {
305 INSTANCE_CHECK;
306 PRECONDITION(CheckSize(size));
307 THROWS;
308 GC_NOTRIGGER;
309 }
310 CONTRACT_END;
311
312 Resize(size);
313
314 RETURN;
315}
316
317inline void SBuffer::MaximizeSize()
318{
319 CONTRACT_VOID
320 {
321 INSTANCE_CHECK;
322 THROWS;
323 GC_NOTRIGGER;
324 }
325 CONTRACT_END;
326
327 if (!IsImmutable())
328 Resize(m_allocation);
329
330 RETURN;
331}
332
333inline COUNT_T SBuffer::GetAllocation() const
334{
335 CONTRACT(COUNT_T)
336 {
337 INSTANCE_CHECK;
338 NOTHROW;
339 GC_NOTRIGGER;
340 SO_TOLERANT;
341 SUPPORTS_DAC;
342 }
343 CONTRACT_END;
344
345 RETURN m_allocation;
346}
347
348inline void SBuffer::Preallocate(COUNT_T allocation) const
349{
350 CONTRACT_VOID
351 {
352 if (allocation) THROWS; else NOTHROW;
353 INSTANCE_CHECK;
354 PRECONDITION(CheckAllocation(allocation));
355 THROWS;
356 GC_NOTRIGGER;
357 SUPPORTS_DAC_HOST_ONLY;
358 }
359 CONTRACT_END;
360
361 if (allocation > m_allocation)
362 const_cast<SBuffer *>(this)->ReallocateBuffer(allocation, PRESERVE);
363
364 RETURN;
365}
366
367inline void SBuffer::Trim() const
368{
369 CONTRACT_VOID
370 {
371 INSTANCE_CHECK;
372 THROWS;
373 GC_NOTRIGGER;
374 }
375 CONTRACT_END;
376
377 if (!IsImmutable())
378 const_cast<SBuffer *>(this)->ReallocateBuffer(m_size, PRESERVE);
379
380 RETURN;
381}
382
383inline void SBuffer::Zero()
384{
385 CONTRACT_VOID
386 {
387 INSTANCE_CHECK;
388 NOTHROW;
389 GC_NOTRIGGER;
390 }
391 CONTRACT_END;
392
393 ZeroMemory(m_buffer, m_size);
394
395 RETURN;
396}
397
398inline void SBuffer::Fill(BYTE value)
399{
400 CONTRACT_VOID
401 {
402 INSTANCE_CHECK;
403 NOTHROW;
404 GC_NOTRIGGER;
405 }
406 CONTRACT_END;
407
408 memset(m_buffer, value, m_size);
409
410 RETURN;
411}
412
413inline void SBuffer::Fill(const Iterator &i, BYTE value, COUNT_T size)
414{
415 CONTRACT_VOID
416 {
417 INSTANCE_CHECK;
418 PRECONDITION(CheckIteratorRange(i, size));
419 NOTHROW;
420 GC_NOTRIGGER;
421 }
422 CONTRACT_END;
423
424 memset(i.m_ptr, value, size);
425
426 RETURN;
427}
428
429inline void SBuffer::Copy(const Iterator &to, const CIterator &from, COUNT_T size)
430{
431 CONTRACT_VOID
432 {
433 INSTANCE_CHECK;
434 PRECONDITION(CheckIteratorRange(to, size));
435 PRECONDITION(CheckIteratorRange(from, size));
436 NOTHROW;
437 GC_NOTRIGGER;
438 }
439 CONTRACT_END;
440
441 DebugDestructBuffer(to.m_ptr, size);
442
443 DebugCopyConstructBuffer(to.m_ptr, from.m_ptr, size);
444
445 RETURN;
446}
447
448inline void SBuffer::Move(const Iterator &to, const CIterator &from, COUNT_T size)
449{
450 CONTRACT_VOID
451 {
452 INSTANCE_CHECK;
453 PRECONDITION(CheckIteratorRange(to, size));
454 PRECONDITION(CheckIteratorRange(from, size));
455 NOTHROW;
456 GC_NOTRIGGER;
457 }
458 CONTRACT_END;
459
460 DebugDestructBuffer(to.m_ptr, size);
461
462 DebugMoveBuffer(to.m_ptr, from.m_ptr, size);
463
464 DebugConstructBuffer(from.m_ptr, size);
465
466 RETURN;
467}
468
469inline void SBuffer::Copy(const Iterator &i, const SBuffer &source)
470{
471 CONTRACT_VOID
472 {
473 INSTANCE_CHECK;
474 PRECONDITION(CheckIteratorRange(i, source.GetSize()));
475 PRECONDITION(source.Check());
476 NOTHROW;
477 GC_NOTRIGGER;
478 }
479 CONTRACT_END;
480
481 DebugDestructBuffer(i.m_ptr, source.m_size);
482
483 DebugCopyConstructBuffer(i.m_ptr, source.m_buffer, source.m_size);
484
485 RETURN;
486}
487
488inline void SBuffer::Copy(const Iterator &i, const void *source, COUNT_T size)
489{
490 CONTRACT_VOID
491 {
492 PRECONDITION(CheckPointer(this));
493 PRECONDITION(CheckSize(size));
494 PRECONDITION(CheckIteratorRange(i, size));
495 PRECONDITION(CheckPointer(source, size == 0 ? NULL_OK : NULL_NOT_OK));
496 NOTHROW;
497 GC_NOTRIGGER;
498 SUPPORTS_DAC;
499 }
500 CONTRACT_END;
501
502 DebugDestructBuffer(i.m_ptr, size);
503
504 DebugCopyConstructBuffer(i.m_ptr, (const BYTE *) source, size);
505
506 RETURN;
507}
508
509inline void SBuffer::Copy(void *dest, const CIterator &i, COUNT_T size)
510{
511 CONTRACT_VOID
512 {
513 PRECONDITION(CheckPointer(this));
514 PRECONDITION(CheckSize(size));
515 PRECONDITION(CheckIteratorRange(i, size));
516 PRECONDITION(CheckPointer(dest, size == 0 ? NULL_OK : NULL_NOT_OK));
517 NOTHROW;
518 GC_NOTRIGGER;
519 }
520 CONTRACT_END;
521
522 memcpy(dest, i.m_ptr, size);
523
524 RETURN;
525}
526
527inline void SBuffer::Insert(const Iterator &i, const SBuffer &source)
528{
529 CONTRACT_VOID
530 {
531 INSTANCE_CHECK;
532 THROWS;
533 PRECONDITION(CheckIteratorRange(i,0));
534 GC_NOTRIGGER;
535 }
536 CONTRACT_END;
537
538 Replace(i, 0, source.GetSize());
539 Copy(i, source, source.GetSize());
540
541 RETURN;
542}
543
544inline void SBuffer::Insert(const Iterator &i, COUNT_T size)
545{
546 CONTRACT_VOID
547 {
548 INSTANCE_CHECK;
549 THROWS;
550 PRECONDITION(CheckIteratorRange(i,0));
551 GC_NOTRIGGER;
552 }
553 CONTRACT_END;
554
555 Replace(i, 0, size);
556
557 RETURN;
558}
559
560inline void SBuffer::Clear()
561{
562 CONTRACT_VOID
563 {
564 INSTANCE_CHECK;
565 THROWS;
566 GC_NOTRIGGER;
567 }
568 CONTRACT_END;
569
570 Delete(Begin(), GetSize());
571
572 RETURN;
573}
574
575inline void SBuffer::Delete(const Iterator &i, COUNT_T size)
576{
577 CONTRACT_VOID
578 {
579 INSTANCE_CHECK;
580 PRECONDITION(CheckIteratorRange(i, size));
581 THROWS;
582 GC_NOTRIGGER;
583 }
584 CONTRACT_END;
585
586 Replace(i, size, 0);
587
588 RETURN;
589}
590
591inline void SBuffer::Replace(const Iterator &i, COUNT_T deleteSize, const SBuffer &insert)
592{
593 CONTRACT_VOID
594 {
595 INSTANCE_CHECK;
596 PRECONDITION(CheckIteratorRange(i, deleteSize));
597 THROWS;
598 GC_NOTRIGGER;
599 }
600 CONTRACT_END;
601
602 Replace(i, deleteSize, insert.GetSize());
603 Copy(i, insert, insert.GetSize());
604
605 RETURN;
606}
607
608inline int SBuffer::Compare(const SBuffer &compare) const
609{
610 CONTRACT(int)
611 {
612 INSTANCE_CHECK;
613 PRECONDITION(compare.Check());
614 POSTCONDITION(RETVAL == -1 || RETVAL == 0 || RETVAL == 1);
615 NOTHROW;
616 GC_NOTRIGGER;
617 }
618 CONTRACT_END;
619
620 RETURN Compare(compare.m_buffer, compare.m_size);
621}
622
623inline int SBuffer::Compare(const BYTE *compare, COUNT_T size) const
624{
625 CONTRACT(int)
626 {
627 INSTANCE_CHECK;
628 PRECONDITION(CheckPointer(compare));
629 PRECONDITION(CheckSize(size));
630 POSTCONDITION(RETVAL == -1 || RETVAL == 0 || RETVAL == 1);
631 NOTHROW;
632 GC_NOTRIGGER;
633 }
634 CONTRACT_END;
635
636 COUNT_T smaller;
637 int equals;
638 int result;
639
640 if (m_size < size)
641 {
642 smaller = m_size;
643 equals = -1;
644 }
645 else if (m_size > size)
646 {
647 smaller = size;
648 equals = 1;
649 }
650 else
651 {
652 smaller = size;
653 equals = 0;
654 }
655
656 result = memcmp(m_buffer, compare, size);
657
658 if (result == 0)
659 RETURN equals;
660 else
661 RETURN result;
662}
663
664inline BOOL SBuffer::Equals(const SBuffer &compare) const
665{
666 CONTRACT(int)
667 {
668 INSTANCE_CHECK;
669 PRECONDITION(compare.Check());
670 NOTHROW;
671 GC_NOTRIGGER;
672 SO_TOLERANT;
673 }
674 CONTRACT_END;
675
676 RETURN Equals(compare.m_buffer, compare.m_size);
677}
678
679inline BOOL SBuffer::Equals(const BYTE *compare, COUNT_T size) const
680{
681 CONTRACT(int)
682 {
683 INSTANCE_CHECK;
684 PRECONDITION(CheckPointer(compare));
685 PRECONDITION(CheckSize(size));
686 NOTHROW;
687 GC_NOTRIGGER;
688 SO_TOLERANT;
689 }
690 CONTRACT_END;
691
692 if (m_size != size)
693 RETURN FALSE;
694 else
695 RETURN (memcmp(m_buffer, compare, size) == 0);
696}
697
698inline BOOL SBuffer::Match(const CIterator &i, const SBuffer &match) const
699{
700 CONTRACT(int)
701 {
702 INSTANCE_CHECK;
703 PRECONDITION(CheckIteratorRange(i));
704 PRECONDITION(match.Check());
705 NOTHROW;
706 GC_NOTRIGGER;
707 }
708 CONTRACT_END;
709
710 RETURN Match(i, match.m_buffer, match.m_size);
711}
712
713inline BOOL SBuffer::Match(const CIterator &i, const BYTE *match, COUNT_T size) const
714{
715 CONTRACT(int)
716 {
717 INSTANCE_CHECK;
718 PRECONDITION(CheckIteratorRange(i));
719 PRECONDITION(CheckPointer(match));
720 PRECONDITION(CheckSize(size));
721 NOTHROW;
722 GC_NOTRIGGER;
723 }
724 CONTRACT_END;
725
726 COUNT_T remaining = (COUNT_T) (m_buffer + m_size - i.m_ptr);
727
728 if (remaining < size)
729 RETURN FALSE;
730
731 RETURN (memcmp(i.m_ptr, match, size) == 0);
732}
733
734//----------------------------------------------------------------------------
735// EnsureMutable
736// Ensures that the buffer is mutable
737//----------------------------------------------------------------------------
738inline void SBuffer::EnsureMutable() const
739{
740 CONTRACT_VOID
741 {
742 PRECONDITION(CheckPointer(this));
743 PRECONDITION(CheckBufferClosed());
744 THROWS;
745 GC_NOTRIGGER;
746 SUPPORTS_DAC_HOST_ONLY;
747 }
748 CONTRACT_END;
749
750 if (IsImmutable())
751 const_cast<SBuffer *>(this)->ReallocateBuffer(m_allocation, PRESERVE);
752
753 RETURN;
754}
755
756//----------------------------------------------------------------------------
757// Resize
758// Change the visible size of the buffer; realloc if necessary
759//----------------------------------------------------------------------------
760FORCEINLINE void SBuffer::Resize(COUNT_T size, Preserve preserve)
761{
762 CONTRACT_VOID
763 {
764 PRECONDITION(CheckPointer(this));
765 PRECONDITION(CheckSize(size));
766 POSTCONDITION(GetSize() == size);
767 POSTCONDITION(m_allocation >= GetSize());
768 POSTCONDITION(CheckInvariant(*this));
769 if (size > 0) THROWS; else NOTHROW;
770 GC_NOTRIGGER;
771 SUPPORTS_DAC_HOST_ONLY;
772 }
773 CONTRACT_END;
774
775#ifdef _DEBUG
776 // Change our revision
777 m_revision++;
778#endif
779
780 SCOUNT_T delta = size - m_size;
781
782 if (delta < 0)
783 DebugDestructBuffer(m_buffer + size, -delta);
784
785 // Only actually allocate if we are growing
786 if (size > m_allocation)
787 ReallocateBuffer(size, preserve);
788
789 if (delta > 0)
790 DebugConstructBuffer(m_buffer + m_size, delta);
791
792 m_size = size;
793
794 RETURN;
795}
796
797//----------------------------------------------------------------------------
798// ResizePadded
799// Change the visible size of the buffer; realloc if necessary
800// add extra space to minimize further growth
801//----------------------------------------------------------------------------
802inline void SBuffer::ResizePadded(COUNT_T size, Preserve preserve)
803{
804 CONTRACT_VOID
805 {
806 PRECONDITION(CheckPointer(this));
807 PRECONDITION(CheckSize(size));
808 POSTCONDITION(GetSize() == size);
809 POSTCONDITION(m_allocation >= GetSize());
810 POSTCONDITION(CheckInvariant(*this));
811 if (size > 0) THROWS; else NOTHROW;
812 GC_NOTRIGGER;
813 SUPPORTS_DAC_HOST_ONLY;
814 }
815 CONTRACT_END;
816
817#ifdef _DEBUG
818 // Change our revision
819 m_revision++;
820#endif
821
822 SCOUNT_T delta = size - m_size;
823
824 if (delta < 0)
825 DebugDestructBuffer(m_buffer + size, -delta);
826
827 // Only actually allocate if we are growing
828 if (size > m_allocation)
829 {
830 COUNT_T padded = (size*3)/2;
831
832 ReallocateBuffer(padded, preserve);
833 }
834
835 if (delta > 0)
836 DebugConstructBuffer(m_buffer + m_size, delta);
837
838 m_size = size;
839
840 RETURN;
841}
842
843//----------------------------------------------------------------------------
844// TweakSize
845// An optimized form of Resize, which can only adjust the size within the
846// currently allocated range, and never reallocates
847//----------------------------------------------------------------------------
848inline void SBuffer::TweakSize(COUNT_T size)
849{
850 CONTRACT_VOID
851 {
852 PRECONDITION(CheckPointer(this));
853 PRECONDITION(CheckSize(size));
854 PRECONDITION(size <= GetAllocation());
855 POSTCONDITION(GetSize() == size);
856 POSTCONDITION(CheckInvariant(*this));
857 NOTHROW;
858 SO_TOLERANT;
859 GC_NOTRIGGER;
860 SUPPORTS_DAC_HOST_ONLY;
861 }
862 CONTRACT_END;
863
864#ifdef _DEBUG
865 // Change our revision
866 m_revision++;
867#endif
868
869 SCOUNT_T delta = size - m_size;
870
871 if (delta < 0)
872 DebugDestructBuffer(m_buffer + size, -delta);
873 else
874 DebugConstructBuffer(m_buffer + m_size, delta);
875
876 m_size = size;
877
878 RETURN;
879}
880
881//-----------------------------------------------------------------------------
882// SBuffer allocates all memory via NewBuffer & DeleteBuffer members.
883// If SBUFFER_CANARY_CHECKS is defined, NewBuffer will place Canaries at the start
884// and end of the buffer to detect overflows.
885//-----------------------------------------------------------------------------
886
887#ifdef _DEBUG
888#define SBUFFER_CANARY_CHECKS 1
889#endif
890
891#ifdef SBUFFER_CANARY_CHECKS
892
893// The value we place at the start/end of the buffer,
894static const UINT64 SBUFFER_CANARY_VALUE = UI64(0xD00BED00BED00BAA);
895
896// Expose the quantity of padding needed when providing a prealloced
897// buffer. This is an unrolled version of the actualAllocation calculated
898// below for use as a constant value for InlineSString<X> to use. It is
899// padded with one additional sizeof(SBUFFER_CANARY_VALUE) to account for
900// possible alignment problems issues (pre- and post-padding).
901#define SBUFFER_PADDED_SIZE(desiredUsefulSize) \
902 ((((SIZE_T)(desiredUsefulSize) + sizeof(SBUFFER_CANARY_VALUE) - 1) & \
903 ~(sizeof(SBUFFER_CANARY_VALUE)-1)) + 3 * sizeof(SBUFFER_CANARY_VALUE))
904
905#else // SBUFFER_CANARY_CHECKS
906
907#define SBUFFER_PADDED_SIZE(desiredUsefulSize) (desiredUsefulSize)
908
909#endif // SBUFFER_CANARY_CHECKS else
910
911// Must match expected guaranteed alignment of new []
912#ifdef ALIGN_ACCESS
913static const int SBUFFER_ALIGNMENT = ALIGN_ACCESS;
914#else
915// This is only 4 bytes on win98 and below
916static const int SBUFFER_ALIGNMENT = 4;
917#endif
918
919//----------------------------------------------------------------------------
920// Allocate memory, use canaries.
921//----------------------------------------------------------------------------
922inline BYTE *SBuffer::NewBuffer(COUNT_T allocation)
923{
924 CONTRACT(BYTE*)
925 {
926 PRECONDITION(CheckSize(allocation));
927 PRECONDITION(allocation > 0);
928 POSTCONDITION(CheckPointer(RETVAL));
929 THROWS;
930 GC_NOTRIGGER;
931 SUPPORTS_DAC_HOST_ONLY;
932 }
933 CONTRACT_END;
934
935#ifdef SBUFFER_CANARY_CHECKS
936
937 COUNT_T alignPadding = AlignmentPad(allocation, sizeof(SBUFFER_CANARY_VALUE));
938 COUNT_T actualAllocation= sizeof(SBUFFER_CANARY_VALUE) + allocation + alignPadding + sizeof(SBUFFER_CANARY_VALUE);
939 BYTE *raw = new BYTE [actualAllocation];
940
941 *(UINT64*) raw = SBUFFER_CANARY_VALUE;
942 *(UINT64*) (raw + sizeof(SBUFFER_CANARY_VALUE) + allocation + alignPadding) = SBUFFER_CANARY_VALUE;
943
944 BYTE *buffer = raw + sizeof(SBUFFER_CANARY_VALUE);
945
946#else
947
948 BYTE *buffer = new BYTE [allocation];
949
950#endif
951
952 DebugStompUnusedBuffer(buffer, allocation);
953
954 CONSISTENCY_CHECK(CheckBuffer(buffer, allocation));
955
956 RETURN buffer;
957}
958
959//----------------------------------------------------------------------------
960// Use existing memory, use canaries.
961//----------------------------------------------------------------------------
962inline BYTE *SBuffer::UseBuffer(BYTE *buffer, COUNT_T *allocation)
963{
964 CONTRACT(BYTE*)
965 {
966 NOTHROW;
967 GC_NOTRIGGER;
968 CANNOT_TAKE_LOCK;
969 SUPPORTS_DAC_HOST_ONLY;
970 PRECONDITION(CheckPointer(buffer));
971 PRECONDITION(CheckSize(*allocation));
972// POSTCONDITION(CheckPointer(RETVAL));
973 POSTCONDITION(CheckSize(*allocation));
974 }
975 CONTRACT_END;
976
977#ifdef SBUFFER_CANARY_CHECKS
978
979 COUNT_T prepad = AlignmentPad((SIZE_T) buffer, sizeof(SBUFFER_CANARY_VALUE));
980 COUNT_T postpad = AlignmentTrim((SIZE_T) buffer+*allocation, sizeof(SBUFFER_CANARY_VALUE));
981
982 SCOUNT_T usableAllocation = *allocation - prepad - sizeof(SBUFFER_CANARY_VALUE) - sizeof(SBUFFER_CANARY_VALUE) - postpad;
983 if (usableAllocation <= 0)
984 {
985 buffer = NULL;
986 *allocation = 0;
987 }
988 else
989 {
990 BYTE *result = buffer + prepad + sizeof(SBUFFER_CANARY_VALUE);
991
992 *(UINT64*) (buffer + prepad) = SBUFFER_CANARY_VALUE;
993 *(UINT64*) (buffer + prepad + sizeof(SBUFFER_CANARY_VALUE) + usableAllocation) = SBUFFER_CANARY_VALUE;
994
995 buffer = result;
996 *allocation = usableAllocation;
997 }
998
999#endif
1000
1001 DebugStompUnusedBuffer(buffer, *allocation);
1002
1003 CONSISTENCY_CHECK(CheckBuffer(buffer, *allocation));
1004
1005 RETURN buffer;
1006}
1007
1008//----------------------------------------------------------------------------
1009// Free memory allocated by NewHelper
1010//----------------------------------------------------------------------------
1011inline void SBuffer::DeleteBuffer(BYTE *buffer, COUNT_T allocation)
1012{
1013 CONTRACT_VOID
1014 {
1015 PRECONDITION(CheckSize(allocation));
1016 POSTCONDITION(CheckPointer(buffer));
1017 SO_TOLERANT;
1018 NOTHROW;
1019 GC_NOTRIGGER;
1020 SO_TOLERANT;
1021 SUPPORTS_DAC_HOST_ONLY;
1022 }
1023 CONTRACT_END;
1024 VALIDATE_BACKOUT_STACK_CONSUMPTION;
1025
1026 CONSISTENCY_CHECK(CheckBuffer(buffer, allocation));
1027
1028#ifdef SBUFFER_CANARY_CHECKS
1029
1030 delete [] (buffer - sizeof(SBUFFER_CANARY_VALUE));
1031
1032#else
1033
1034 delete [] buffer;
1035
1036#endif
1037
1038 RETURN;
1039}
1040
1041//----------------------------------------------------------------------------
1042// Check the buffer at the given address. The memory must have been a pointer
1043// returned by NewHelper.
1044//----------------------------------------------------------------------------
1045inline CHECK SBuffer::CheckBuffer(const BYTE *buffer, COUNT_T allocation) const
1046{
1047 CONTRACT_CHECK
1048 {
1049 NOTHROW;
1050 GC_NOTRIGGER;
1051 SO_TOLERANT;
1052 CANNOT_TAKE_LOCK;
1053 PRECONDITION(CheckPointer(buffer));
1054 }
1055 CONTRACT_CHECK_END;
1056
1057 if (allocation > 0)
1058 {
1059#ifdef SBUFFER_CANARY_CHECKS
1060 const BYTE *raw = buffer - sizeof(SBUFFER_CANARY_VALUE);
1061
1062 COUNT_T alignPadding = ((allocation + (sizeof(SBUFFER_CANARY_VALUE) - 1)) & ~((sizeof(SBUFFER_CANARY_VALUE) - 1))) - allocation;
1063
1064 CHECK_MSG(*(UINT64*) raw == SBUFFER_CANARY_VALUE, "SBuffer underflow");
1065 CHECK_MSG(*(UINT64*) (raw + sizeof(SBUFFER_CANARY_VALUE) + allocation + alignPadding) == SBUFFER_CANARY_VALUE, "SBuffer overflow");
1066
1067#endif
1068
1069 CHECK_MSG((((SIZE_T)buffer) & (SBUFFER_ALIGNMENT-1)) == 0, "SBuffer not properly aligned");
1070 }
1071
1072 CHECK_OK;
1073}
1074
1075
1076inline BYTE *SBuffer::OpenRawBuffer(COUNT_T size)
1077{
1078 CONTRACT(BYTE*)
1079 {
1080#if _DEBUG
1081 PRECONDITION_MSG(!IsOpened(), "Can't nest calls to OpenBuffer()");
1082#endif
1083 PRECONDITION(CheckSize(size));
1084 POSTCONDITION(GetSize() == size);
1085 THROWS;
1086 GC_NOTRIGGER;
1087 }
1088 CONTRACT_END;
1089
1090 Resize(size);
1091 EnsureMutable();
1092
1093#if _DEBUG
1094 SetOpened();
1095#endif
1096
1097 RETURN m_buffer;
1098}
1099
1100//----------------------------------------------------------------------------
1101// Close an open buffer. Assumes that we wrote exactly number of characters
1102// we requested in OpenBuffer.
1103//----------------------------------------------------------------------------
1104inline void SBuffer::CloseRawBuffer()
1105{
1106 CONTRACT_VOID
1107 {
1108#if _DEBUG
1109 PRECONDITION(IsOpened());
1110#endif
1111 THROWS;
1112 GC_NOTRIGGER;
1113 }
1114 CONTRACT_END;
1115
1116 CloseRawBuffer(m_size);
1117
1118 RETURN;
1119}
1120
1121//----------------------------------------------------------------------------
1122// CloseBuffer() tells the SBuffer that we're done using the unsafe buffer.
1123// finalSize is the count of bytes actually used (so we can set m_count).
1124// This is important if we request a buffer larger than what we actually
1125// used.
1126//----------------------------------------------------------------------------
1127inline void SBuffer::CloseRawBuffer(COUNT_T finalSize)
1128{
1129 CONTRACT_VOID
1130 {
1131#if _DEBUG
1132 PRECONDITION_MSG(IsOpened(), "Can only CloseRawBuffer() after a call to OpenRawBuffer()");
1133#endif
1134 PRECONDITION(CheckSize(finalSize));
1135 PRECONDITION_MSG(finalSize <= GetSize(), "Can't use more characters than requested via OpenRawBuffer()");
1136 THROWS;
1137 GC_NOTRIGGER;
1138 }
1139 CONTRACT_END;
1140
1141#if _DEBUG
1142 ClearOpened();
1143#endif
1144
1145 TweakSize(finalSize);
1146
1147 CONSISTENCY_CHECK(CheckBuffer(m_buffer, m_allocation));
1148
1149 RETURN;
1150}
1151
1152inline SBuffer::operator const void *() const
1153{
1154 LIMITED_METHOD_CONTRACT;
1155
1156 return (void *) m_buffer;
1157}
1158
1159inline SBuffer::operator const BYTE *() const
1160{
1161 LIMITED_METHOD_DAC_CONTRACT;
1162
1163 return m_buffer;
1164}
1165
1166inline BYTE &SBuffer::operator[](int index)
1167{
1168 LIMITED_METHOD_CONTRACT;
1169
1170 return m_buffer[index];
1171}
1172
1173inline const BYTE &SBuffer::operator[](int index) const
1174{
1175 LIMITED_METHOD_CONTRACT;
1176
1177 return m_buffer[index];
1178}
1179
1180inline SBuffer::Iterator SBuffer::Begin()
1181{
1182 CONTRACT(SBuffer::Iterator)
1183 {
1184 INSTANCE_CHECK;
1185 THROWS;
1186 GC_NOTRIGGER;
1187 SUPPORTS_DAC_HOST_ONLY;
1188 }
1189 CONTRACT_END;
1190
1191 // This is a bit unfortunate to have to do here, but it's our
1192 // last opportunity before possibly doing a *i= with the iterator
1193 EnsureMutable();
1194
1195 RETURN Iterator(this, 0);
1196}
1197
1198inline SBuffer::Iterator SBuffer::End()
1199{
1200 CONTRACT(SBuffer::Iterator)
1201 {
1202 INSTANCE_CHECK;
1203 THROWS;
1204 GC_NOTRIGGER;
1205 }
1206 CONTRACT_END;
1207
1208 // This is a bit unfortunate to have to do here, but it's our
1209 // last opportunity before possibly doing a *i= with the iterator
1210 EnsureMutable();
1211
1212 RETURN Iterator(this, m_size);
1213}
1214
1215inline SBuffer::CIterator SBuffer::Begin() const
1216{
1217 CONTRACT(SBuffer::CIterator)
1218 {
1219 INSTANCE_CHECK;
1220 NOTHROW;
1221 GC_NOTRIGGER;
1222 }
1223 CONTRACT_END;
1224
1225 RETURN SBuffer::CIterator(this, 0);
1226}
1227
1228inline SBuffer::CIterator SBuffer::End() const
1229{
1230 CONTRACT(SBuffer::CIterator)
1231 {
1232 INSTANCE_CHECK;
1233 NOTHROW;
1234 GC_NOTRIGGER;
1235 }
1236 CONTRACT_END;
1237
1238 RETURN CIterator(const_cast<SBuffer*>(this), m_size);
1239}
1240
1241inline BOOL SBuffer::IsAllocated() const
1242{
1243 LIMITED_METHOD_DAC_CONTRACT;
1244
1245 return (m_flags & ALLOCATED) != 0;
1246}
1247
1248inline void SBuffer::SetAllocated()
1249{
1250 LIMITED_METHOD_CONTRACT;
1251 SUPPORTS_DAC_HOST_ONLY;
1252
1253 m_flags |= ALLOCATED;
1254}
1255
1256inline void SBuffer::ClearAllocated()
1257{
1258 LIMITED_METHOD_CONTRACT;
1259 SUPPORTS_DAC_HOST_ONLY;
1260
1261 m_flags &= ~ALLOCATED;
1262}
1263
1264inline BOOL SBuffer::IsImmutable() const
1265{
1266 LIMITED_METHOD_DAC_CONTRACT;
1267
1268 return (m_flags & IMMUTABLE) != 0;
1269}
1270
1271inline void SBuffer::SetImmutable()
1272{
1273 LIMITED_METHOD_CONTRACT;
1274 SUPPORTS_DAC_HOST_ONLY;
1275
1276 m_flags |= IMMUTABLE;
1277}
1278
1279inline void SBuffer::ClearImmutable()
1280{
1281 LIMITED_METHOD_CONTRACT;
1282 SUPPORTS_DAC_HOST_ONLY;
1283
1284 m_flags &= ~IMMUTABLE;
1285}
1286
1287inline BOOL SBuffer::IsFlag1() const
1288{
1289 LIMITED_METHOD_DAC_CONTRACT;
1290
1291 return (m_flags & FLAG1) != 0;
1292}
1293
1294inline void SBuffer::SetFlag1()
1295{
1296 LIMITED_METHOD_DAC_CONTRACT;
1297
1298 m_flags |= FLAG1;
1299}
1300
1301inline void SBuffer::ClearFlag1()
1302{
1303 LIMITED_METHOD_CONTRACT;
1304
1305 m_flags &= ~FLAG1;
1306}
1307
1308inline BOOL SBuffer::IsFlag2() const
1309{
1310 LIMITED_METHOD_CONTRACT;
1311
1312 return (m_flags & FLAG2) != 0;
1313}
1314
1315inline void SBuffer::SetFlag2()
1316{
1317 LIMITED_METHOD_CONTRACT;
1318
1319 m_flags |= FLAG2;
1320}
1321
1322inline void SBuffer::ClearFlag2()
1323{
1324 LIMITED_METHOD_CONTRACT;
1325
1326 m_flags &= ~FLAG2;
1327}
1328
1329inline BOOL SBuffer::IsFlag3() const
1330{
1331 LIMITED_METHOD_DAC_CONTRACT;
1332
1333 return (m_flags & FLAG3) != 0;
1334}
1335
1336inline void SBuffer::SetFlag3()
1337{
1338 LIMITED_METHOD_CONTRACT;
1339
1340 m_flags |= FLAG3;
1341}
1342
1343inline void SBuffer::ClearFlag3()
1344{
1345 LIMITED_METHOD_DAC_CONTRACT;
1346
1347 m_flags &= ~FLAG3;
1348}
1349
1350inline int SBuffer::GetRepresentationField() const
1351{
1352 LIMITED_METHOD_CONTRACT;
1353 SUPPORTS_DAC;
1354
1355 return (m_flags & REPRESENTATION_MASK);
1356}
1357
1358inline void SBuffer::SetRepresentationField(int value)
1359{
1360 CONTRACT_VOID
1361 {
1362 PRECONDITION((value & ~REPRESENTATION_MASK) == 0);
1363 NOTHROW;
1364 GC_NOTRIGGER;
1365 SO_TOLERANT;
1366 SUPPORTS_DAC_HOST_ONLY;
1367 }
1368 CONTRACT_END;
1369
1370 m_flags &= ~REPRESENTATION_MASK;
1371 m_flags |= value;
1372
1373 RETURN;
1374}
1375
1376#if _DEBUG
1377inline BOOL SBuffer::IsOpened() const
1378{
1379 LIMITED_METHOD_CONTRACT;
1380
1381 return (m_flags & OPENED) != 0;
1382}
1383
1384inline void SBuffer::SetOpened()
1385{
1386 LIMITED_METHOD_CONTRACT;
1387
1388 m_flags |= OPENED;
1389}
1390
1391inline void SBuffer::ClearOpened()
1392{
1393 LIMITED_METHOD_CONTRACT;
1394
1395 m_flags &= ~OPENED;
1396}
1397#endif
1398
1399inline void SBuffer::DebugMoveBuffer(__out_bcount(size) BYTE *to, BYTE *from, COUNT_T size)
1400{
1401 CONTRACT_VOID
1402 {
1403 INSTANCE_CHECK;
1404 PRECONDITION(CheckPointer(to, size == 0 ? NULL_OK : NULL_NOT_OK));
1405 PRECONDITION(CheckPointer(from, size == 0 ? NULL_OK : NULL_NOT_OK));
1406 PRECONDITION(CheckSize(size));
1407 NOTHROW;
1408 GC_NOTRIGGER;
1409 SUPPORTS_DAC_HOST_ONLY;
1410 }
1411 CONTRACT_END;
1412
1413 if (size == 0) // special case
1414 RETURN;
1415
1416 // Handle overlapping ranges
1417 if (to > from && to < from + size)
1418 CONSISTENCY_CHECK(CheckUnusedBuffer(from + size, (COUNT_T) (to - from)));
1419 else if (to < from && to + size > from)
1420 CONSISTENCY_CHECK(CheckUnusedBuffer(to, (COUNT_T) (from - to)));
1421 else
1422 CONSISTENCY_CHECK(CheckUnusedBuffer(to, size));
1423
1424 memmove(to, from, size);
1425
1426 // Handle overlapping ranges
1427 if (to > from && to < from + size)
1428 DebugStompUnusedBuffer(from, (COUNT_T) (to - from));
1429 else if (to < from && to + size > from)
1430 DebugStompUnusedBuffer(to + size, (COUNT_T) (from - to));
1431 else
1432 DebugStompUnusedBuffer(from, size);
1433
1434 RETURN;
1435}
1436
1437inline void SBuffer::DebugCopyConstructBuffer(__out_bcount(size) BYTE *to, const BYTE *from, COUNT_T size)
1438{
1439 CONTRACT_VOID
1440 {
1441 INSTANCE_CHECK;
1442 PRECONDITION(CheckPointer(to, size == 0 ? NULL_OK : NULL_NOT_OK));
1443 PRECONDITION(CheckPointer(from, size == 0 ? NULL_OK : NULL_NOT_OK));
1444 PRECONDITION(CheckSize(size));
1445 NOTHROW;
1446 GC_NOTRIGGER;
1447 SUPPORTS_DAC_HOST_ONLY;
1448 }
1449 CONTRACT_END;
1450
1451 if (size != 0) {
1452 CONSISTENCY_CHECK(CheckUnusedBuffer(to, size));
1453 memmove(to, from, size);
1454 }
1455
1456 RETURN;
1457}
1458
1459inline void SBuffer::DebugConstructBuffer(BYTE *buffer, COUNT_T size)
1460{
1461 CONTRACT_VOID
1462 {
1463 INSTANCE_CHECK;
1464 PRECONDITION(CheckPointer(buffer, size == 0 ? NULL_OK : NULL_NOT_OK));
1465 PRECONDITION(CheckSize(size));
1466 NOTHROW;
1467 GC_NOTRIGGER;
1468 SUPPORTS_DAC;
1469 DEBUG_ONLY;
1470 }
1471 CONTRACT_END;
1472
1473 if (size != 0) {
1474 CONSISTENCY_CHECK(CheckUnusedBuffer(buffer, size));
1475 }
1476
1477 RETURN;
1478}
1479
1480inline void SBuffer::DebugDestructBuffer(BYTE *buffer, COUNT_T size)
1481{
1482 CONTRACT_VOID
1483 {
1484 INSTANCE_CHECK;
1485 PRECONDITION(CheckPointer(buffer, size == 0 ? NULL_OK : NULL_NOT_OK));
1486 PRECONDITION(CheckSize(size));
1487 NOTHROW;
1488 GC_NOTRIGGER;
1489 DEBUG_ONLY;
1490 SUPPORTS_DAC_HOST_ONLY;
1491 }
1492 CONTRACT_END;
1493
1494 if (size != 0)
1495 {
1496 DebugStompUnusedBuffer(buffer, size);
1497 }
1498
1499 RETURN;
1500}
1501
1502static const BYTE GARBAGE_FILL_CHARACTER = '$';
1503
1504extern const DWORD g_garbageFillBuffer[];
1505
1506inline void SBuffer::DebugStompUnusedBuffer(BYTE *buffer, COUNT_T size)
1507{
1508 CONTRACT_VOID
1509 {
1510 INSTANCE_CHECK;
1511 PRECONDITION(CheckPointer(buffer, size == 0 ? NULL_OK : NULL_NOT_OK));
1512 PRECONDITION(CheckSize(size));
1513 NOTHROW;
1514 GC_NOTRIGGER;
1515 CANNOT_TAKE_LOCK;
1516 DEBUG_ONLY;
1517 SUPPORTS_DAC_HOST_ONLY;
1518 }
1519 CONTRACT_END;
1520
1521#if _DEBUG
1522 if (!IsImmutable()
1523 || buffer < m_buffer || buffer > m_buffer + m_allocation) // Allocating a new buffer
1524 {
1525 // Whack the memory
1526 if (size > GARBAGE_FILL_BUFFER_SIZE) size = GARBAGE_FILL_BUFFER_SIZE;
1527 memset(buffer, GARBAGE_FILL_CHARACTER, size);
1528 }
1529#endif
1530
1531 RETURN;
1532}
1533
1534#if _DEBUG
1535inline BOOL SBuffer::EnsureGarbageCharOnly(const BYTE *buffer, COUNT_T size)
1536{
1537 LIMITED_METHOD_CONTRACT;
1538 BOOL bRet = TRUE;
1539 if (size > GARBAGE_FILL_BUFFER_SIZE)
1540 {
1541 size = GARBAGE_FILL_BUFFER_SIZE;
1542 }
1543 if (bRet && size > 0)
1544 {
1545 bRet &= (memcmp(buffer, g_garbageFillBuffer, size) == 0);
1546 }
1547 return bRet;
1548}
1549#endif
1550
1551inline CHECK SBuffer::CheckUnusedBuffer(const BYTE *buffer, COUNT_T size) const
1552{
1553 WRAPPER_NO_CONTRACT;
1554 // This check is too expensive.
1555#if 0 // _DEBUG
1556 if (!IsImmutable()
1557 || buffer < m_buffer || buffer > m_buffer + m_allocation) // Allocating a new buffer
1558 {
1559 if (!SBuffer::EnsureGarbageCharOnly(buffer, size))
1560 {
1561 CHECK_FAIL("Overwrite of unused buffer region found");
1562 }
1563 }
1564#endif
1565 CHECK_OK;
1566}
1567
1568inline CHECK SBuffer::Check() const
1569{
1570 WRAPPER_NO_CONTRACT;
1571 CHECK(CheckBufferClosed());
1572 CHECK_OK;
1573}
1574
1575inline CHECK SBuffer::Invariant() const
1576{
1577 LIMITED_METHOD_CONTRACT;
1578
1579 CHECK_OK;
1580}
1581
1582inline CHECK SBuffer::InternalInvariant() const
1583{
1584 WRAPPER_NO_CONTRACT;
1585 CHECK(m_size <= m_allocation);
1586
1587 CHECK(CheckUnusedBuffer(m_buffer + m_size, m_allocation - m_size));
1588
1589 if (IsAllocated())
1590 CHECK(CheckBuffer(m_buffer, m_allocation));
1591
1592 CHECK_OK;
1593}
1594
1595inline CHECK SBuffer::CheckBufferClosed() const
1596{
1597 WRAPPER_NO_CONTRACT;
1598#if _DEBUG
1599 CHECK_MSG(!IsOpened(), "Cannot use buffer API while raw open is in progress");
1600#endif
1601 CHECK_OK;
1602}
1603
1604inline CHECK SBuffer::CheckSize(COUNT_T size)
1605{
1606 LIMITED_METHOD_CONTRACT;
1607 // !todo: add any range checking here
1608 CHECK_OK;
1609}
1610
1611inline CHECK SBuffer::CheckAllocation(COUNT_T size)
1612{
1613 LIMITED_METHOD_CONTRACT;
1614
1615 // !todo: add any range checking here
1616 CHECK_OK;
1617}
1618
1619inline CHECK SBuffer::CheckIteratorRange(const CIterator &i) const
1620{
1621 WRAPPER_NO_CONTRACT;
1622 CHECK(i.Check());
1623 CHECK(i.CheckContainer(this));
1624 CHECK(i >= Begin());
1625 CHECK(i < End());
1626 CHECK_OK;
1627}
1628
1629inline CHECK SBuffer::CheckIteratorRange(const CIterator &i, COUNT_T size) const
1630{
1631 WRAPPER_NO_CONTRACT;
1632 CHECK(i.Check());
1633 CHECK(i.CheckContainer(this));
1634 CHECK(i >= Begin());
1635 CHECK(i + size <= End());
1636 CHECK_OK;
1637}
1638
1639inline SBuffer::Index::Index()
1640{
1641 LIMITED_METHOD_DAC_CONTRACT;
1642
1643 m_ptr = NULL;
1644}
1645
1646inline SBuffer::Index::Index(SBuffer *container, SCOUNT_T index)
1647 : CheckedIteratorBase<SBuffer>(container)
1648{
1649 LIMITED_METHOD_CONTRACT;
1650 SUPPORTS_DAC_HOST_ONLY;
1651
1652 m_ptr = container->m_buffer + index;
1653}
1654
1655inline BYTE &SBuffer::Index::GetAt(SCOUNT_T delta) const
1656{
1657 LIMITED_METHOD_DAC_CONTRACT;
1658
1659 return m_ptr[delta];
1660}
1661
1662inline void SBuffer::Index::Skip(SCOUNT_T delta)
1663{
1664 LIMITED_METHOD_CONTRACT;
1665 SUPPORTS_DAC_HOST_ONLY;
1666
1667 m_ptr += delta;
1668}
1669
1670inline SCOUNT_T SBuffer::Index::Subtract(const Index &i) const
1671{
1672 LIMITED_METHOD_CONTRACT;
1673 SUPPORTS_DAC_HOST_ONLY;
1674
1675 return (SCOUNT_T) (m_ptr - i.m_ptr);
1676}
1677
1678inline CHECK SBuffer::Index::DoCheck(SCOUNT_T delta) const
1679{
1680 WRAPPER_NO_CONTRACT;
1681#if _DEBUG
1682 CHECK(m_ptr + delta >= GetContainerDebug()->m_buffer);
1683 CHECK(m_ptr + delta < GetContainerDebug()->m_buffer + GetContainerDebug()->m_size);
1684#endif
1685 CHECK_OK;
1686}
1687
1688inline void SBuffer::Index::Resync(const SBuffer *buffer, BYTE *value) const
1689{
1690 CONTRACT_VOID
1691 {
1692 // INSTANCE_CHECK - Iterator is out of sync with its object now by definition
1693 POSTCONDITION(CheckPointer(this));
1694 PRECONDITION(CheckPointer(buffer));
1695 NOTHROW;
1696 GC_NOTRIGGER;
1697 SUPPORTS_DAC_HOST_ONLY;
1698 }
1699 CONTRACT_END;
1700
1701 const_cast<Index*>(this)->CheckedIteratorBase<SBuffer>::Resync(const_cast<SBuffer*>(buffer));
1702 const_cast<Index*>(this)->m_ptr = value;
1703
1704 RETURN;
1705}
1706
1707#ifdef _MSC_VER
1708#pragma warning(pop)
1709#endif // _MSC_VER
1710
1711#endif // _SBUFFER_INL_
1712