HCOLL-136 HCOLL-137 Improved BytesReader, BytesWriter and BytesInterop docs [dc]

This commit is contained in:
leventov
2014-11-07 14:16:31 +03:00
parent 28d20d03b6
commit f96d369cdd
22 changed files with 339 additions and 49 deletions
@@ -22,15 +22,30 @@ import net.openhft.lang.io.Bytes;
import net.openhft.lang.model.Byteable;
/**
* Marshaller for byte sequences, which are copied to off-heap {@link Bytes}
* in a very straightforward manner, e. g. {@link Byteable Byteables}, {@code byte[]} arrays,
* {@code Bytes} themselves. The criterion of this interface applicability --
* {@link Object#equals(Object)} implementation shouldn't require deserialization and any garbage creation.
* Writer for objects, which themselves are bytes sequence in some sense:
* {@link Byteable Byteables}, {@code byte[]} arrays, other primitive arrays, "flat" objects
* (with primitives fields only), particularly boxed primitive types.
*
* <p>This interface is called "BytesInterop" because it allows to work with object as they
* are already marshalled to {@code Bytes}: {@linkplain #startsWith(Bytes, Object) compare}
* with other {@code Bytes}, i. e. interoperate objects and {@code Bytes}.
*
* @param <E> type of marshalled objects
*/
public interface BytesInterop<E> extends BytesWriter<E> {
/**
* Checks if the given {@code bytes} starts (from the {@code bytes}' {@linkplain
* Bytes#position() position}) with the byte sequence the given object
* {@linkplain #write(Bytes, Object) is serialized} to, without actual serialization.
*
* @param bytes the bytes to check if starts with the serialized form of the given object.
* {@code bytes}' is positioned at the first byte to compare. {@code bytes}' limit
* is unspecified. {@code bytes}' position and limit shouldn't be altered during
* this call.
* @param e the object to serialize virtually and compare with the given {@code bytes}
* @return if the given {@code bytes} starts with the given {@code e} object's serialized form
*/
boolean startsWith(Bytes bytes, E e);
long hash(E e);
@@ -18,13 +18,86 @@
package net.openhft.chronicle.hash.serialization;
import net.openhft.chronicle.hash.ChronicleHash;
import net.openhft.lang.io.Bytes;
import org.jetbrains.annotations.Nullable;
import java.io.Serializable;
/**
* Deserializer (object from {@link Bytes}, mirroring the {@link BytesWriter}, i. e. assuming the
* length of the serialized form isn't written in the beginning of the serialized form itself,
* but managed by {@link ChronicleHash} implementation and passed to the reading methods.
*
* <p>Implementation example:<pre><code>
* class LongPair { long first, second; }
*
* enum LongPairArrayReader implements BytesReader&lt;LongPair[]&gt; {
* INSTANCE;
*
* &#064;Override
* public LongPair[] read(Bytes bytes, long size) {
* return read(bytes, size, null);
* }
*
* &#064;Override
* public LongPair[] read(Bytes bytes, long size, LongPair[] toReuse) {
* int resLen = (int) (size / 16L);
* LongPair[] res;
* if (toReuse != null) {
* if (toReuse.length == resLen) {
* res = toReuse;
* } else {
* res = Arrays.copyOf(toReuse, resLen);
* }
* } else {
* res = new LongPair[resLen];
* }
* for (int i = 0; i < resLen; i++) {
* LongPair pair = res[i];
* if (pair == null)
* res[i] = pair = new LongPair();
* pair.first = bytes.readLong();
* pair.second = bytes.readLong();
* }
* return res;
* }
* }</code></pre>
*
* @param <E> the type of the object demarshalled
* @see BytesWriter
*/
public interface BytesReader<E> extends Serializable {
/**
* Reads and returns the object from {@code [position(), position() + size]} bytes of the given
* {@link Bytes}.
*
* <p>Implementation of this method should increment the {@code bytes}' position by the given
* size, i. e. "consume" the bytes of the deserialized object. It must not alter the
* {@code bytes}' {@link Bytes#limit() limit} and contents.
*
* @param bytes the {@code Bytes} to read the object from
* @param size the size of the serialized form of the returned object
* @return the object read from the bytes
* @see BytesWriter#write(Bytes, Object)
* @see #read(Bytes, long, Object)
*/
E read(Bytes bytes, long size);
E read(Bytes bytes, long size, E e);
/**
* Similar to {@link #read(Bytes, long)}, but should attempt to reuse the given object, i. e.
* to read the deserialized data into the given instance. If it is possible, this objects than
* returned from this method. If it isn't possible for any reason, a new object should be
* created and returned, just like in {@link #read(Bytes, long)} method. The given object could
* be {@code null}, in this case this method should behave exactly the same as
* {@link #read(Bytes, long)} method does.
*
* @param bytes the {@code Bytes} to read the object from
* @param size the size of the serialized form of the returned object
* @param toReuse the object to read the deserialized data into
* @return the object read from the bytes, either reused or newly created
* @see #read(Bytes, long)
*/
E read(Bytes bytes, long size, @Nullable E toReuse);
}
@@ -18,13 +18,66 @@
package net.openhft.chronicle.hash.serialization;
import net.openhft.chronicle.hash.ChronicleHash;
import net.openhft.lang.io.Bytes;
import java.io.Serializable;
/**
* Serializer (object to {@link Bytes} writer) which 1) knows the length of serialized form
* of any object before actual serialization 2) doesn't include that length in the serialized
* form itself, assuming it will be passed by the {@link ChronicleHash} into
* {@link BytesReader#read(Bytes, long)} deserialization method.
*
* <p>Implementation example: <pre><code>
* class LongPair { long first, second; }
*
* enum LongPairArrayWriter implements BytesWriter&lt;LongPair[]&gt; {
* INSTANCE;
*
* &#064;Override
* public long size(LongPair[] longPairs) {
* return longPairs.length * 16L;
* }
*
* &#064;Override
* public void write(Bytes bytes, LongPair[] longPairs) {
* for (LongPair pair : longPairs) {
* bytes.writeLong(pair.first);
* bytes.writeLong(pair.second);
* }
* }
* }</code></pre>
*
* @param <E> the type of the object marshalled
* @see BytesReader
* @see BytesInterop
*/
public interface BytesWriter<E> extends Serializable {
/**
* Returns the length (in bytes) of the serialized form of the given object. Serialization form
* in terms of this interface, i. e. how much bytes are written to {@code bytes} on
* {@link #write(Bytes, Object) write(bytes, e)} call.
*
* @param e the object which serialized form length should be returned
* @return the length (in bytes) of the serialized form of the given object
*/
long size(E e);
/**
* Serializes the given object to the given {@code bytes}, without writing the length of the
* serialized form itself.
*
* <p>Implementation of this method should increment the {@code bytes}' {@linkplain
* Bytes#position() position} by {@link #size(Object) size(e)}. The given object should
* be written into these range between the initial {@code bytes}' position and the position
* after this method call returns. Implementation of this method must not alter the
* {@code bytes}' {@linkplain Bytes#limit() limit} and contents outside of the specified range.
*
* @param bytes the {@code Bytes} to write the given object to
* @param e the object to serialize to the given bytes
* @see BytesReader#read(Bytes, long)
*/
void write(Bytes bytes, E e);
}
@@ -16,7 +16,7 @@
* limitations under the License.
*/
package net.openhft.chronicle.hash.serialization.impl;
package net.openhft.chronicle.hash.serialization.internal;
import net.openhft.chronicle.hash.serialization.BytesInterop;
import net.openhft.chronicle.hash.serialization.BytesReader;
@@ -59,10 +59,10 @@ public enum ByteArrayMarshaller implements BytesInterop<byte[]>, BytesReader<byt
}
@Override
public byte[] read(Bytes bytes, long size, byte[] ba) {
if (ba == null || size != ba.length)
ba = new byte[(int) size];
bytes.read(ba);
return ba;
public byte[] read(Bytes bytes, long size, byte[] toReuse) {
if (toReuse == null || size != toReuse.length)
toReuse = new byte[(int) size];
bytes.read(toReuse);
return toReuse;
}
}
@@ -16,7 +16,7 @@
* limitations under the License.
*/
package net.openhft.chronicle.hash.serialization.impl;
package net.openhft.chronicle.hash.serialization.internal;
import net.openhft.chronicle.hash.serialization.AgileBytesMarshaller;
import net.openhft.chronicle.hash.serialization.Hasher;
@@ -114,13 +114,13 @@ public class ByteableMarshaller<E extends Byteable> implements AgileBytesMarshal
}
@Override
public E read(Bytes bytes, long size, E e) {
public E read(Bytes bytes, long size, E toReuse) {
try {
if (e == null)
e = getInstance();
setBytesAndOffset(e, bytes);
if (toReuse == null)
toReuse = getInstance();
setBytesAndOffset(toReuse, bytes);
bytes.skip(size);
return e;
return toReuse;
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
@@ -16,13 +16,27 @@
* limitations under the License.
*/
package net.openhft.chronicle.hash.serialization;
package net.openhft.chronicle.hash.serialization.internal;
import net.openhft.chronicle.hash.serialization.BytesReader;
import net.openhft.lang.io.Bytes;
import net.openhft.lang.io.serialization.BytesMarshaller;
/**
* Utility methods returning {@link BytesReader} implementations.
*/
public final class BytesReaders {
/**
* Returns a {@link BytesReader} wrapping the given {@link BytesMarshaller}. One of the
* bridge methods between general serialization API from {@link net.openhft.lang} and
* reader - writer - interop API, specific for ChronicleHashes,
* from {@link net.openhft.chronicle.hash.serialization} package.
*
* @param marshaller the actual reading implementation
* @param <E> type of the objects marshalled
* @return a {@code BytesReader} wrapping the given {@code BytesMarshaller}
*/
public static <E> BytesReader<E> fromBytesMarshaller(BytesMarshaller<E> marshaller) {
return new SimpleBytesReader<E>(marshaller);
}
@@ -42,8 +56,8 @@ public final class BytesReaders {
}
@Override
public E read(Bytes bytes, long size, E e) {
return marshaller.read(bytes, e);
public E read(Bytes bytes, long size, E toReuse) {
return marshaller.read(bytes, toReuse);
}
}
@@ -16,7 +16,7 @@
* limitations under the License.
*/
package net.openhft.chronicle.hash.serialization.impl;
package net.openhft.chronicle.hash.serialization.internal;
import net.openhft.chronicle.hash.serialization.BytesInterop;
import net.openhft.chronicle.hash.serialization.BytesReader;
@@ -49,11 +49,11 @@ public enum CharArrayMarshaller implements BytesInterop<char[]>, BytesReader<cha
}
@Override
public char[] read(Bytes bytes, long size, char[] chars) {
if (chars == null || chars.length != size)
chars = new char[(int) size];
bytes.readFully(chars);
return chars;
public char[] read(Bytes bytes, long size, char[] toReuse) {
if (toReuse == null || toReuse.length != size)
toReuse = new char[(int) size];
bytes.readFully(toReuse);
return toReuse;
}
@Override
@@ -16,7 +16,7 @@
* limitations under the License.
*/
package net.openhft.chronicle.hash.serialization.impl;
package net.openhft.chronicle.hash.serialization.internal;
import net.openhft.chronicle.hash.serialization.BytesReader;
import net.openhft.lang.io.AbstractBytes;
@@ -78,14 +78,14 @@ public final class CharSequenceReader<S extends CharSequence>
}
@Override
public S read(Bytes bytes, long size, S s) {
public S read(Bytes bytes, long size, S toReuse) {
Appendable appendable;
if (s instanceof Appendable) {
appendable = (Appendable) s;
if (s instanceof StringBuilder) {
((StringBuilder) s).setLength(0);
} else if (s instanceof StringBuffer) {
((StringBuffer) s).setLength(0);
if (toReuse instanceof Appendable) {
appendable = (Appendable) toReuse;
if (toReuse instanceof StringBuilder) {
((StringBuilder) toReuse).setLength(0);
} else if (toReuse instanceof StringBuffer) {
((StringBuffer) toReuse).setLength(0);
}
} else {
sb.setLength(0);
@@ -96,8 +96,8 @@ public final class CharSequenceReader<S extends CharSequence>
} catch (IOException e) {
throw new IllegalStateException(e);
}
if (appendable == s)
return s;
if (appendable == toReuse)
return toReuse;
return interner.intern(sb);
}
@@ -16,7 +16,7 @@
* limitations under the License.
*/
package net.openhft.chronicle.hash.serialization.impl;
package net.openhft.chronicle.hash.serialization.internal;
import net.openhft.chronicle.hash.serialization.BytesWriter;
import net.openhft.lang.io.AbstractBytes;
@@ -16,7 +16,7 @@
* limitations under the License.
*/
package net.openhft.chronicle.hash.serialization.impl;
package net.openhft.chronicle.hash.serialization.internal;
import net.openhft.chronicle.hash.serialization.AgileBytesMarshaller;
import net.openhft.chronicle.hash.serialization.Hasher;
@@ -68,7 +68,7 @@ public enum DoubleMarshaller implements AgileBytesMarshaller<Double> {
}
@Override
public Double read(Bytes bytes, long size, Double e) {
public Double read(Bytes bytes, long size, Double toReuse) {
return read(bytes, size);
}
}
@@ -16,7 +16,7 @@
* limitations under the License.
*/
package net.openhft.chronicle.hash.serialization.impl;
package net.openhft.chronicle.hash.serialization.internal;
import net.openhft.chronicle.hash.serialization.AgileBytesMarshaller;
import net.openhft.chronicle.hash.serialization.Hasher;
@@ -66,7 +66,7 @@ public enum IntegerMarshaller implements AgileBytesMarshaller<Integer> {
}
@Override
public Integer read(Bytes bytes, long size, Integer e) {
public Integer read(Bytes bytes, long size, Integer toReuse) {
return bytes.readInt();
}
}
@@ -16,7 +16,7 @@
* limitations under the License.
*/
package net.openhft.chronicle.hash.serialization.impl;
package net.openhft.chronicle.hash.serialization.internal;
import net.openhft.chronicle.hash.serialization.AgileBytesMarshaller;
import net.openhft.chronicle.hash.serialization.Hasher;
@@ -66,7 +66,7 @@ public enum LongMarshaller implements AgileBytesMarshaller<Long> {
}
@Override
public Long read(Bytes bytes, long size, Long e) {
public Long read(Bytes bytes, long size, Long toReuse) {
return bytes.readLong();
}
}
@@ -16,7 +16,7 @@
* limitations under the License.
*/
package net.openhft.chronicle.hash.serialization.impl;
package net.openhft.chronicle.hash.serialization.internal;
import net.openhft.chronicle.hash.serialization.AgileBytesMarshaller;
import net.openhft.lang.io.Bytes;
@@ -66,7 +66,7 @@ public enum VoidMarshaller implements AgileBytesMarshaller<Void> {
}
@Override
public Void read(Bytes bytes, long size, Void aVoid) {
public Void read(Bytes bytes, long size, Void toReuse) {
return null;
}
@@ -0,0 +1,22 @@
/*
* Copyright 2014 Higher Frequency Trading http://www.higherfrequencytrading.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Classes, which should be part of the parent {@code net.openhft.chronicle.hash.serialization}
* package, but shouldn't be used in the user code (in 99% of cases). This package isn't
* documented in published javadocs.
*/
package net.openhft.chronicle.hash.serialization.internal;
@@ -21,7 +21,7 @@ package net.openhft.chronicle.map;
import net.openhft.lang.threadlocal.Provider;
import net.openhft.lang.threadlocal.ThreadLocalCopies;
import net.openhft.chronicle.hash.serialization.*;
import net.openhft.chronicle.hash.serialization.impl.*;
import net.openhft.chronicle.hash.serialization.internal.*;
import net.openhft.lang.io.Bytes;
import net.openhft.lang.io.serialization.BytesMarshallable;
import net.openhft.lang.io.serialization.BytesMarshaller;
@@ -42,7 +42,7 @@ enum DummyValueMarshaller implements AgileBytesMarshaller<DummyValue> {
}
@Override
public DummyValue read(Bytes bytes, long size, DummyValue dummyValue) {
public DummyValue read(Bytes bytes, long size, DummyValue toReuse) {
return DUMMY_VALUE;
}