Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef nsSegmentedBuffer_h__
8 : #define nsSegmentedBuffer_h__
9 :
10 : #include "nsIMemory.h"
11 :
12 : class nsSegmentedBuffer
13 : {
14 : public:
15 76 : nsSegmentedBuffer()
16 76 : : mSegmentSize(0)
17 : , mMaxSize(0)
18 : , mSegmentArray(nullptr)
19 : , mSegmentArrayCount(0)
20 : , mFirstSegmentIndex(0)
21 76 : , mLastSegmentIndex(0)
22 : {
23 76 : }
24 :
25 75 : ~nsSegmentedBuffer()
26 75 : {
27 75 : Empty();
28 75 : }
29 :
30 :
31 : nsresult Init(uint32_t aSegmentSize, uint32_t aMaxSize);
32 :
33 : char* AppendNewSegment(); // pushes at end
34 :
35 : // returns true if no more segments remain:
36 : bool DeleteFirstSegment(); // pops from beginning
37 :
38 : // returns true if no more segments remain:
39 : bool DeleteLastSegment(); // pops from beginning
40 :
41 : // Call Realloc() on last segment. This is used to reduce memory
42 : // consumption when data is not an exact multiple of segment size.
43 : bool ReallocLastSegment(size_t aNewSize);
44 :
45 : void Empty(); // frees all segments
46 :
47 186 : inline uint32_t GetSegmentCount()
48 : {
49 186 : if (mFirstSegmentIndex <= mLastSegmentIndex) {
50 186 : return mLastSegmentIndex - mFirstSegmentIndex;
51 : } else {
52 0 : return mSegmentArrayCount + mLastSegmentIndex - mFirstSegmentIndex;
53 : }
54 : }
55 :
56 183 : inline uint32_t GetSegmentSize()
57 : {
58 183 : return mSegmentSize;
59 : }
60 : inline uint32_t GetMaxSize()
61 : {
62 : return mMaxSize;
63 : }
64 91 : inline uint32_t GetSize()
65 : {
66 91 : return GetSegmentCount() * mSegmentSize;
67 : }
68 :
69 95 : inline char* GetSegment(uint32_t aIndex)
70 : {
71 95 : NS_ASSERTION(aIndex < GetSegmentCount(), "index out of bounds");
72 95 : int32_t i = ModSegArraySize(mFirstSegmentIndex + (int32_t)aIndex);
73 95 : return mSegmentArray[i];
74 : }
75 :
76 : protected:
77 297 : inline int32_t ModSegArraySize(int32_t aIndex)
78 : {
79 297 : uint32_t result = aIndex & (mSegmentArrayCount - 1);
80 297 : NS_ASSERTION(result == aIndex % mSegmentArrayCount,
81 : "non-power-of-2 mSegmentArrayCount");
82 297 : return result;
83 : }
84 :
85 91 : inline bool IsFull()
86 : {
87 91 : return ModSegArraySize(mLastSegmentIndex + 1) == mFirstSegmentIndex;
88 : }
89 :
90 : protected:
91 : uint32_t mSegmentSize;
92 : uint32_t mMaxSize;
93 : char** mSegmentArray;
94 : uint32_t mSegmentArrayCount;
95 : int32_t mFirstSegmentIndex;
96 : int32_t mLastSegmentIndex;
97 : };
98 :
99 : // NS_SEGMENTARRAY_INITIAL_SIZE: This number needs to start out as a
100 : // power of 2 given how it gets used. We double the segment array
101 : // when we overflow it, and use that fact that it's a power of 2
102 : // to compute a fast modulus operation in IsFull.
103 : //
104 : // 32 segment array entries can accommodate 128k of data if segments
105 : // are 4k in size. That seems like a reasonable amount that will avoid
106 : // needing to grow the segment array.
107 : #define NS_SEGMENTARRAY_INITIAL_COUNT 32
108 :
109 : #endif // nsSegmentedBuffer_h__
|