132
|
1 /*******************************************************************************
|
|
2
|
|
3 copyright: Copyright (c) 2004 Kris Bell. All rights reserved
|
|
4
|
|
5 license: BSD style: $(LICENSE)
|
|
6
|
|
7 version: Initial release: October 2004
|
|
8 Outback release: December 2006
|
|
9
|
|
10 author: Kris
|
|
11
|
|
12 Allocators to use in conjunction with the Reader class. These are
|
|
13 intended to manage array allocation for a variety of Reader.get()
|
|
14 methods
|
|
15
|
|
16 *******************************************************************************/
|
|
17
|
|
18 module tango.io.protocol.Allocator;
|
|
19
|
|
20 private import tango.io.protocol.model.IProtocol;
|
|
21
|
|
22
|
|
23 /*******************************************************************************
|
|
24
|
|
25 Simple allocator, copying into the heap for each array requested:
|
|
26 this is the default behaviour for Reader instances
|
|
27
|
|
28 *******************************************************************************/
|
|
29
|
|
30 class HeapCopy : IAllocator
|
|
31 {
|
|
32 private IProtocol protocol_;
|
|
33
|
|
34 /***********************************************************************
|
|
35
|
|
36 ***********************************************************************/
|
|
37
|
|
38 this (IProtocol protocol)
|
|
39 {
|
|
40 protocol_ = protocol;
|
|
41 }
|
|
42
|
|
43 /***********************************************************************
|
|
44
|
|
45 ***********************************************************************/
|
|
46
|
|
47 final IProtocol protocol ()
|
|
48 {
|
|
49 return protocol_;
|
|
50 }
|
|
51
|
|
52 /***********************************************************************
|
|
53
|
|
54 ***********************************************************************/
|
|
55
|
|
56 final void reset ()
|
|
57 {
|
|
58 }
|
|
59
|
|
60 /***********************************************************************
|
|
61
|
|
62 ***********************************************************************/
|
|
63
|
|
64 final void[] allocate (IProtocol.Reader reader, uint bytes, IProtocol.Type type)
|
|
65 {
|
|
66 return reader ((new void[bytes]).ptr, bytes, type);
|
|
67 }
|
|
68 }
|
|
69
|
|
70
|
|
71 /*******************************************************************************
|
|
72
|
|
73 Allocate from within a private heap space. This supports reading
|
|
74 data as 'records', reusing the same chunk of memory for each record
|
|
75 loaded. The ctor takes an argument defining the initial allocation
|
|
76 made, and this will be increased as necessary to accomodate larger
|
|
77 records. Use the reset() method to indicate end of record (reuse
|
|
78 memory for subsequent requests), or set the autoreset flag to reuse
|
|
79 upon each array request.
|
|
80
|
|
81 *******************************************************************************/
|
|
82
|
|
83 class HeapSlice : IAllocator
|
|
84 {
|
|
85 private uint used;
|
|
86 private void[] buffer;
|
|
87 private IProtocol protocol_;
|
|
88 private bool autoreset;
|
|
89
|
|
90 /***********************************************************************
|
|
91
|
|
92 ***********************************************************************/
|
|
93
|
|
94 this (IProtocol protocol, uint width=4096, bool autoreset=false)
|
|
95 {
|
|
96 protocol_ = protocol;
|
|
97 buffer = new void[width];
|
|
98 this.autoreset = autoreset;
|
|
99 }
|
|
100
|
|
101 /***********************************************************************
|
|
102
|
|
103 ***********************************************************************/
|
|
104
|
|
105 final IProtocol protocol ()
|
|
106 {
|
|
107 return protocol_;
|
|
108 }
|
|
109
|
|
110 /***********************************************************************
|
|
111
|
|
112 Reset content length to zero
|
|
113
|
|
114 ***********************************************************************/
|
|
115
|
|
116 final void reset ()
|
|
117 {
|
|
118 used = 0;
|
|
119 }
|
|
120
|
|
121 /***********************************************************************
|
|
122
|
|
123 No allocation: copy into a reserved arena.
|
|
124
|
|
125 With HeapSlice, it is normal to allocate space large
|
|
126 enough to contain, say, a record of data. The reserved
|
|
127 space will grow to accomodate larger records. A reset()
|
|
128 call should be made between each record read, to ensure
|
|
129 the space is being reused.
|
|
130
|
|
131 ***********************************************************************/
|
|
132
|
|
133 final void[] allocate (IProtocol.Reader reader, uint bytes, IProtocol.Type type)
|
|
134 {
|
|
135 if (autoreset)
|
|
136 used = 0;
|
|
137
|
|
138 if ((used + bytes) > buffer.length)
|
|
139 buffer.length = (used + bytes) * 2;
|
|
140
|
|
141 auto ptr = &buffer[used];
|
|
142 used += bytes;
|
|
143
|
|
144 return reader (ptr, bytes, type);
|
|
145 }
|
|
146 }
|
|
147
|
|
148
|
|
149 /*******************************************************************************
|
|
150
|
|
151 Alias directly from the buffer instead of allocating from the heap.
|
|
152 This avoids both heap activity and copying, but requires some care
|
|
153 in terms of usage. See methods allocate() for details
|
|
154
|
|
155 *******************************************************************************/
|
|
156
|
|
157 class BufferSlice : IAllocator
|
|
158 {
|
|
159 private IProtocol protocol_;
|
|
160
|
|
161 /***********************************************************************
|
|
162
|
|
163 ***********************************************************************/
|
|
164
|
|
165 this (IProtocol protocol)
|
|
166 {
|
|
167 protocol_ = protocol;
|
|
168 }
|
|
169
|
|
170 /***********************************************************************
|
|
171
|
|
172 ***********************************************************************/
|
|
173
|
|
174 final IProtocol protocol ()
|
|
175 {
|
|
176 return protocol_;
|
|
177 }
|
|
178
|
|
179 /***********************************************************************
|
|
180
|
|
181 Move all unconsumed data to the front of the buffer, freeing
|
|
182 up space for more
|
|
183
|
|
184 ***********************************************************************/
|
|
185
|
|
186 final void reset ()
|
|
187 {
|
|
188 protocol.buffer.compress;
|
|
189 }
|
|
190
|
|
191 /***********************************************************************
|
|
192
|
|
193 No alloc or copy: alias directly from buffer. While this is
|
|
194 very efficient (no heap activity) it should be used only in
|
|
195 scenarios where content is known to fit within a buffer, and
|
|
196 there is no conversion of said content e.g. take care when
|
|
197 using with EndianProtocol since it will convert within the
|
|
198 buffer, potentially confusing additional buffer clients.
|
|
199
|
|
200 With BufferSlice, it is considered normal to create a Buffer
|
|
201 large enough to contain, say, a file and subsequently slice
|
|
202 all strings/arrays directly from this buffer. Smaller Buffers
|
|
203 can be used in a record-oriented manner similar to HeapSlice:
|
|
204 invoke reset() before each record is processed to ensure here
|
|
205 is sufficient space available in the buffer to house a complete
|
|
206 record. GrowBuffer could be used in the latter case, to ensure
|
|
207 the largest record width is always accomodated.
|
|
208
|
|
209 A good use of this is in handling of network traffic, where
|
|
210 incoming data is often transient and of a known extent. For
|
|
211 another potential use, consider the quantity of distinct text
|
|
212 arrays generated by an XML parser -- would be convenient to
|
|
213 slice all of them from a single allocation instead
|
|
214
|
|
215 ***********************************************************************/
|
|
216
|
|
217 final void[] allocate (IProtocol.Reader reader, uint bytes, IProtocol.Type type)
|
|
218 {
|
|
219 return protocol_.buffer.slice (bytes);
|
|
220 }
|
|
221 }
|