1 /* 2 * hunt-proton: AMQP Protocol library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 module hunt.proton.engine.impl.FrameWriterBuffer; 12 13 import hunt.io.ByteBuffer; 14 import std.algorithm; 15 import hunt.proton.codec.ReadableBuffer; 16 import hunt.proton.codec.WritableBuffer; 17 import hunt.Byte; 18 import hunt.Short; 19 import hunt.Long; 20 import hunt.Integer; 21 import hunt.Float; 22 import hunt.Double; 23 import hunt.Exceptions; 24 import hunt.logging; 25 class FrameWriterBuffer : WritableBuffer { 26 27 public static int DEFAULT_CAPACITY = 1024; 28 29 byte [] _array; 30 int _position; 31 32 /** 33 * Creates a new WritableBuffer with default capacity. 34 */ 35 this() { 36 this(DEFAULT_CAPACITY); 37 } 38 39 /** 40 * Create a new WritableBuffer with the given capacity. 41 * 42 * @param capacity 43 * the inital capacity to allocate for this buffer. 44 */ 45 this(int capacity) { 46 this._array = new byte[capacity]; 47 } 48 49 public byte[] array() { 50 return _array; 51 } 52 53 public int arrayOffset() { 54 return 0; 55 } 56 57 override 58 public void put(byte b) { 59 ensureRemaining(Byte.BYTES); 60 _array[_position++] = b; 61 } 62 63 override 64 public void putShort(short value) { 65 ensureRemaining(Short.BYTES); 66 _array[_position++] = cast(byte)(value >>> 8); 67 _array[_position++] = cast(byte)(value >>> 0); 68 } 69 70 override 71 public void putInt(int value) { 72 ensureRemaining(Integer.BYTES); 73 _array[_position++] = cast(byte)(value >>> 24); 74 _array[_position++] = cast(byte)(value >>> 16); 75 _array[_position++] = cast(byte)(value >>> 8); 76 _array[_position++] = cast(byte)(value >>> 0); 77 } 78 79 override 80 public void putLong(long value) { 81 ensureRemaining(Long.BYTES); 82 _array[_position++] = cast(byte)(value >>> 56); 83 _array[_position++] = cast(byte)(value >>> 48); 84 _array[_position++] = cast(byte)(value >>> 40); 85 _array[_position++] = cast(byte)(value >>> 32); 86 _array[_position++] = cast(byte)(value >>> 24); 87 _array[_position++] = cast(byte)(value >>> 16); 88 _array[_position++] = cast(byte)(value >>> 8); 89 _array[_position++] = cast(byte)(value >>> 0); 90 } 91 92 override 93 public void putFloat(float value) { 94 putInt(Float.floatToRawIntBits(value)); 95 } 96 97 override 98 public void putDouble(double value) { 99 putLong(Double.doubleToRawLongBits(value)); 100 } 101 102 override 103 public void put(byte[] src, int offset, int length) { 104 if (length == 0) { 105 return; 106 } 107 108 ensureRemaining(length); 109 //System.arraycopy(src, offset, array, position, length); 110 _array[_position .. _position+length] = src[offset .. offset+length]; 111 _position += length; 112 } 113 114 override 115 public void put(ByteBuffer payload) { 116 int toCopy = payload.remaining(); 117 ensureRemaining(toCopy); 118 119 if (payload.hasArray()) { 120 //System.arraycopy(payload.array(), payload.arrayOffset() + payload.position(), array, position, toCopy); 121 _array[_position .. _position+toCopy] = payload.array()[payload.arrayOffset() + payload.position() .. payload.arrayOffset() + payload.position()+toCopy]; 122 payload.position(payload.position() + toCopy); 123 } else { 124 payload.get(_array, _position, toCopy); 125 } 126 127 _position += toCopy; 128 } 129 130 override 131 public void put(ReadableBuffer payload) { 132 int toCopy = payload.remaining(); 133 ensureRemaining(toCopy); 134 135 if (payload.hasArray()) { 136 //System.arraycopy(payload.array(), payload.arrayOffset() + payload.position(), array, position, toCopy); 137 _array[_position .. toCopy+ _position] = payload.array()[payload.arrayOffset() + payload.position() .. payload.arrayOffset() + payload.position() + toCopy]; 138 payload.position(payload.position() + toCopy); 139 } else { 140 payload.get(_array, _position, toCopy); 141 } 142 143 _position += toCopy; 144 } 145 146 override 147 public bool hasRemaining() { 148 return _position < Integer.MAX_VALUE; 149 } 150 151 override 152 public int remaining() { 153 return Integer.MAX_VALUE - _position; 154 } 155 156 /** 157 * Ensures the the buffer has at least the requiredRemaining space specified. 158 * <p> 159 * The internal buffer will be doubled if the requested capacity is less than that 160 * amount or the buffer will be expanded to the full new requiredRemaining value. 161 * 162 * @param requiredRemaining 163 * the minimum remaining bytes needed to meet the next write operation. 164 */ 165 override 166 public void ensureRemaining(int requiredRemaining) { 167 if (requiredRemaining > _array.length - _position) { 168 byte [] newBuffer = new byte[max(_array.length << 1, requiredRemaining + _position)]; 169 newBuffer[0 .. _array.length] = _array[0 .. _array.length]; 170 //System.arraycopy(array, 0, newBuffer, 0, array.length); 171 _array = newBuffer; 172 } 173 } 174 175 override 176 public int position() { 177 return _position; 178 } 179 180 override 181 public void position(int position) { 182 if (position < 0) { 183 throw new IllegalArgumentException("Requested new buffer position cannot be negative"); 184 } 185 186 if (position > _array.length) { 187 ensureRemaining(position - cast(int)_array.length); 188 } 189 190 this._position = position; 191 } 192 193 override 194 public int limit() { 195 return Integer.MAX_VALUE; 196 } 197 198 /** 199 * Copy bytes from this buffer into the target buffer and compacts this buffer. 200 * <p> 201 * Copy either all bytes written into this buffer (start to current position) or 202 * as many as will fit if the target capacity is less that the bytes written. Bytes 203 * not read from this buffer are moved to the front of the buffer and the position is 204 * reset to the end of the copied region. 205 * 206 * @param target 207 * The array to move bytes to from those written into this buffer. 208 * 209 * @return the number of bytes transfered to the target buffer. 210 */ 211 public int transferTo(ByteBuffer target) { 212 int size = min(_position, target.remaining()); 213 if (size == 0) { 214 return 0; 215 } 216 217 if (target.hasArray()) { 218 // System.arraycopy(array, 0, target.array(), target.arrayOffset() + target.position(), size); 219 target.array()[target.arrayOffset() + target.position() .. target.arrayOffset() + target.position()+size] = _array[0 .. size]; 220 target.position(target.position() + size); 221 } else { 222 target.put(_array, 0, size); 223 } 224 225 // Compact any remaining data to the front of the array so that new writes can reuse 226 // space previously allocated and not extend the array if possible. 227 if (size != _position) { 228 int remainder = _position - size; 229 230 //System.arraycopy(array, size, array, 0, remainder); 231 // _array[0 .. remainder] = _array[size .. _position].dup; 232 for(int i =0; i< remainder; i++) { 233 _array[i] = _array[size+i]; 234 } 235 236 _position = remainder; // ensure we are at end of unread chunk 237 } else { 238 _position = 0; // reset to empty state. 239 } 240 241 return size; 242 } 243 }