Import atomix/{storage,utils}
[controller.git] / third-party / atomix / storage / src / main / java / io / atomix / storage / buffer / AbstractBuffer.java
1 /*
2  * Copyright 2015-present Open Networking Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package io.atomix.storage.buffer;
17
18 import io.atomix.utils.concurrent.ReferenceManager;
19 import io.atomix.utils.memory.Memory;
20
21 import java.nio.BufferOverflowException;
22 import java.nio.BufferUnderflowException;
23 import java.nio.ByteOrder;
24 import java.nio.InvalidMarkException;
25 import java.nio.charset.Charset;
26 import java.nio.charset.StandardCharsets;
27 import java.util.concurrent.atomic.AtomicInteger;
28
29 import static io.atomix.storage.buffer.Bytes.BOOLEAN;
30 import static io.atomix.storage.buffer.Bytes.BYTE;
31 import static io.atomix.storage.buffer.Bytes.SHORT;
32
33 /**
34  * Abstract buffer implementation.
35  *
36  * @author <a href="http://github.com/kuujo">Jordan Halterman</a>
37  */
38 public abstract class AbstractBuffer implements Buffer {
39   static final int DEFAULT_INITIAL_CAPACITY = 4096;
40   static final int MAX_SIZE = Integer.MAX_VALUE - 5;
41
42   protected final Bytes bytes;
43   private int offset;
44   private int initialCapacity;
45   private int capacity;
46   private int maxCapacity;
47   private int position;
48   private int limit = -1;
49   private int mark = -1;
50   private final AtomicInteger references = new AtomicInteger();
51   protected final ReferenceManager<Buffer> referenceManager;
52   private SwappedBuffer swap;
53
54   protected AbstractBuffer(Bytes bytes, ReferenceManager<Buffer> referenceManager) {
55     this(bytes, 0, 0, 0, referenceManager);
56   }
57
58   protected AbstractBuffer(Bytes bytes, int offset, int initialCapacity, int maxCapacity, ReferenceManager<Buffer> referenceManager) {
59     if (bytes == null) {
60       throw new NullPointerException("bytes cannot be null");
61     }
62     if (offset < 0) {
63       throw new IndexOutOfBoundsException("offset out of bounds of the underlying byte array");
64     }
65     this.bytes = bytes;
66     this.offset = offset;
67     this.capacity = 0;
68     this.initialCapacity = initialCapacity;
69     this.maxCapacity = maxCapacity;
70     capacity(initialCapacity);
71     this.referenceManager = referenceManager;
72     references.set(1);
73   }
74
75   /**
76    * Resets the buffer's internal offset and capacity.
77    */
78   protected AbstractBuffer reset(int offset, int capacity, int maxCapacity) {
79     this.offset = offset;
80     this.capacity = 0;
81     this.initialCapacity = capacity;
82     this.maxCapacity = maxCapacity;
83     capacity(initialCapacity);
84     references.set(0);
85     rewind();
86     return this;
87   }
88
89   @Override
90   public Buffer acquire() {
91     references.incrementAndGet();
92     return this;
93   }
94
95   @Override
96   public boolean release() {
97     if (references.decrementAndGet() == 0) {
98       if (referenceManager != null) {
99         referenceManager.release(this);
100       } else {
101         bytes.close();
102       }
103       return true;
104     }
105     return false;
106   }
107
108   @Override
109   public int references() {
110     return references.get();
111   }
112
113   @Override
114   public Bytes bytes() {
115     return bytes;
116   }
117
118   @Override
119   public ByteOrder order() {
120     return bytes.order();
121   }
122
123   @Override
124   public Buffer order(ByteOrder order) {
125     if (order == null) {
126       throw new NullPointerException("order cannot be null");
127     }
128     if (order == order()) {
129       return this;
130     }
131     if (swap != null) {
132       return swap;
133     }
134     swap = new SwappedBuffer(this, offset, capacity, maxCapacity, referenceManager);
135     return swap;
136   }
137
138   @Override
139   public boolean isDirect() {
140     return bytes.isDirect();
141   }
142
143   @Override
144   public boolean isFile() {
145     return bytes.isFile();
146   }
147
148   @Override
149   public boolean isReadOnly() {
150     return false;
151   }
152
153   @Override
154   public Buffer asReadOnlyBuffer() {
155     return new ReadOnlyBuffer(this, referenceManager)
156         .reset(offset, capacity, maxCapacity)
157         .position(position)
158         .limit(limit);
159   }
160
161   @Override
162   public Buffer compact() {
163     compact(offset(position), offset, (limit != -1 ? limit : capacity) - offset(position));
164     return clear();
165   }
166
167   /**
168    * Compacts the given bytes.
169    */
170   protected abstract void compact(int from, int to, int length);
171
172   @Override
173   public Buffer slice() {
174     int maxCapacity = this.maxCapacity - position;
175     int capacity = Math.min(Math.min(initialCapacity, maxCapacity), bytes.size() - offset(position));
176     if (limit != -1) {
177       capacity = maxCapacity = limit - position;
178     }
179     return new SlicedBuffer(this, bytes, offset(position), capacity, maxCapacity);
180   }
181
182   @Override
183   public Buffer slice(int length) {
184     checkSlice(position, length);
185     return new SlicedBuffer(this, bytes, offset(position), length, length);
186   }
187
188   @Override
189   public Buffer slice(int offset, int length) {
190     checkSlice(offset, length);
191     return new SlicedBuffer(this, bytes, offset(offset), length, length);
192   }
193
194   @Override
195   public int offset() {
196     return offset;
197   }
198
199   @Override
200   public int capacity() {
201     return capacity;
202   }
203
204   /**
205    * Updates the buffer capacity.
206    */
207   public Buffer capacity(int capacity) {
208     if (capacity > maxCapacity) {
209       throw new IllegalArgumentException("capacity cannot be greater than maximum capacity");
210     } else if (capacity < this.capacity) {
211       throw new IllegalArgumentException("capacity cannot be decreased");
212     } else if (capacity != this.capacity) {
213       // It's possible that the bytes could already meet the requirements of the capacity.
214       if (offset(capacity) > bytes.size()) {
215         bytes.resize((int) Math.min(Memory.Util.toPow2(offset(capacity)), Integer.MAX_VALUE));
216       }
217       this.capacity = capacity;
218     }
219     return this;
220   }
221
222   @Override
223   public int maxCapacity() {
224     return maxCapacity;
225   }
226
227   @Override
228   public int position() {
229     return position;
230   }
231
232   @Override
233   public Buffer position(int position) {
234     if (limit != -1 && position > limit) {
235       throw new IllegalArgumentException("position cannot be greater than limit");
236     } else if (limit == -1 && position > maxCapacity) {
237       throw new IllegalArgumentException("position cannot be greater than capacity");
238     }
239     if (position > capacity) {
240       capacity((int) Math.min(maxCapacity, Memory.Util.toPow2(position)));
241     }
242     this.position = position;
243     return this;
244   }
245
246   /**
247    * Returns the real offset of the given relative offset.
248    */
249   private int offset(int offset) {
250     return this.offset + offset;
251   }
252
253   @Override
254   public int limit() {
255     return limit;
256   }
257
258   @Override
259   public Buffer limit(int limit) {
260     if (limit > maxCapacity) {
261       throw new IllegalArgumentException("limit cannot be greater than buffer capacity");
262     }
263     if (limit < -1) {
264       throw new IllegalArgumentException("limit cannot be negative");
265     }
266     if (limit != -1 && offset(limit) > bytes.size()) {
267       bytes.resize(offset(limit));
268     }
269     this.limit = limit;
270     return this;
271   }
272
273   @Override
274   public int remaining() {
275     return (limit == -1 ? maxCapacity : limit) - position;
276   }
277
278   @Override
279   public boolean hasRemaining() {
280     return remaining() > 0;
281   }
282
283   @Override
284   public Buffer flip() {
285     limit = position;
286     position = 0;
287     mark = -1;
288     return this;
289   }
290
291   @Override
292   public Buffer mark() {
293     this.mark = position;
294     return this;
295   }
296
297   @Override
298   public Buffer rewind() {
299     position = 0;
300     mark = -1;
301     return this;
302   }
303
304   @Override
305   public Buffer reset() {
306     if (mark == -1) {
307       throw new InvalidMarkException();
308     }
309     position = mark;
310     return this;
311   }
312
313   @Override
314   public Buffer skip(int length) {
315     if (length > remaining()) {
316       throw new IndexOutOfBoundsException("length cannot be greater than remaining bytes in the buffer");
317     }
318     position += length;
319     return this;
320   }
321
322   @Override
323   public Buffer clear() {
324     position = 0;
325     limit = -1;
326     mark = -1;
327     return this;
328   }
329
330   /**
331    * Checks that the offset is within the bounds of the buffer.
332    */
333   protected void checkOffset(int offset) {
334     if (offset(offset) < this.offset) {
335       throw new IndexOutOfBoundsException();
336     } else if (limit == -1) {
337       if (offset > maxCapacity) {
338         throw new IndexOutOfBoundsException();
339       }
340     } else {
341       if (offset > limit) {
342         throw new IndexOutOfBoundsException();
343       }
344     }
345   }
346
347   /**
348    * Checks bounds for a slice.
349    */
350   protected int checkSlice(int offset, int length) {
351     checkOffset(offset);
352     if (limit == -1) {
353       if (offset + length > capacity) {
354         if (capacity < maxCapacity) {
355           capacity(calculateCapacity(offset + length));
356         } else {
357           throw new BufferUnderflowException();
358         }
359       }
360     } else {
361       if (offset + length > limit) {
362         throw new BufferUnderflowException();
363       }
364     }
365     return offset(offset);
366   }
367
368   /**
369    * Checks bounds for a read for the given length.
370    */
371   protected int checkRead(int length) {
372     checkRead(position, length);
373     int previousPosition = this.position;
374     this.position = previousPosition + length;
375     return offset(previousPosition);
376   }
377
378   /**
379    * Checks bounds for a read.
380    */
381   protected int checkRead(int offset, int length) {
382     checkOffset(offset);
383     if (limit == -1) {
384       if (offset + length > capacity) {
385         if (capacity < maxCapacity) {
386           if (this.offset + offset + length <= bytes.size()) {
387             capacity = bytes.size() - this.offset;
388           } else {
389             capacity(calculateCapacity(offset + length));
390           }
391         } else {
392           throw new BufferUnderflowException();
393         }
394       }
395     } else {
396       if (offset + length > limit) {
397         throw new BufferUnderflowException();
398       }
399     }
400     return offset(offset);
401   }
402
403   /**
404    * Checks bounds for a write of the given length.
405    */
406   protected int checkWrite(int length) {
407     checkWrite(position, length);
408     int previousPosition = this.position;
409     this.position = previousPosition + length;
410     return offset(previousPosition);
411   }
412
413   /**
414    * Checks bounds for a write.
415    */
416   protected int checkWrite(int offset, int length) {
417     checkOffset(offset);
418     if (limit == -1) {
419       if (offset + length > capacity) {
420         if (capacity < maxCapacity) {
421           capacity(calculateCapacity(offset + length));
422         } else {
423           throw new BufferOverflowException();
424         }
425       }
426     } else {
427       if (offset + length > limit) {
428         throw new BufferOverflowException();
429       }
430     }
431     return offset(offset);
432   }
433
434   /**
435    * Calculates the next capacity that meets the given minimum capacity.
436    */
437   private int calculateCapacity(int minimumCapacity) {
438     int newCapacity = Math.min(Math.max(capacity, 2), minimumCapacity);
439     while (newCapacity < Math.min(minimumCapacity, maxCapacity)) {
440       newCapacity <<= 1;
441     }
442     return Math.min(newCapacity, maxCapacity);
443   }
444
445   @Override
446   public Buffer zero() {
447     bytes.zero(offset);
448     return this;
449   }
450
451   @Override
452   public Buffer zero(int offset) {
453     checkOffset(offset);
454     bytes.zero(offset(offset));
455     return this;
456   }
457
458   @Override
459   public Buffer zero(int offset, int length) {
460     checkOffset(offset);
461     bytes.zero(offset(offset), length);
462     return this;
463   }
464
465   @Override
466   public Buffer read(Buffer buffer) {
467     int length = Math.min(buffer.remaining(), remaining());
468     read(buffer.bytes(), buffer.offset() + buffer.position(), length);
469     buffer.position(buffer.position() + length);
470     return this;
471   }
472
473   @Override
474   public Buffer read(Bytes bytes) {
475     this.bytes.read(checkRead(bytes.size()), bytes, 0, bytes.size());
476     return this;
477   }
478
479   @Override
480   public Buffer read(Bytes bytes, int offset, int length) {
481     this.bytes.read(checkRead(length), bytes, offset, length);
482     return this;
483   }
484
485   @Override
486   public Buffer read(int srcOffset, Bytes bytes, int dstOffset, int length) {
487     this.bytes.read(checkRead(srcOffset, length), bytes, dstOffset, length);
488     return this;
489   }
490
491   @Override
492   public Buffer read(byte[] bytes) {
493     this.bytes.read(checkRead(bytes.length), bytes, 0, bytes.length);
494     return this;
495   }
496
497   @Override
498   public Buffer read(byte[] bytes, int offset, int length) {
499     this.bytes.read(checkRead(length), bytes, offset, length);
500     return this;
501   }
502
503   @Override
504   public Buffer read(int srcOffset, byte[] bytes, int dstOffset, int length) {
505     this.bytes.read(checkRead(srcOffset, length), bytes, dstOffset, length);
506     return this;
507   }
508
509   @Override
510   public int readByte() {
511     return bytes.readByte(checkRead(BYTE));
512   }
513
514   @Override
515   public int readByte(int offset) {
516     return bytes.readByte(checkRead(offset, BYTE));
517   }
518
519   @Override
520   public int readUnsignedByte() {
521     return bytes.readUnsignedByte(checkRead(BYTE));
522   }
523
524   @Override
525   public int readUnsignedByte(int offset) {
526     return bytes.readUnsignedByte(checkRead(offset, BYTE));
527   }
528
529   @Override
530   public char readChar() {
531     return bytes.readChar(checkRead(Bytes.CHARACTER));
532   }
533
534   @Override
535   public char readChar(int offset) {
536     return bytes.readChar(checkRead(offset, Bytes.CHARACTER));
537   }
538
539   @Override
540   public short readShort() {
541     return bytes.readShort(checkRead(SHORT));
542   }
543
544   @Override
545   public short readShort(int offset) {
546     return bytes.readShort(checkRead(offset, SHORT));
547   }
548
549   @Override
550   public int readUnsignedShort() {
551     return bytes.readUnsignedShort(checkRead(SHORT));
552   }
553
554   @Override
555   public int readUnsignedShort(int offset) {
556     return bytes.readUnsignedShort(checkRead(offset, SHORT));
557   }
558
559   @Override
560   public int readMedium() {
561     return bytes.readMedium(checkRead(3));
562   }
563
564   @Override
565   public int readMedium(int offset) {
566     return bytes.readMedium(checkRead(offset, 3));
567   }
568
569   @Override
570   public int readUnsignedMedium() {
571     return bytes.readUnsignedMedium(checkRead(3));
572   }
573
574   @Override
575   public int readUnsignedMedium(int offset) {
576     return bytes.readUnsignedMedium(checkRead(offset, 3));
577   }
578
579   @Override
580   public int readInt() {
581     return bytes.readInt(checkRead(Bytes.INTEGER));
582   }
583
584   @Override
585   public int readInt(int offset) {
586     return bytes.readInt(checkRead(offset, Bytes.INTEGER));
587   }
588
589   @Override
590   public long readUnsignedInt() {
591     return bytes.readUnsignedInt(checkRead(Bytes.INTEGER));
592   }
593
594   @Override
595   public long readUnsignedInt(int offset) {
596     return bytes.readUnsignedInt(checkRead(offset, Bytes.INTEGER));
597   }
598
599   @Override
600   public long readLong() {
601     return bytes.readLong(checkRead(Bytes.LONG));
602   }
603
604   @Override
605   public long readLong(int offset) {
606     return bytes.readLong(checkRead(offset, Bytes.LONG));
607   }
608
609   @Override
610   public float readFloat() {
611     return bytes.readFloat(checkRead(Bytes.FLOAT));
612   }
613
614   @Override
615   public float readFloat(int offset) {
616     return bytes.readFloat(checkRead(offset, Bytes.FLOAT));
617   }
618
619   @Override
620   public double readDouble() {
621     return bytes.readDouble(checkRead(Bytes.DOUBLE));
622   }
623
624   @Override
625   public double readDouble(int offset) {
626     return bytes.readDouble(checkRead(offset, Bytes.DOUBLE));
627   }
628
629   @Override
630   public boolean readBoolean() {
631     return bytes.readBoolean(checkRead(BYTE));
632   }
633
634   @Override
635   public boolean readBoolean(int offset) {
636     return bytes.readBoolean(checkRead(offset, BYTE));
637   }
638
639   @Override
640   public String readString(Charset charset) {
641     if (readBoolean(position)) {
642       byte[] bytes = new byte[readUnsignedShort(position + BOOLEAN)];
643       read(position + BOOLEAN + SHORT, bytes, 0, bytes.length);
644       this.position += BOOLEAN + SHORT + bytes.length;
645       return new String(bytes, charset);
646     } else {
647       this.position += BOOLEAN;
648     }
649     return null;
650   }
651
652   @Override
653   public String readString(int offset, Charset charset) {
654     if (readBoolean(offset)) {
655       byte[] bytes = new byte[readUnsignedShort(offset + BOOLEAN)];
656       read(offset + BOOLEAN + SHORT, bytes, 0, bytes.length);
657       return new String(bytes, charset);
658     }
659     return null;
660   }
661
662   @Override
663   public String readString() {
664     return readString(Charset.defaultCharset());
665   }
666
667   @Override
668   public String readString(int offset) {
669     return readString(offset, Charset.defaultCharset());
670   }
671
672   @Override
673   public String readUTF8() {
674     return readString(StandardCharsets.UTF_8);
675   }
676
677   @Override
678   public String readUTF8(int offset) {
679     return readString(offset, StandardCharsets.UTF_8);
680   }
681
682   @Override
683   public Buffer write(Buffer buffer) {
684     int length = Math.min(buffer.remaining(), remaining());
685     write(buffer.bytes(), buffer.offset() + buffer.position(), length);
686     buffer.position(buffer.position() + length);
687     return this;
688   }
689
690   @Override
691   public Buffer write(Bytes bytes) {
692     this.bytes.write(checkWrite(bytes.size()), bytes, 0, bytes.size());
693     return this;
694   }
695
696   @Override
697   public Buffer write(Bytes bytes, int offset, int length) {
698     this.bytes.write(checkWrite(length), bytes, offset, length);
699     return this;
700   }
701
702   @Override
703   public Buffer write(int offset, Bytes bytes, int srcOffset, int length) {
704     this.bytes.write(checkWrite(offset, length), bytes, srcOffset, length);
705     return this;
706   }
707
708   @Override
709   public Buffer write(byte[] bytes) {
710     this.bytes.write(checkWrite(bytes.length), bytes, 0, bytes.length);
711     return this;
712   }
713
714   @Override
715   public Buffer write(byte[] bytes, int offset, int length) {
716     this.bytes.write(checkWrite(length), bytes, offset, length);
717     return this;
718   }
719
720   @Override
721   public Buffer write(int offset, byte[] bytes, int srcOffset, int length) {
722     this.bytes.write(checkWrite(offset, length), bytes, srcOffset, length);
723     return this;
724   }
725
726   @Override
727   public Buffer writeByte(int b) {
728     bytes.writeByte(checkWrite(BYTE), b);
729     return this;
730   }
731
732   @Override
733   public Buffer writeByte(int offset, int b) {
734     bytes.writeByte(checkWrite(offset, BYTE), b);
735     return this;
736   }
737
738   @Override
739   public Buffer writeUnsignedByte(int b) {
740     bytes.writeUnsignedByte(checkWrite(BYTE), b);
741     return this;
742   }
743
744   @Override
745   public Buffer writeUnsignedByte(int offset, int b) {
746     bytes.writeUnsignedByte(checkWrite(offset, BYTE), b);
747     return this;
748   }
749
750   @Override
751   public Buffer writeChar(char c) {
752     bytes.writeChar(checkWrite(Bytes.CHARACTER), c);
753     return this;
754   }
755
756   @Override
757   public Buffer writeChar(int offset, char c) {
758     bytes.writeChar(checkWrite(offset, Bytes.CHARACTER), c);
759     return this;
760   }
761
762   @Override
763   public Buffer writeShort(short s) {
764     bytes.writeShort(checkWrite(SHORT), s);
765     return this;
766   }
767
768   @Override
769   public Buffer writeShort(int offset, short s) {
770     bytes.writeShort(checkWrite(offset, SHORT), s);
771     return this;
772   }
773
774   @Override
775   public Buffer writeUnsignedShort(int s) {
776     bytes.writeUnsignedShort(checkWrite(SHORT), s);
777     return this;
778   }
779
780   @Override
781   public Buffer writeUnsignedShort(int offset, int s) {
782     bytes.writeUnsignedShort(checkWrite(offset, SHORT), s);
783     return this;
784   }
785
786   @Override
787   public Buffer writeMedium(int m) {
788     bytes.writeMedium(checkWrite(3), m);
789     return this;
790   }
791
792   @Override
793   public Buffer writeMedium(int offset, int m) {
794     bytes.writeMedium(checkWrite(offset, 3), m);
795     return this;
796   }
797
798   @Override
799   public Buffer writeUnsignedMedium(int m) {
800     bytes.writeUnsignedMedium(checkWrite(3), m);
801     return this;
802   }
803
804   @Override
805   public Buffer writeUnsignedMedium(int offset, int m) {
806     bytes.writeUnsignedMedium(checkWrite(offset, 3), m);
807     return this;
808   }
809
810   @Override
811   public Buffer writeInt(int i) {
812     bytes.writeInt(checkWrite(Bytes.INTEGER), i);
813     return this;
814   }
815
816   @Override
817   public Buffer writeInt(int offset, int i) {
818     bytes.writeInt(checkWrite(offset, Bytes.INTEGER), i);
819     return this;
820   }
821
822   @Override
823   public Buffer writeUnsignedInt(long i) {
824     bytes.writeUnsignedInt(checkWrite(Bytes.INTEGER), i);
825     return this;
826   }
827
828   @Override
829   public Buffer writeUnsignedInt(int offset, long i) {
830     bytes.writeUnsignedInt(checkWrite(offset, Bytes.INTEGER), i);
831     return this;
832   }
833
834   @Override
835   public Buffer writeLong(long l) {
836     bytes.writeLong(checkWrite(Bytes.LONG), l);
837     return this;
838   }
839
840   @Override
841   public Buffer writeLong(int offset, long l) {
842     bytes.writeLong(checkWrite(offset, Bytes.LONG), l);
843     return this;
844   }
845
846   @Override
847   public Buffer writeFloat(float f) {
848     bytes.writeFloat(checkWrite(Bytes.FLOAT), f);
849     return this;
850   }
851
852   @Override
853   public Buffer writeFloat(int offset, float f) {
854     bytes.writeFloat(checkWrite(offset, Bytes.FLOAT), f);
855     return this;
856   }
857
858   @Override
859   public Buffer writeDouble(double d) {
860     bytes.writeDouble(checkWrite(Bytes.DOUBLE), d);
861     return this;
862   }
863
864   @Override
865   public Buffer writeDouble(int offset, double d) {
866     bytes.writeDouble(checkWrite(offset, Bytes.DOUBLE), d);
867     return this;
868   }
869
870   @Override
871   public Buffer writeBoolean(boolean b) {
872     bytes.writeBoolean(checkWrite(BYTE), b);
873     return this;
874   }
875
876   @Override
877   public Buffer writeBoolean(int offset, boolean b) {
878     bytes.writeBoolean(checkWrite(offset, BYTE), b);
879     return this;
880   }
881
882   @Override
883   public Buffer writeString(String s, Charset charset) {
884     if (s == null) {
885       return writeBoolean(checkWrite(BOOLEAN), Boolean.FALSE);
886     } else {
887       byte[] bytes = s.getBytes(charset);
888       checkWrite(position, BOOLEAN + SHORT + bytes.length);
889       writeBoolean(Boolean.TRUE)
890           .writeUnsignedShort(bytes.length)
891           .write(bytes, 0, bytes.length);
892       return this;
893     }
894   }
895
896   @Override
897   public Buffer writeString(int offset, String s, Charset charset) {
898     if (s == null) {
899       return writeBoolean(checkWrite(offset, BOOLEAN), Boolean.FALSE);
900     } else {
901       byte[] bytes = s.getBytes(charset);
902       checkWrite(offset, BOOLEAN + SHORT + bytes.length);
903       writeBoolean(offset, Boolean.TRUE)
904           .writeUnsignedShort(offset + BOOLEAN, bytes.length)
905           .write(offset + BOOLEAN + SHORT, bytes, 0, bytes.length);
906       return this;
907     }
908   }
909
910   @Override
911   public Buffer writeString(String s) {
912     return writeString(s, Charset.defaultCharset());
913   }
914
915   @Override
916   public Buffer writeString(int offset, String s) {
917     return writeString(offset, s, Charset.defaultCharset());
918   }
919
920   @Override
921   public Buffer writeUTF8(String s) {
922     return writeString(s, StandardCharsets.UTF_8);
923   }
924
925   @Override
926   public Buffer writeUTF8(int offset, String s) {
927     return writeString(offset, s, StandardCharsets.UTF_8);
928   }
929
930   @Override
931   public Buffer flush() {
932     bytes.flush();
933     return this;
934   }
935
936   @Override
937   public void close() {
938     references.set(0);
939     if (referenceManager != null) {
940       referenceManager.release(this);
941     } else {
942       bytes.close();
943     }
944   }
945
946 }