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 }