1 // 2 // Copyright (c) ZeroC, Inc. All rights reserved. 3 // 4 5 package com.zeroc.IceInternal; 6 7 // 8 // An instance of java.nio.ByteBuffer cannot grow beyond its initial capacity. 9 // This class wraps a ByteBuffer and supports reallocation. 10 // 11 public class Buffer 12 { Buffer(boolean direct)13 public Buffer(boolean direct) 14 { 15 this(direct, java.nio.ByteOrder.LITTLE_ENDIAN); 16 } 17 Buffer(boolean direct, java.nio.ByteOrder order)18 public Buffer(boolean direct, java.nio.ByteOrder order) 19 { 20 b = _emptyBuffer; 21 _size = 0; 22 _capacity = 0; 23 _direct = direct; 24 _order = order; 25 } 26 Buffer(byte[] data)27 public Buffer(byte[] data) 28 { 29 this(data, java.nio.ByteOrder.LITTLE_ENDIAN); 30 } 31 Buffer(byte[] data, java.nio.ByteOrder order)32 public Buffer(byte[] data, java.nio.ByteOrder order) 33 { 34 b = java.nio.ByteBuffer.wrap(data); 35 b.order(order); 36 _size = data.length; 37 _capacity = 0; 38 _direct = false; 39 _order = order; 40 } 41 Buffer(java.nio.ByteBuffer data)42 public Buffer(java.nio.ByteBuffer data) 43 { 44 this(data, java.nio.ByteOrder.LITTLE_ENDIAN); 45 } 46 Buffer(java.nio.ByteBuffer data, java.nio.ByteOrder order)47 public Buffer(java.nio.ByteBuffer data, java.nio.ByteOrder order) 48 { 49 b = data; 50 b.order(order); 51 _size = data.remaining(); 52 _capacity = 0; 53 _direct = false; 54 _order = order; 55 } 56 Buffer(Buffer buf, boolean adopt)57 public Buffer(Buffer buf, boolean adopt) 58 { 59 b = buf.b; 60 _size = buf._size; 61 _capacity = buf._capacity; 62 _direct = buf._direct; 63 _shrinkCounter = buf._shrinkCounter; 64 _order = buf._order; 65 66 if(adopt) 67 { 68 buf.clear(); 69 } 70 } 71 position(int newPosition)72 public java.nio.Buffer position(int newPosition) 73 { 74 // Cast to java.nio.Buffer to avoid incompatible covariant 75 // return type used in Java 9 java.nio.ByteBuffer 76 return ((java.nio.Buffer)b).position(newPosition); 77 } 78 limit(int newLimit)79 public java.nio.Buffer limit(int newLimit) 80 { 81 // Cast to java.nio.Buffer to avoid incompatible covariant 82 // return type used in Java 9 java.nio.ByteBuffer 83 return ((java.nio.Buffer)b).limit(newLimit); 84 } 85 flip()86 public java.nio.Buffer flip() 87 { 88 // Cast to java.nio.Buffer to avoid incompatible covariant 89 // return type used in Java 9 java.nio.ByteBuffer 90 return ((java.nio.Buffer)b).flip(); 91 } 92 swap(Buffer buf)93 public void swap(Buffer buf) 94 { 95 final java.nio.ByteBuffer bb = buf.b; 96 final int size = buf._size; 97 final int capacity = buf._capacity; 98 final boolean direct = buf._direct; 99 final int shrinkCounter = buf._shrinkCounter; 100 final java.nio.ByteOrder order = buf._order; 101 102 buf.b = b; 103 buf._size = _size; 104 buf._capacity = _capacity; 105 buf._direct = _direct; 106 buf._shrinkCounter = _shrinkCounter; 107 buf._order = _order; 108 109 b = bb; 110 _size = size; 111 _capacity = capacity; 112 _direct = direct; 113 _shrinkCounter = shrinkCounter; 114 _order = order; 115 } 116 size()117 public int size() 118 { 119 return _size; 120 } 121 empty()122 public boolean empty() 123 { 124 return _size == 0; 125 } 126 clear()127 public void clear() 128 { 129 b = _emptyBuffer; 130 _size = 0; 131 _capacity = 0; 132 _shrinkCounter = 0; 133 } 134 135 // 136 // Call expand(n) to add room for n additional bytes. Note that expand() 137 // examines the current position of the buffer first; we don't want to 138 // expand the buffer if the caller is writing to a location that is 139 // already in the buffer. 140 // expand(int n)141 public void expand(int n) 142 { 143 final int sz = (b == _emptyBuffer) ? n : b.position() + n; 144 if(sz > _size) 145 { 146 resize(sz, false); 147 } 148 } 149 resize(int n, boolean reading)150 public void resize(int n, boolean reading) 151 { 152 assert(b == _emptyBuffer || _capacity > 0); 153 154 if(n == 0) 155 { 156 clear(); 157 } 158 else if(n > _capacity) 159 { 160 reserve(n); 161 } 162 _size = n; 163 164 // 165 // When used for reading, we want to set the buffer's limit to the new size. 166 // 167 if(reading) 168 { 169 limit(_size); 170 } 171 } 172 reset()173 public void reset() 174 { 175 if(_size > 0 && _size * 2 < _capacity) 176 { 177 // 178 // If the current buffer size is smaller than the 179 // buffer capacity, we shrink the buffer memory to the 180 // current size. This is to avoid holding on to too much 181 // memory if it's not needed anymore. 182 // 183 if(++_shrinkCounter > 2) 184 { 185 reserve(_size); 186 _shrinkCounter = 0; 187 } 188 } 189 else 190 { 191 _shrinkCounter = 0; 192 } 193 _size = 0; 194 if(b != _emptyBuffer) 195 { 196 limit(b.capacity()); 197 position(0); 198 } 199 } 200 reserve(int n)201 private void reserve(int n) 202 { 203 if(n > _capacity) 204 { 205 _capacity = java.lang.Math.max(n, 2 * _capacity); 206 _capacity = java.lang.Math.max(240, _capacity); 207 } 208 else if(n < _capacity) 209 { 210 _capacity = n; 211 } 212 else 213 { 214 return; 215 } 216 217 try 218 { 219 java.nio.ByteBuffer buf; 220 221 if(_direct) 222 { 223 buf = java.nio.ByteBuffer.allocateDirect(_capacity); 224 } 225 else 226 { 227 buf = java.nio.ByteBuffer.allocate(_capacity); 228 } 229 230 if(b == _emptyBuffer) 231 { 232 b = buf; 233 } 234 else 235 { 236 final int pos = b.position(); 237 position(0); 238 limit(java.lang.Math.min(_capacity, b.capacity())); 239 buf.put(b); 240 b = buf; 241 limit(b.capacity()); 242 position(pos); 243 } 244 245 b.order(_order); // Preserve the original order. 246 } 247 catch(OutOfMemoryError ex) 248 { 249 _capacity = b.capacity(); // Restore the previous capacity. 250 throw ex; 251 } 252 } 253 254 public java.nio.ByteBuffer b; 255 // Sentinel used for null buffer. 256 public java.nio.ByteBuffer _emptyBuffer = java.nio.ByteBuffer.allocate(0); 257 258 private int _size; 259 private int _capacity; // Cache capacity to avoid excessive method calls. 260 private boolean _direct; // Use direct buffers? 261 private int _shrinkCounter; 262 private java.nio.ByteOrder _order; 263 } 264