1 /*******************************************************************************
2 
3     Composes two queues, with the second acting as an overflow of the first.
4 
5     Items are initially pushed into the main queue until it is full. Subsequent
6     items then begin to be pushed into the swap queue and will continue doing so
7     until the swap queue becomes empty again.
8 
9     Items are popped first from the main queue, and secondly from the overflow
10     queue.
11 
12     The composed queues do not have to be of the same type (they are both simply
13     required to implement the IByteQueue interface). A common usage pattern is
14     to chain a file-based queue as an overflow of a memory-based queue.
15 
16     Copyright:
17         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
18         All rights reserved.
19 
20     License:
21         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
22         Alternatively, this file may be distributed under the terms of the Tango
23         3-Clause BSD License (see LICENSE_BSD.txt for details).
24 
25 *******************************************************************************/
26 
27 module ocean.util.container.queue.QueueChain;
28 
29 
30 
31 
32 import ocean.util.container.queue.model.IByteQueue;
33 
34 import ocean.util.container.queue.model.IQueueInfo;
35 
36 import ocean.util.container.queue.FlexibleRingQueue;
37 
38 
39 import ocean.io.stream.Buffered,
40        ocean.io.device.File,
41        Filesystem = ocean.io.Path;
42 
43 import ocean.meta.types.Qualifiers;
44 
45 
46 public class QueueChain : IByteQueue
47 {
48     /***************************************************************************
49 
50         Queues
51 
52     ***************************************************************************/
53 
54     private IByteQueue queue, swap;
55 
56 
57     /***************************************************************************
58 
59         Constructor
60 
61         Params:
62             queue = queue instance that will be used
63             swap  = queue instance that will be used as swap
64 
65     ***************************************************************************/
66 
67     public this ( IByteQueue queue, IByteQueue swap )
68     {
69         this.queue = queue;
70         this.swap  = swap;
71     }
72 
73 
74     /***************************************************************************
75 
76         Pushes an item into the queue.
77 
78         Params:
79             item = data item to push
80 
81         Returns:
82             true if the item was pushed successfully, false if it didn't fit
83 
84     ***************************************************************************/
85 
86     public bool push ( in void[] item )
87     {
88         if ( item.length == 0 ) return false;
89 
90         if ( this.swap.is_empty() && this.queue.willFit(item.length) )
91         {
92             return this.queue.push(item);
93         }
94         else
95         {
96             return this.swap.push(item);
97         }
98     }
99 
100 
101     /***************************************************************************
102 
103         Reserves space for an item of <size> bytes on the queue but doesn't
104         fill the content. The caller is expected to fill in the content using
105         the returned slice.
106 
107         Params:
108             size = size of the space of the item that should be reserved
109 
110         Returns:
111             slice to the reserved space if it was successfully reserved,
112             else null
113 
114     ***************************************************************************/
115 
116     public void[] push ( size_t size )
117     {
118         if ( this.swap.is_empty() && this.queue.willFit(size) )
119         {
120             return this.queue.push(size);
121         }
122         else
123         {
124             return this.swap.push(size);
125         }
126     }
127 
128 
129     /***************************************************************************
130 
131         Pops an item from the queue.
132 
133         Returns:
134             item popped from queue, may be null if queue is empty
135 
136     ***************************************************************************/
137 
138     public void[] pop ( )
139     {
140         if ( this.queue.is_empty() == false )
141         {
142             return this.queue.pop();
143         }
144         else
145         {
146             bool fits ( )
147             {
148                 auto len = this.swap.peek().length;
149 
150                 return len > 0 && this.queue.willFit(len);
151             }
152 
153             while ( fits() )
154             {
155                 this.queue.push(this.swap.pop());
156             }
157 
158             return this.queue.pop();
159         }
160     }
161 
162 
163     /***************************************************************************
164 
165         Peek at the next item that would be popped from the queue.
166 
167         Returns:
168             item that would be popped from queue, may be null if queue is empty
169 
170     ***************************************************************************/
171 
172     public void[] peek ( )
173     {
174         if ( this.queue.is_empty() == false )
175         {
176             return this.queue.peek();
177         }
178 
179         return this.swap.peek();
180     }
181 
182 
183     /***************************************************************************
184 
185         Finds out whether the provided number of bytes will fit in the queue.
186 
187         Params:
188             bytes = size of item to check
189 
190         Returns:
191             always true
192 
193     ***************************************************************************/
194 
195     public bool willFit ( size_t bytes )
196     {
197         return this.queue.willFit(bytes) || this.swap.willFit(bytes);
198     }
199 
200 
201     /***************************************************************************
202 
203         Returns:
204             total number of bytes used by queue (used space + free space)
205 
206     ***************************************************************************/
207 
208     public ulong total_space ( )
209     {
210         return queue.total_space() + swap.total_space();
211     }
212 
213 
214     /***************************************************************************
215 
216         Returns:
217             number of bytes stored in queue
218 
219     ***************************************************************************/
220 
221     public ulong used_space ( )
222     {
223         return queue.used_space() + swap.used_space();
224     }
225 
226 
227     /***************************************************************************
228 
229         Returns:
230             number of bytes free in queue
231 
232     ***************************************************************************/
233 
234     public ulong free_space ( )
235     {
236         if ( swap.is_empty() == false ) return swap.free_space();
237 
238         return queue.free_space() + swap.free_space();
239     }
240 
241 
242     /***************************************************************************
243 
244         Returns:
245             the number of items in the queue
246 
247     ***************************************************************************/
248 
249     public size_t length ( )
250     {
251         return queue.length() + swap.length();
252     }
253 
254 
255     /***************************************************************************
256 
257         Tells whether the queue is empty.
258 
259         Returns:
260             true if the queue is empty
261 
262     ***************************************************************************/
263 
264     public bool is_empty ( )
265     {
266         return queue.is_empty() && swap.is_empty();
267     }
268 
269 
270     /***************************************************************************
271 
272         Deletes all items
273 
274     ***************************************************************************/
275 
276     public void clear ( )
277     {
278         this.queue.clear();
279         this.swap.clear();
280     }
281 }