working on more data structures
This commit is contained in:
parent
5a0fe36e18
commit
8ebb1a8e69
772 changed files with 198255 additions and 145 deletions
202
LICENSE.txt
Normal file
202
LICENSE.txt
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
|
@ -28,6 +28,7 @@ subprojects {
|
|||
apply from: rootProject.file('gradle/ide/idea.gradle')
|
||||
apply from: rootProject.file('gradle/compile/java.gradle')
|
||||
apply from: rootProject.file('gradle/test/junit5.gradle')
|
||||
apply from: rootProject.file('gradle/test/jmh.gradle')
|
||||
apply from: rootProject.file('gradle/publishing/publication.gradle')
|
||||
}
|
||||
|
||||
|
|
6
datastructures-bytes/build.gradle
Normal file
6
datastructures-bytes/build.gradle
Normal file
|
@ -0,0 +1,6 @@
|
|||
dependencies {
|
||||
api "net.openhft:chronicle-core:2.21ea14"
|
||||
testImplementation "org.junit.vintage:junit-vintage-engine:5.7.0"
|
||||
testImplementation "junit:junit:4.13"
|
||||
testImplementation "net.openhft:affinity:3.21ea0"
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.bytes.algo.BytesStoreHash;
|
||||
import net.openhft.chronicle.core.io.AbstractReferenceCounted;
|
||||
|
||||
import java.nio.BufferUnderflowException;
|
||||
|
||||
public abstract class AbstractBytesStore<B extends BytesStore<B, Underlying>, Underlying>
|
||||
extends AbstractReferenceCounted
|
||||
implements BytesStore<B, Underlying> {
|
||||
|
||||
protected AbstractBytesStore() {
|
||||
}
|
||||
|
||||
protected AbstractBytesStore(boolean monitored) {
|
||||
super(monitored);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int peekUnsignedByte(long offset) throws BufferUnderflowException {
|
||||
return offset >= readLimit() ? -1 : readUnsignedByte(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return BytesStoreHash.hash32(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readPosition() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readRemaining() {
|
||||
return readLimit() - readPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long writeRemaining() {
|
||||
return writeLimit() - writePosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long start() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean performReleaseInBackground() {
|
||||
return isDirectMemory();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import net.openhft.chronicle.core.annotation.ForceInline;
|
||||
import net.openhft.chronicle.core.annotation.Java9;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UTFDataFormatException;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public enum AppendableUtil {
|
||||
;
|
||||
|
||||
public static void setCharAt( Appendable sb, int index, char ch)
|
||||
throws IllegalArgumentException, BufferOverflowException {
|
||||
if (sb instanceof StringBuilder)
|
||||
((StringBuilder) sb).setCharAt(index, ch);
|
||||
else if (sb instanceof Bytes)
|
||||
((Bytes) sb).writeByte(index, ch);
|
||||
else
|
||||
throw new IllegalArgumentException("" + sb.getClass());
|
||||
}
|
||||
|
||||
public static void parseUtf8( BytesStore bs, StringBuilder sb, boolean utf, int length) throws UTFDataFormatRuntimeException {
|
||||
BytesInternal.parseUtf8(bs, bs.readPosition(), sb, utf, length);
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
public static void setLength( Appendable sb, int newLength)
|
||||
throws BufferUnderflowException, IllegalArgumentException {
|
||||
if (sb instanceof StringBuilder)
|
||||
((StringBuilder) sb).setLength(newLength);
|
||||
else if (sb instanceof Bytes)
|
||||
((Bytes) sb).readPositionRemaining(0, newLength);
|
||||
else
|
||||
throw new IllegalArgumentException("" + sb.getClass());
|
||||
}
|
||||
|
||||
public static void append( Appendable sb, double value)
|
||||
throws IllegalArgumentException, BufferOverflowException {
|
||||
if (sb instanceof StringBuilder)
|
||||
((StringBuilder) sb).append(value);
|
||||
else if (sb instanceof Bytes)
|
||||
((Bytes) sb).append(value);
|
||||
else
|
||||
throw new IllegalArgumentException("" + sb.getClass());
|
||||
}
|
||||
|
||||
public static void append( Appendable sb, long value)
|
||||
throws IllegalArgumentException, BufferOverflowException {
|
||||
if (sb instanceof StringBuilder)
|
||||
((StringBuilder) sb).append(value);
|
||||
else if (sb instanceof Bytes)
|
||||
((Bytes) sb).append(value);
|
||||
else
|
||||
throw new IllegalArgumentException("" + sb.getClass());
|
||||
}
|
||||
|
||||
public static <ACS extends Appendable & CharSequence> void append( ACS sb, String str) {
|
||||
try {
|
||||
sb.append(str);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void read8bitAndAppend( StreamingDataInput bytes,
|
||||
StringBuilder appendable,
|
||||
StopCharsTester tester) {
|
||||
while (true) {
|
||||
int c = bytes.readUnsignedByte();
|
||||
if (tester.isStopChar(c, bytes.peekUnsignedByte()))
|
||||
return;
|
||||
appendable.append((char) c);
|
||||
if (bytes.readRemaining() == 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public static void readUTFAndAppend( StreamingDataInput bytes,
|
||||
Appendable appendable,
|
||||
StopCharsTester tester)
|
||||
throws BufferUnderflowException {
|
||||
try {
|
||||
readUtf8AndAppend(bytes, appendable, tester);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void readUtf8AndAppend( StreamingDataInput bytes,
|
||||
Appendable appendable,
|
||||
StopCharsTester tester)
|
||||
throws BufferUnderflowException, IOException {
|
||||
while (true) {
|
||||
int c = bytes.readUnsignedByte();
|
||||
if (c >= 128) {
|
||||
bytes.readSkip(-1);
|
||||
break;
|
||||
}
|
||||
// this is used for array class such as !type byte[]
|
||||
if (c == '[' && bytes.peekUnsignedByte() == ']') {
|
||||
appendable.append((char) c);
|
||||
appendable.append((char) bytes.readUnsignedByte());
|
||||
if (bytes.readRemaining() == 0)
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tester.isStopChar(c, bytes.peekUnsignedByte()))
|
||||
return;
|
||||
appendable.append((char) c);
|
||||
if (bytes.readRemaining() == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
for (int c; (c = bytes.readUnsignedByte()) >= 0; ) {
|
||||
switch (c >> 4) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
/* 0xxxxxxx */
|
||||
if (tester.isStopChar(c, bytes.peekUnsignedByte()))
|
||||
return;
|
||||
appendable.append((char) c);
|
||||
break;
|
||||
|
||||
case 12:
|
||||
case 13: {
|
||||
/* 110x xxxx 10xx xxxx */
|
||||
int char2 = bytes.readUnsignedByte();
|
||||
if ((char2 & 0xC0) != 0x80)
|
||||
throw new UTFDataFormatException(
|
||||
"malformed input around byte " + Integer.toHexString(char2));
|
||||
int c2 = (char) (((c & 0x1F) << 6) |
|
||||
(char2 & 0x3F));
|
||||
if (tester.isStopChar(c2, bytes.peekUnsignedByte()))
|
||||
return;
|
||||
appendable.append((char) c2);
|
||||
break;
|
||||
}
|
||||
|
||||
case 14: {
|
||||
/* 1110 xxxx 10xx xxxx 10xx xxxx */
|
||||
int char2 = bytes.readUnsignedByte();
|
||||
int char3 = bytes.readUnsignedByte();
|
||||
|
||||
if (((char2 & 0xC0) != 0x80))
|
||||
throw new UTFDataFormatException(
|
||||
"malformed input around byte " + Integer.toHexString(char2));
|
||||
if ((char3 & 0xC0) != 0x80)
|
||||
throw new UTFDataFormatException(
|
||||
"malformed input around byte " + Integer.toHexString(char3));
|
||||
int c3 = (char) (((c & 0x0F) << 12) |
|
||||
((char2 & 0x3F) << 6) |
|
||||
(char3 & 0x3F));
|
||||
if (tester.isStopChar(c3, bytes.peekUnsignedByte()))
|
||||
return;
|
||||
appendable.append((char) c3);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
/* 10xx xxxx, 1111 xxxx */
|
||||
throw new UTFDataFormatException(
|
||||
"malformed input around byte " + Integer.toHexString(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void parse8bit_SB1( Bytes bytes, StringBuilder sb, int length)
|
||||
throws BufferUnderflowException {
|
||||
if (length > bytes.readRemaining())
|
||||
throw new BufferUnderflowException();
|
||||
NativeBytesStore nbs = (NativeBytesStore) bytes.bytesStore();
|
||||
long offset = bytes.readPosition();
|
||||
int count = BytesInternal.parse8bit_SB1(offset, nbs, sb, length);
|
||||
bytes.readSkip(count);
|
||||
}
|
||||
|
||||
public static void parse8bit( StreamingDataInput bytes, Appendable appendable, int utflen)
|
||||
throws BufferUnderflowException, IOException {
|
||||
if (appendable instanceof StringBuilder) {
|
||||
final StringBuilder sb = (StringBuilder) appendable;
|
||||
if (bytes instanceof Bytes && ((Bytes) bytes).bytesStore() instanceof NativeBytesStore) {
|
||||
parse8bit_SB1((Bytes) bytes, sb, utflen);
|
||||
} else {
|
||||
BytesInternal.parse8bit1(bytes, sb, utflen);
|
||||
}
|
||||
} else {
|
||||
BytesInternal.parse8bit1(bytes, appendable, utflen);
|
||||
}
|
||||
}
|
||||
|
||||
public static <ACS extends Appendable & CharSequence> void append(ACS a, CharSequence cs, long start, long len) {
|
||||
if (a instanceof StringBuilder) {
|
||||
if (cs instanceof Bytes)
|
||||
((StringBuilder) a).append(Bytes.toString(((Bytes) cs), start, len));
|
||||
else
|
||||
((StringBuilder) a).append(cs.subSequence(Maths.toInt32(start), Maths.toInt32(len)));
|
||||
} else if (a instanceof Bytes) {
|
||||
((Bytes) a).appendUtf8(cs, Maths.toInt32(start), Maths.toInt32(len));
|
||||
} else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static long findUtf8Length( CharSequence str) throws IndexOutOfBoundsException {
|
||||
int strlen = str.length();
|
||||
long utflen = strlen;/* use charAt instead of copying String to char array */
|
||||
for (int i = 0; i < strlen; i++) {
|
||||
char c = str.charAt(i);
|
||||
if (c <= 0x007F) {
|
||||
continue;
|
||||
}
|
||||
if (c <= 0x07FF) {
|
||||
utflen++;
|
||||
|
||||
} else {
|
||||
utflen += 2;
|
||||
}
|
||||
}
|
||||
return utflen;
|
||||
}
|
||||
|
||||
@Java9
|
||||
public static long findUtf8Length( byte[] bytes, byte coder) {
|
||||
long utflen;
|
||||
|
||||
if (coder == 0) {
|
||||
int strlen = bytes.length;
|
||||
utflen = bytes.length;
|
||||
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0; i < strlen; i++) {
|
||||
int b = (bytes[i] & 0xFF);
|
||||
|
||||
if (b > 0x007F) {
|
||||
utflen++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int strlen = bytes.length;
|
||||
utflen = 0;/* use charAt instead of copying String to char array */
|
||||
for (int i = 0; i < strlen; i += 2) {
|
||||
char c = (char) (((bytes[i + 1] & 0xFF) << 8) | (bytes[i] & 0xFF));
|
||||
|
||||
if (c <= 0x007F) {
|
||||
utflen += 1;
|
||||
continue;
|
||||
}
|
||||
if (c <= 0x07FF) {
|
||||
utflen += 2;
|
||||
} else {
|
||||
utflen += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return utflen;
|
||||
}
|
||||
|
||||
@Java9
|
||||
public static long findUtf8Length( byte[] chars) {
|
||||
long utflen = 0; /* use charAt instead of copying String to char array */
|
||||
int strlen = chars.length;
|
||||
for (int i = 0; i < strlen; i++) {
|
||||
int c = chars[i] & 0xFF; // unsigned byte
|
||||
|
||||
if (c == 0) { // we have hit end of string
|
||||
break;
|
||||
}
|
||||
|
||||
if (c >= 0xF0) {
|
||||
utflen += 4;
|
||||
i += 3;
|
||||
} else if (c >= 0xE0) {
|
||||
utflen += 3;
|
||||
i += 2;
|
||||
} else if (c >= 0xC0) {
|
||||
utflen += 2;
|
||||
i += 1;
|
||||
} else {
|
||||
utflen += 1;
|
||||
}
|
||||
}
|
||||
return utflen;
|
||||
}
|
||||
|
||||
public static long findUtf8Length( char[] chars) {
|
||||
long utflen = chars.length;/* use charAt instead of copying String to char array */
|
||||
for (char c : chars) {
|
||||
if (c <= 0x007F) {
|
||||
continue;
|
||||
}
|
||||
if (c <= 0x07FF) {
|
||||
utflen++;
|
||||
|
||||
} else {
|
||||
utflen += 2;
|
||||
}
|
||||
}
|
||||
return utflen;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.util.AbstractInvocationHandler;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class BinaryBytesMethodWriterInvocationHandler extends AbstractInvocationHandler implements BytesMethodWriterInvocationHandler {
|
||||
private final Function<Method, MethodEncoder> methodToId;
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final BytesOut out;
|
||||
private final Map<Method, MethodEncoder> methodToIdMap = new LinkedHashMap<>();
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public BinaryBytesMethodWriterInvocationHandler(Function<Method, MethodEncoder> methodToId, BytesOut out) {
|
||||
super(HashMap::new);
|
||||
this.methodToId = methodToId;
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doInvoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
|
||||
MethodEncoder info = methodToIdMap.computeIfAbsent(method, methodToId);
|
||||
if (info == null) {
|
||||
Jvm.warn().on(getClass(), "Unknown method " + method + " ignored");
|
||||
return null;
|
||||
}
|
||||
out.comment(method.getName());
|
||||
out.writeStopBit(info.messageId());
|
||||
info.encode(args, out);
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public interface BinaryWireCode {
|
||||
|
||||
// sequence of length 0 - 255 bytes
|
||||
int BYTES_LENGTH8 = 0x80;
|
||||
// sequence of length 0 - 2^16-1 bytes
|
||||
int BYTES_LENGTH16 = 0x81;
|
||||
// sequence of length 0 - 2^32-1
|
||||
int BYTES_LENGTH32 = 0x82;
|
||||
// sequence of length 0 - 255
|
||||
// public static final int BYTES_LENGTH64 = 0x83;
|
||||
|
||||
int FIELD_ANCHOR = 0x87;
|
||||
int ANCHOR = 0x88;
|
||||
int UPDATED_ALIAS = 0x89;
|
||||
|
||||
// an array of unsigned bytes
|
||||
int U8_ARRAY = 0x8A;
|
||||
// public static final int U16_ARRAY = 0x8B;
|
||||
// public static final int I32_ARRAY = 0x8C;
|
||||
int I64_ARRAY = 0x8D;
|
||||
int PADDING32 = 0x8E;
|
||||
int PADDING = 0x8F;
|
||||
|
||||
int FLOAT32 = 0x90;
|
||||
int FLOAT64 = 0x91;
|
||||
int FLOAT_STOP_2 = 0x92;
|
||||
int FLOAT_STOP_4 = 0x94;
|
||||
int FLOAT_STOP_6 = 0x96;
|
||||
int FLOAT_SET_LOW_0 = 0x9A;
|
||||
int FLOAT_SET_LOW_2 = 0x9B;
|
||||
int FLOAT_SET_LOW_4 = 0x9C;
|
||||
// 0x98 - 0x9F
|
||||
|
||||
int UUID = 0xA0;
|
||||
int UINT8 = 0xA1;
|
||||
int UINT16 = 0xA2;
|
||||
int UINT32 = 0xA3;
|
||||
int INT8 = 0xA4;
|
||||
int INT16 = 0xA5;
|
||||
int INT32 = 0xA6;
|
||||
int INT64 = 0xA7;
|
||||
int SET_LOW_INT8 = 0xA8;
|
||||
int SET_LOW_INT16 = 0xA9;
|
||||
// public static final int FIXED_5 = 0xAA;
|
||||
// public static final int FIXED_4 = 0xAB;
|
||||
// public static final int FIXED_3 = 0xAC;
|
||||
// public static final int FIXED_2 = 0xAD;
|
||||
int STOP_BIT = 0xAE;
|
||||
int INT64_0x = 0xAF;
|
||||
|
||||
int FALSE = 0xB0;
|
||||
int TRUE = 0xB1;
|
||||
int TIME = 0xB2;
|
||||
int DATE = 0xB3;
|
||||
int DATE_TIME = 0xB4;
|
||||
int ZONED_DATE_TIME = 0xB5;
|
||||
int TYPE_PREFIX = 0xB6;
|
||||
int FIELD_NAME_ANY = 0xB7;
|
||||
int STRING_ANY = 0xB8;
|
||||
int EVENT_NAME = 0xB9;
|
||||
int FIELD_NUMBER = 0xBA;
|
||||
int NULL = 0xBB;
|
||||
int TYPE_LITERAL = 0xBC;
|
||||
int EVENT_OBJECT = 0xBD;
|
||||
int COMMENT = 0xBE;
|
||||
int HINT = 0xBF;
|
||||
|
||||
int FIELD_NAME0 = 0xC0;
|
||||
// ...
|
||||
int FIELD_NAME31 = 0xDF;
|
||||
|
||||
int STRING_0 = 0xE0;
|
||||
// ...
|
||||
int STRING_31 = 0xFF;
|
||||
|
||||
String[] STRING_FOR_CODE = _stringForCode(BinaryWireCode.class);
|
||||
|
||||
static String[] _stringForCode(Class clazz) {
|
||||
String[] stringForCode = new String[256];
|
||||
try {
|
||||
for ( Field field : clazz.getDeclaredFields()) {
|
||||
if (field.getType() == int.class)
|
||||
stringForCode[field.getInt(null)] = field.getName();
|
||||
else if (field.getType() == byte.class)
|
||||
stringForCode[field.getByte(null) & 0xFF] = field.getName();
|
||||
}
|
||||
for (int i = FIELD_NAME0; i <= FIELD_NAME31; i++)
|
||||
stringForCode[i] = "FIELD_" + i;
|
||||
for (int i = STRING_0; i <= STRING_31; i++)
|
||||
stringForCode[i] = "STRING_" + i;
|
||||
for (int i = 0; i < stringForCode.length; i++) {
|
||||
if (stringForCode[i] == null)
|
||||
if (i <= ' ' || i >= 127)
|
||||
stringForCode[i] = "Unknown_0x" + Integer.toHexString(i).toUpperCase();
|
||||
else
|
||||
stringForCode[i] = "Unknown_" + (char) i;
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return stringForCode;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import net.openhft.chronicle.core.io.UnsafeText;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Methods to append text to a Bytes. This extends the Appendable interface.
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public interface ByteStringAppender<B extends ByteStringAppender<B>> extends StreamingDataOutput<B>, Appendable {
|
||||
|
||||
/**
|
||||
* @return these Bytes as a Writer
|
||||
*/
|
||||
|
||||
default Writer writer() {
|
||||
return new ByteStringWriter(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a char in UTF-8
|
||||
*
|
||||
* @param ch to append
|
||||
* @return this
|
||||
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
||||
*/
|
||||
@Override
|
||||
|
||||
default B append(char ch) throws BufferOverflowException {
|
||||
BytesInternal.appendUtf8Char(this, ch);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a characters in UTF-8
|
||||
*
|
||||
* @param cs to append
|
||||
* @return this
|
||||
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
||||
*/
|
||||
@Override
|
||||
|
||||
default B append( CharSequence cs) throws BufferOverflowException {
|
||||
if (cs.length() == 0)
|
||||
return (B) this;
|
||||
try {
|
||||
return append(cs, 0, cs.length());
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a boolean as T or F
|
||||
*
|
||||
* @param flag to append
|
||||
* @return this
|
||||
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
||||
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
||||
*/
|
||||
|
||||
default B append(boolean flag) throws BufferOverflowException {
|
||||
return append(flag ? 'T' : 'F');
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an int in decimal
|
||||
*
|
||||
* @param value to append
|
||||
* @return this
|
||||
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
||||
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
||||
*/
|
||||
|
||||
default B append(int value) throws BufferOverflowException {
|
||||
BytesInternal.appendBase10(this, value);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a long in decimal
|
||||
*
|
||||
* @param value to append
|
||||
* @return this
|
||||
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
||||
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
||||
*/
|
||||
|
||||
default B append(long value) throws BufferOverflowException {
|
||||
if (value == (int) value)
|
||||
BytesInternal.appendBase10(this, (int) value);
|
||||
else
|
||||
BytesInternal.appendBase10(this, value);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
|
||||
default B appendBase(long value, int base) throws BufferOverflowException {
|
||||
BytesInternal.append(this, value, base);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
|
||||
default B appendBase16(long value) throws BufferOverflowException {
|
||||
BytesInternal.appendBase16(this, value, 1);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
|
||||
default B appendBase16(long value, int minDigits) throws BufferOverflowException {
|
||||
BytesInternal.appendBase16(this, value, minDigits);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a long in decimal with a given number of decimal places. Print value * 10^-decimalPlaces
|
||||
*
|
||||
* @param value to append
|
||||
* @param decimalPlaces to shift the decimal place.
|
||||
* @return this
|
||||
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
||||
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
||||
*/
|
||||
|
||||
default B appendDecimal(long value, int decimalPlaces) throws BufferOverflowException {
|
||||
BytesInternal.appendDecimal(this, value, decimalPlaces);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a float in decimal notation
|
||||
*
|
||||
* @param f to append
|
||||
* @return this
|
||||
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
||||
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
||||
*/
|
||||
|
||||
default B append(float f) throws BufferOverflowException {
|
||||
float f2 = Math.abs(f);
|
||||
if (f2 > 1e6 || f2 < 1e-3) {
|
||||
return append(Float.toString(f));
|
||||
}
|
||||
int precision = (int) Math.floor(6 - Math.log10(f2));
|
||||
long tens = Maths.tens(precision);
|
||||
return append((double) Math.round(f * tens) / tens);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a double in decimal notation
|
||||
*
|
||||
* @param d to append
|
||||
* @return this
|
||||
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
||||
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
||||
*/
|
||||
|
||||
default B append(double d) throws BufferOverflowException {
|
||||
BytesInternal.append(this, d);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a double in decimal notation to a specific number of decimal places. Trailing zeros are not truncated.
|
||||
* <p>
|
||||
* If the number would normally be printed with more decimal places, the number is rounded.
|
||||
*
|
||||
* @param d to append
|
||||
* @param decimalPlaces to always produce
|
||||
* @return this
|
||||
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
||||
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
||||
*/
|
||||
|
||||
default B append(double d, int decimalPlaces) throws BufferOverflowException {
|
||||
if (decimalPlaces < 0)
|
||||
throw new IllegalArgumentException();
|
||||
if (decimalPlaces < 18) {
|
||||
double d2 = d * Maths.tens(decimalPlaces);
|
||||
if (d2 < Long.MAX_VALUE && d2 > Long.MIN_VALUE) {
|
||||
// changed from java.lang.Math.round(d2) as this was shown up to cause latency
|
||||
long round = d2 > 0.0 ? (long) (d2 + 0.5) : (long) (d2 - 0.5);
|
||||
if (canWriteDirect(20 + decimalPlaces)) {
|
||||
long address = addressForWritePosition();
|
||||
long address2 = UnsafeText.appendBase10d(address, round, decimalPlaces);
|
||||
writeSkip(address2 - address);
|
||||
} else {
|
||||
appendDecimal(round, decimalPlaces);
|
||||
}
|
||||
return (B) this;
|
||||
}
|
||||
}
|
||||
return append(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a portion of a String to the Bytes in UTF-8.
|
||||
*
|
||||
* @param cs to copy
|
||||
* @param start index of the first char inclusive
|
||||
* @param end index of the last char exclusive.
|
||||
* @return this
|
||||
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
||||
*/
|
||||
@Override
|
||||
|
||||
default B append( CharSequence cs, int start, int end)
|
||||
throws IndexOutOfBoundsException, BufferOverflowException {
|
||||
BytesInternal.appendUtf8(this, cs, start, end - start);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a String to the Bytes in ISO-8859-1
|
||||
*
|
||||
* @param cs to write
|
||||
* @return this
|
||||
* @throws BufferOverflowException If the string as too large to write in the capacity available
|
||||
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
||||
*/
|
||||
|
||||
default B append8bit( CharSequence cs)
|
||||
throws BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException {
|
||||
return append8bit(cs, 0, cs.length());
|
||||
}
|
||||
|
||||
default B append8bit( BytesStore bs)
|
||||
throws BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException {
|
||||
return write(bs, 0L, bs.readRemaining());
|
||||
}
|
||||
|
||||
default B append8bit( String cs)
|
||||
throws BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException {
|
||||
return append8bit(cs, 0, cs.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a portion of a String to the Bytes in ISO-8859-1
|
||||
*
|
||||
* @param cs to copy
|
||||
* @param start index of the first char inclusive
|
||||
* @param end index of the last char exclusive.
|
||||
* @return this
|
||||
* @throws BufferOverflowException If the string as too large to write in the capacity available
|
||||
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
||||
* @throws IndexOutOfBoundsException if the start or the end are not valid for the CharSequence
|
||||
*/
|
||||
default B append8bit( CharSequence cs, int start, int end)
|
||||
throws IllegalArgumentException, BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException {
|
||||
if (cs instanceof BytesStore) {
|
||||
return write((BytesStore) cs, (long) start, end);
|
||||
}
|
||||
for (int i = start; i < end; i++) {
|
||||
char c = cs.charAt(i);
|
||||
if (c > 255) c = '?';
|
||||
writeByte((byte) c);
|
||||
}
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
default B append8bit( BytesStore bs, long start, long end)
|
||||
throws IllegalArgumentException, BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException {
|
||||
return write(bs, start, end);
|
||||
}
|
||||
|
||||
|
||||
default B appendDateMillis(long dateInMillis) {
|
||||
BytesInternal.appendDateMillis(this, dateInMillis);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
|
||||
default B appendTimeMillis(long timeOfDayInMillis) {
|
||||
BytesInternal.appendTimeMillis(this, timeOfDayInMillis % 86400_000L);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
|
||||
default B append( BigDecimal bigDecimal) {
|
||||
append(bigDecimal.toString());
|
||||
return (B) this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import net.openhft.chronicle.core.annotation.ForceInline;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Supports parsing bytes as text. You can parse them as special or white space terminated text.
|
||||
*/
|
||||
interface ByteStringParser<B extends ByteStringParser<B>> extends StreamingDataInput<B> {
|
||||
/**
|
||||
* Access these bytes as an ISO-8859-1 encoded Reader
|
||||
*
|
||||
* @return as a Reader
|
||||
*/
|
||||
|
||||
default Reader reader() {
|
||||
return new ByteStringReader(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true or false, or null if it could not be detected
|
||||
* as true or false. Case is not important
|
||||
* <p>
|
||||
* <p>false: f, false, n, no, 0
|
||||
* <p>
|
||||
* <p>true: t, true, y, yes, 1
|
||||
*
|
||||
* @param tester to detect the end of the text.
|
||||
* @return true, false, or null if neither.
|
||||
*/
|
||||
|
||||
default Boolean parseBoolean( StopCharTester tester) {
|
||||
return BytesInternal.parseBoolean(this, tester);
|
||||
}
|
||||
|
||||
|
||||
default Boolean parseBoolean() {
|
||||
return BytesInternal.parseBoolean(this, StopCharTesters.NON_ALPHA_DIGIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse text with UTF-8 decoding as character terminated.
|
||||
*
|
||||
* @param stopCharTester to check if the end has been reached.
|
||||
* @return the text as a String.
|
||||
*/
|
||||
|
||||
@ForceInline
|
||||
default String parseUtf8( StopCharTester stopCharTester) {
|
||||
return BytesInternal.parseUtf8(this, stopCharTester);
|
||||
}
|
||||
|
||||
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
default String parseUTF( StopCharTester stopCharTester) {
|
||||
return parseUtf8(stopCharTester);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse text with UTF-8 decoding as character terminated.
|
||||
*
|
||||
* @param buffer to populate
|
||||
* @param stopCharTester to check if the end has been reached.
|
||||
*/
|
||||
@ForceInline
|
||||
default void parseUtf8( Appendable buffer, StopCharTester stopCharTester) throws BufferUnderflowException {
|
||||
BytesInternal.parseUtf8(this, buffer, stopCharTester);
|
||||
}
|
||||
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
default void parseUTF( Appendable buffer, StopCharTester stopCharTester) throws BufferUnderflowException {
|
||||
parseUtf8(buffer, stopCharTester);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse text with UTF-8 decoding as one or two character terminated.
|
||||
*
|
||||
* @param buffer to populate
|
||||
* @param stopCharsTester to check if the end has been reached.
|
||||
*/
|
||||
@ForceInline
|
||||
default void parseUtf8( Appendable buffer, StopCharsTester stopCharsTester)
|
||||
throws BufferUnderflowException, IORuntimeException {
|
||||
BytesInternal.parseUtf8(this, buffer, stopCharsTester);
|
||||
}
|
||||
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
default void parseUTF( Appendable buffer, StopCharsTester stopCharsTester)
|
||||
throws BufferUnderflowException, IORuntimeException {
|
||||
parseUtf8(buffer, stopCharsTester);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse text with ISO-8859-1 decoding as character terminated.
|
||||
*
|
||||
* @param buffer to populate
|
||||
* @param stopCharTester to check if the end has been reached.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@ForceInline
|
||||
default void parse8bit(Appendable buffer, StopCharTester stopCharTester)
|
||||
throws BufferUnderflowException {
|
||||
if (buffer instanceof StringBuilder)
|
||||
BytesInternal.parse8bit(this, (StringBuilder) buffer, stopCharTester);
|
||||
else
|
||||
BytesInternal.parse8bit(this, (Bytes) buffer, stopCharTester);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse text with ISO-8859-1 decoding as character terminated.
|
||||
*
|
||||
* @param stopCharTester to check if the end has been reached.
|
||||
*/
|
||||
default String parse8bit( StopCharTester stopCharTester)
|
||||
throws BufferUnderflowException {
|
||||
return BytesInternal.parse8bit(this, stopCharTester);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse text with ISO-8859-1 decoding as character terminated.
|
||||
*
|
||||
* @param buffer to populate
|
||||
* @param stopCharsTester to check if the end has been reached.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@ForceInline
|
||||
default void parse8bit(Appendable buffer, StopCharsTester stopCharsTester)
|
||||
throws BufferUnderflowException {
|
||||
if (buffer instanceof StringBuilder)
|
||||
BytesInternal.parse8bit(this, (StringBuilder) buffer, stopCharsTester);
|
||||
else
|
||||
BytesInternal.parse8bit(this, (Bytes) buffer, stopCharsTester);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
default void parse8bit(Bytes buffer, StopCharsTester stopCharsTester)
|
||||
throws BufferUnderflowException {
|
||||
BytesInternal.parse8bit(this, buffer, stopCharsTester);
|
||||
}
|
||||
|
||||
default void parse8bit(StringBuilder buffer, StopCharsTester stopCharsTester)
|
||||
throws BufferUnderflowException {
|
||||
BytesInternal.parse8bit(this, buffer, stopCharsTester);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse text as an int. The terminating character is consumed.
|
||||
*
|
||||
* @return an int.
|
||||
*/
|
||||
@ForceInline
|
||||
default int parseInt() throws BufferUnderflowException {
|
||||
return Maths.toInt32(BytesInternal.parseLong(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* parse text as a long integer. The terminating character is consumed.
|
||||
*
|
||||
* @return a long.
|
||||
*/
|
||||
@ForceInline
|
||||
default long parseLong() throws BufferUnderflowException {
|
||||
return BytesInternal.parseLong(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse text as a float decimal. The terminating character is consumed.
|
||||
* <p>
|
||||
* The number of decimal places can be retrieved with lastDecimalPlaces()
|
||||
*
|
||||
* @return a float.
|
||||
*/
|
||||
default float parseFloat() throws BufferUnderflowException {
|
||||
return (float) BytesInternal.parseDouble(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse text as a double decimal. The terminating character is consumed.
|
||||
* <p>
|
||||
* The number of decimal places can be retrieved with lastDecimalPlaces()
|
||||
*
|
||||
* @return a double.
|
||||
*/
|
||||
default double parseDouble() throws BufferUnderflowException {
|
||||
return BytesInternal.parseDouble(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the significant digits of a decimal number.
|
||||
* <p>
|
||||
* The number of decimal places can be retrieved with lastDecimalPlaces()
|
||||
*
|
||||
* @return the significant digits
|
||||
*/
|
||||
default long parseLongDecimal() throws BufferUnderflowException {
|
||||
return BytesInternal.parseLongDecimal(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the last number of decimal places for parseDouble or parseLongDecimal
|
||||
*/
|
||||
int lastDecimalPlaces();
|
||||
|
||||
/**
|
||||
* Store the last number of decimal places. If
|
||||
*
|
||||
* @param lastDecimalPlaces set the number of decimal places if positive, otherwise 0.
|
||||
*/
|
||||
void lastDecimalPlaces(int lastDecimalPlaces);
|
||||
|
||||
/**
|
||||
* Skip text until a terminating character is reached.
|
||||
*
|
||||
* @param tester to stop at
|
||||
* @return true if a terminating character was found, false if the end of the buffer was reached.
|
||||
*/
|
||||
@ForceInline
|
||||
default boolean skipTo( StopCharTester tester) {
|
||||
return BytesInternal.skipTo(this, tester);
|
||||
}
|
||||
|
||||
|
||||
default BigDecimal parseBigDecimal() {
|
||||
return new BigDecimal(parseUtf8(StopCharTesters.NUMBER_END));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* A Reader wrapper for Bytes. This Reader moves the readPosition() of the underlying Bytes up to the readLimit()
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class ByteStringReader extends Reader {
|
||||
private final ByteStringParser in;
|
||||
|
||||
public ByteStringReader(ByteStringParser in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
return in.readRemaining() > 0 ? in.readUnsignedByte() : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
long len = Math.min(in.readRemaining(), n);
|
||||
try {
|
||||
in.readSkip(len);
|
||||
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(char[] cbuf, int off, int len) throws IOException {
|
||||
try {
|
||||
return in.read(cbuf, off, len);
|
||||
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.nio.BufferOverflowException;
|
||||
|
||||
/**
|
||||
* A Writer for an underlying Bytes. This moves the writePosition() up to the writeLimit();
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
class ByteStringWriter extends Writer {
|
||||
private final ByteStringAppender out;
|
||||
|
||||
ByteStringWriter(ByteStringAppender out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int c) throws IOException {
|
||||
try {
|
||||
out.append((char) c);
|
||||
|
||||
} catch ( BufferOverflowException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write( String str) throws IOException {
|
||||
out.append(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write( String str, int off, int len) throws IOException {
|
||||
out.append(str, off, off + len);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Writer append( CharSequence csq) throws IOException {
|
||||
out.append(csq);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Writer append( CharSequence csq, int start, int end) throws IOException {
|
||||
out.append(csq, start, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Writer append(char c) throws IOException {
|
||||
out.append(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(char[] cbuf, int off, int len) throws IOException {
|
||||
for (int i = 0; i < len; i++)
|
||||
out.append(cbuf[i + off]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* This Interface allows a reference to off heap memory to be reassigned.
|
||||
* <p></p>
|
||||
* A reference to off heap memory is a proxy for some memory which sits outside the heap.
|
||||
*/
|
||||
public interface Byteable<B extends BytesStore<B, Underlying>, Underlying> {
|
||||
/**
|
||||
* This setter for a data type which points to an underlying ByteStore.
|
||||
*
|
||||
* @param bytesStore the fix point ByteStore
|
||||
* @param offset the offset within the ByteStore
|
||||
* @param length the length in the ByteStore
|
||||
*/
|
||||
void bytesStore(BytesStore<B, Underlying> bytesStore, long offset, long length)
|
||||
throws IllegalStateException, IllegalArgumentException, BufferOverflowException,
|
||||
BufferUnderflowException;
|
||||
|
||||
|
||||
BytesStore<B, Underlying> bytesStore();
|
||||
|
||||
long offset();
|
||||
|
||||
/**
|
||||
* @return the maximum size in byte for this reference.
|
||||
*/
|
||||
long maxSize();
|
||||
}
|
|
@ -0,0 +1,944 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import net.openhft.chronicle.core.annotation.UsedViaReflection;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import net.openhft.chronicle.core.io.ReferenceOwner;
|
||||
import net.openhft.chronicle.core.util.ObjectUtils;
|
||||
import net.openhft.chronicle.core.util.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Bytes is a pointer to a region of memory within a BytesStore. It can be for a fixed region of
|
||||
* memory or an "elastic" buffer which can be resized, but not for a fixed region. <p></p> This is a
|
||||
* BytesStore which is mutable and not thread safe. It has a write position and read position which
|
||||
* must follow these constraints <p></p> start() <= readPosition() <= writePosition() <=
|
||||
* writeLimit() <= capacity() <p></p> Also readLimit() == writePosition() and readPosition()
|
||||
* <= safeLimit(); <p></p>
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public interface Bytes<Underlying> extends
|
||||
BytesStore<Bytes<Underlying>, Underlying>,
|
||||
BytesIn<Underlying>,
|
||||
BytesOut<Underlying> {
|
||||
|
||||
long MAX_CAPACITY = Long.MAX_VALUE & ~0xF; // 8 EiB - 16
|
||||
int MAX_HEAP_CAPACITY = Integer.MAX_VALUE & ~0xF; // 2 GiB - 16
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
int MAX_BYTE_BUFFER_CAPACITY = MAX_HEAP_CAPACITY;
|
||||
int DEFAULT_BYTE_BUFFER_CAPACITY = 256;
|
||||
|
||||
/**
|
||||
* Creates and returns a new elastic wrapper for a direct (off-heap) ByteBuffer with a default capacity
|
||||
* which will be resized as required.
|
||||
*
|
||||
* @return a new elastic wrapper for a direct (off-heap) ByteBuffer with a default capacity
|
||||
* which will be resized as required
|
||||
*/
|
||||
|
||||
static Bytes<ByteBuffer> elasticByteBuffer() {
|
||||
return elasticByteBuffer(DEFAULT_BYTE_BUFFER_CAPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new elastic wrapper for a direct (off-heap) ByteBuffer with
|
||||
* the given {@code initialCapacity} which will be resized as required.
|
||||
*
|
||||
* @param initialCapacity the initial non-negative capacity given in bytes
|
||||
* @return a new elastic wrapper for a direct (off-heap) ByteBuffer with
|
||||
* the given {@code initialCapacity} which will be resized as required
|
||||
*/
|
||||
|
||||
static Bytes<ByteBuffer> elasticByteBuffer(int initialCapacity) {
|
||||
return elasticByteBuffer(initialCapacity, MAX_HEAP_CAPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new elastic wrapper for a direct (off-heap) ByteBuffer with
|
||||
* the given {@code initialCapacity} which will be resized as required up
|
||||
* to the given {@code maxSize}.
|
||||
*
|
||||
* @param initialCapacity the initial non-negative capacity given in bytes
|
||||
* @param maxCapacity the max capacity given in bytes equal or greater than initialCapacity
|
||||
* @return a new elastic wrapper for a direct (off-heap) ByteBuffer with
|
||||
* the given {@code initialCapacity} which will be resized as required up
|
||||
* to the given {@code maxCapacity}
|
||||
*/
|
||||
|
||||
static Bytes<ByteBuffer> elasticByteBuffer(int initialCapacity, int maxCapacity) {
|
||||
NativeBytesStore<ByteBuffer> bs = NativeBytesStore.elasticByteBuffer(initialCapacity, maxCapacity);
|
||||
try {
|
||||
return bs.bytesForWrite();
|
||||
} finally {
|
||||
bs.release(ReferenceOwner.INIT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new elastic wrapper for a heap ByteBuffer with
|
||||
* the given {@code initialCapacity} which will be resized as required.
|
||||
*
|
||||
* @param initialCapacity the initial non-negative capacity given in bytes
|
||||
* @return a new elastic wrapper for a heap ByteBuffer with
|
||||
* the given {@code initialCapacity} which will be resized as required
|
||||
*/
|
||||
|
||||
static Bytes<ByteBuffer> elasticHeapByteBuffer(int initialCapacity) {
|
||||
HeapBytesStore<ByteBuffer> bs = HeapBytesStore.wrap(ByteBuffer.allocate(initialCapacity));
|
||||
try {
|
||||
return NativeBytes.wrapWithNativeBytes(bs, Bytes.MAX_HEAP_CAPACITY);
|
||||
} finally {
|
||||
bs.release(INIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Bytes<ByteBuffer> elasticHeapByteBuffer() {
|
||||
return elasticHeapByteBuffer(128);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the ByteBuffer ready for reading
|
||||
* Method for convenience only - might not be ideal for performance (creates garbage).
|
||||
* To avoid garbage, use something like this example:
|
||||
* <pre>{@code
|
||||
* import net.openhft.chronicle.bytes.Bytes;
|
||||
* import java.nio.ByteBuffer;
|
||||
*
|
||||
* public class ChronicleBytesWithByteBufferExampleTest {
|
||||
* private static final String HELLO_WORLD = "hello world";
|
||||
*
|
||||
* public static void main(String[] args) throws InterruptedException {
|
||||
* //setup Bytes and ByteBuffer to write from
|
||||
* Bytes b = Bytes.elasticByteBuffer();
|
||||
* ByteBuffer toWriteFrom = ByteBuffer.allocate(HELLO_WORLD.length());
|
||||
* toWriteFrom.put(HELLO_WORLD.getBytes(), 0, HELLO_WORLD.length());
|
||||
* toWriteFrom.flip();
|
||||
* byte[] toReadTo = new byte[HELLO_WORLD.length()];
|
||||
*
|
||||
* doWrite(b, toWriteFrom);
|
||||
* ByteBuffer byteBuffer = doRead(b);
|
||||
*
|
||||
* //check result
|
||||
* final StringBuilder sb = new StringBuilder();
|
||||
* for (int i = 0; i < HELLO_WORLD.length(); i++) {
|
||||
* sb.append((char) byteBuffer.get());
|
||||
* }
|
||||
* assert sb.toString().equals(HELLO_WORLD): "Failed - strings not equal!";
|
||||
* }
|
||||
*
|
||||
* private static void doWrite(Bytes b, ByteBuffer toWrite) {
|
||||
* //no garbage when writing to Bytes from ByteBuffer
|
||||
* b.clear();
|
||||
* b.write(b.writePosition(), toWrite, toWrite.position(), toWrite.limit());
|
||||
* }
|
||||
*
|
||||
* private static ByteBuffer doRead(Bytes b) {
|
||||
* //no garbage when getting the underlying ByteBuffer
|
||||
* assert b.underlyingObject() instanceof ByteBuffer;
|
||||
* ByteBuffer byteBuffer = (ByteBuffer) b.underlyingObject();
|
||||
* return byteBuffer;
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @param byteBuffer to wrap
|
||||
* @return a Bytes which wraps the provided ByteBuffer and is ready for reading.
|
||||
*/
|
||||
|
||||
static Bytes<ByteBuffer> wrapForRead( ByteBuffer byteBuffer) {
|
||||
BytesStore<?, ByteBuffer> bs = BytesStore.wrap(byteBuffer);
|
||||
try {
|
||||
Bytes<ByteBuffer> bbb = bs.bytesForRead();
|
||||
bbb.readLimit(byteBuffer.limit());
|
||||
bbb.readPosition(byteBuffer.position());
|
||||
return bbb;
|
||||
} finally {
|
||||
bs.release(INIT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the ByteBuffer ready for writing
|
||||
* Method for convenience only - might not be ideal for performance (creates garbage).
|
||||
* To avoid garbage, use something like this example:
|
||||
* <pre>{@code
|
||||
* import net.openhft.chronicle.bytes.Bytes;
|
||||
* import java.nio.ByteBuffer;
|
||||
*
|
||||
* public class ChronicleBytesWithByteBufferExampleTest {
|
||||
* private static final String HELLO_WORLD = "hello world";
|
||||
*
|
||||
* public static void main(String[] args) throws InterruptedException {
|
||||
* //setup Bytes and ByteBuffer to write from
|
||||
* Bytes b = Bytes.elasticByteBuffer();
|
||||
* ByteBuffer toWriteFrom = ByteBuffer.allocate(HELLO_WORLD.length());
|
||||
* toWriteFrom.put(HELLO_WORLD.getBytes(), 0, HELLO_WORLD.length());
|
||||
* toWriteFrom.flip();
|
||||
* byte[] toReadTo = new byte[HELLO_WORLD.length()];
|
||||
*
|
||||
* doWrite(b, toWriteFrom);
|
||||
* ByteBuffer byteBuffer = doRead(b);
|
||||
*
|
||||
* //check result
|
||||
* final StringBuilder sb = new StringBuilder();
|
||||
* for (int i = 0; i < HELLO_WORLD.length(); i++) {
|
||||
* sb.append((char) byteBuffer.get());
|
||||
* }
|
||||
* assert sb.toString().equals(HELLO_WORLD): "Failed - strings not equal!";
|
||||
* }
|
||||
*
|
||||
* private static void doWrite(Bytes b, ByteBuffer toWrite) {
|
||||
* //no garbage when writing to Bytes from ByteBuffer
|
||||
* b.clear();
|
||||
* b.write(b.writePosition(), toWrite, toWrite.position(), toWrite.limit());
|
||||
* }
|
||||
*
|
||||
* private static ByteBuffer doRead(Bytes b) {
|
||||
* //no garbage when getting the underlying ByteBuffer
|
||||
* assert b.underlyingObject() instanceof ByteBuffer;
|
||||
* ByteBuffer byteBuffer = (ByteBuffer) b.underlyingObject();
|
||||
* return byteBuffer;
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @param byteBuffer to wrap
|
||||
* @return a Bytes which wraps the provided ByteBuffer and is ready for writing.
|
||||
*/
|
||||
|
||||
static Bytes<ByteBuffer> wrapForWrite( ByteBuffer byteBuffer) {
|
||||
BytesStore<?, ByteBuffer> bs = BytesStore.wrap(byteBuffer);
|
||||
try {
|
||||
Bytes<ByteBuffer> bbb = bs.bytesForWrite();
|
||||
bbb.writePosition(byteBuffer.position());
|
||||
bbb.writeLimit(byteBuffer.limit());
|
||||
return bbb;
|
||||
} finally {
|
||||
bs.release(INIT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the byte[] ready for reading
|
||||
* Method for convenience only - might not be ideal for performance (creates garbage).
|
||||
* To avoid garbage, use something like this example:
|
||||
* <pre>{@code
|
||||
* import net.openhft.chronicle.bytes.Bytes;
|
||||
* import java.nio.charset.Charset;
|
||||
*
|
||||
* public class ChronicleBytesWithPrimByteArrayExampleTest {
|
||||
* private static final Charset ISO_8859 = Charset.forName("ISO-8859-1");
|
||||
* private static final String HELLO_WORLD = "hello world";
|
||||
*
|
||||
* public static void main(String[] args) {
|
||||
* //setup Bytes and byte[]s to write from and read to
|
||||
* Bytes b = Bytes.elasticByteBuffer();
|
||||
* byte[] toWriteFrom = HELLO_WORLD.getBytes(ISO_8859);
|
||||
* byte[] toReadTo = new byte[HELLO_WORLD.length()];
|
||||
*
|
||||
* doWrite(b, toWriteFrom);
|
||||
* doRead(b, toReadTo);
|
||||
*
|
||||
* //check result
|
||||
* final StringBuilder sb = new StringBuilder();
|
||||
* for (int i = 0; i < HELLO_WORLD.length(); i++) {
|
||||
* sb.append((char) toReadTo[i]);
|
||||
* }
|
||||
* assert sb.toString().equals(HELLO_WORLD): "Failed - strings not equal!";
|
||||
* }
|
||||
*
|
||||
* private static void doWrite(Bytes b, byte[] toWrite) {
|
||||
* //no garbage when writing to Bytes from byte[]
|
||||
* b.clear();
|
||||
* b.write(toWrite);
|
||||
* }
|
||||
*
|
||||
* private static void doRead(Bytes b, byte[] toReadTo) {
|
||||
* //no garbage when reading from Bytes into byte[]
|
||||
* b.read( toReadTo, 0, HELLO_WORLD.length());
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @param byteArray to wrap
|
||||
* @return the Bytes ready for reading.
|
||||
*/
|
||||
|
||||
static Bytes<byte[]> wrapForRead( byte[] byteArray) {
|
||||
HeapBytesStore<byte[]> bs = BytesStore.wrap(byteArray);
|
||||
try {
|
||||
return bs.bytesForRead();
|
||||
} finally {
|
||||
bs.release(INIT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the byte[] ready for writing
|
||||
* Method for convenience only - might not be ideal for performance (creates garbage).
|
||||
* To avoid garbage, use something like this example:
|
||||
* <pre>{@code
|
||||
* import net.openhft.chronicle.bytes.Bytes;
|
||||
* import java.nio.charset.Charset;
|
||||
*
|
||||
* public class ChronicleBytesWithPrimByteArrayExampleTest {
|
||||
* private static final Charset ISO_8859 = Charset.forName("ISO-8859-1");
|
||||
* private static final String HELLO_WORLD = "hello world";
|
||||
*
|
||||
* public static void main(String[] args) {
|
||||
* //setup Bytes and byte[]s to write from and read to
|
||||
* Bytes b = Bytes.elasticByteBuffer();
|
||||
* byte[] toWriteFrom = HELLO_WORLD.getBytes(ISO_8859);
|
||||
* byte[] toReadTo = new byte[HELLO_WORLD.length()];
|
||||
*
|
||||
* doWrite(b, toWriteFrom);
|
||||
* doRead(b, toReadTo);
|
||||
*
|
||||
* //check result
|
||||
* final StringBuilder sb = new StringBuilder();
|
||||
* for (int i = 0; i < HELLO_WORLD.length(); i++) {
|
||||
* sb.append((char) toReadTo[i]);
|
||||
* }
|
||||
* assert sb.toString().equals(HELLO_WORLD): "Failed - strings not equal!";
|
||||
* }
|
||||
*
|
||||
* private static void doWrite(Bytes b, byte[] toWrite) {
|
||||
* //no garbage when writing to Bytes from byte[]
|
||||
* b.clear();
|
||||
* b.write(toWrite);
|
||||
* }
|
||||
*
|
||||
* private static void doRead(Bytes b, byte[] toReadTo) {
|
||||
* //no garbage when reading from Bytes into byte[]
|
||||
* b.read( toReadTo, 0, HELLO_WORLD.length());
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @param byteArray to wrap
|
||||
* @return the Bytes ready for writing.
|
||||
*/
|
||||
|
||||
static Bytes<byte[]> wrapForWrite( byte[] byteArray) {
|
||||
BytesStore bs = BytesStore.wrap(byteArray);
|
||||
try {
|
||||
return bs.bytesForWrite();
|
||||
} finally {
|
||||
bs.release(INIT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert text to bytes using ISO-8859-1 encoding and return a Bytes ready for reading.
|
||||
* <p>
|
||||
* Note: this returns a direct Bytes now
|
||||
*
|
||||
* @param text to convert
|
||||
* @return Bytes ready for reading.
|
||||
*/
|
||||
|
||||
static Bytes<?> from( CharSequence text) {
|
||||
return from(text.toString());
|
||||
}
|
||||
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
static Bytes<?> fromString(String text) {
|
||||
return from(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert text to bytes using ISO-8859-1 encoding and return a Bytes ready for reading.
|
||||
* <p>
|
||||
* Note: this returns a direct Bytes now
|
||||
*
|
||||
* @param text to convert
|
||||
* @return Bytes ready for reading.
|
||||
*/
|
||||
|
||||
static Bytes<?> directFrom( String text) {
|
||||
NativeBytesStore from = NativeBytesStore.from(text);
|
||||
try {
|
||||
return from.bytesForRead();
|
||||
} finally {
|
||||
from.release(INIT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert text to bytes using ISO-8859-1 encoding and return a Bytes ready for reading.
|
||||
* <p>
|
||||
* Note: this returns a heap Bytes
|
||||
*
|
||||
* @param text to convert
|
||||
* @return Bytes ready for reading.
|
||||
*/
|
||||
|
||||
static Bytes<byte[]> from( String text) throws IllegalArgumentException, IllegalStateException {
|
||||
return wrapForRead(text.getBytes(StandardCharsets.ISO_8859_1));
|
||||
}
|
||||
|
||||
@UsedViaReflection
|
||||
static Bytes<byte[]> valueOf(String text) {
|
||||
return from(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new fix sized wrapper for native (64-bit address)
|
||||
* memory with the given {@code capacity}.
|
||||
*
|
||||
* @param capacity the non-negative capacity given in bytes
|
||||
* @return a new fix sized wrapper for native (64-bit address)
|
||||
* memory with the given {@code capacity}
|
||||
*/
|
||||
|
||||
static VanillaBytes<Void> allocateDirect(long capacity) throws IllegalArgumentException {
|
||||
NativeBytesStore<Void> bs = NativeBytesStore.nativeStoreWithFixedCapacity(capacity);
|
||||
try {
|
||||
return new VanillaBytes<>(bs);
|
||||
} finally {
|
||||
bs.release(INIT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new elastic wrapper for native (64-bit address)
|
||||
* memory with zero initial capacity which will be resized as required.
|
||||
*
|
||||
* @return a new elastic wrapper for native (64-bit address)
|
||||
* memory with zero initial capacity which will be resized as required
|
||||
*/
|
||||
|
||||
static NativeBytes<Void> allocateElasticDirect() {
|
||||
return NativeBytes.nativeBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new elastic wrapper for native (64-bit address)
|
||||
* memory with the given {@code initialCapacity} which will be resized as required.
|
||||
*
|
||||
* @param initialCapacity the initial non-negative capacity given in bytes
|
||||
* @return a new elastic wrapper for native (64-bit address)
|
||||
* memory with the given {@code initialCapacity} which will be resized as required
|
||||
*/
|
||||
|
||||
static NativeBytes<Void> allocateElasticDirect(long initialCapacity) throws IllegalArgumentException {
|
||||
return NativeBytes.nativeBytes(initialCapacity);
|
||||
}
|
||||
|
||||
|
||||
static OnHeapBytes allocateElasticOnHeap() {
|
||||
return allocateElasticOnHeap(32);
|
||||
}
|
||||
|
||||
|
||||
static OnHeapBytes allocateElasticOnHeap(int initialCapacity) {
|
||||
HeapBytesStore<byte[]> wrap = HeapBytesStore.wrap(new byte[initialCapacity]);
|
||||
try {
|
||||
return new OnHeapBytes(wrap, true);
|
||||
} finally {
|
||||
wrap.release(INIT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string from the {@code position} to the {@code limit}, The buffer is not modified
|
||||
* by this call
|
||||
*
|
||||
* @param buffer the buffer to use
|
||||
* @return a string contain the text from the {@code position} to the {@code limit}
|
||||
*/
|
||||
|
||||
static String toString( final Bytes<?> buffer) throws BufferUnderflowException {
|
||||
return toString(buffer, MAX_HEAP_CAPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string from the {@code position} to the {@code limit}, The buffer is not modified
|
||||
* by this call
|
||||
*
|
||||
* @param buffer the buffer to use
|
||||
* @param maxLen of the result returned
|
||||
* @return a string contain the text from the {@code position} to the {@code limit}
|
||||
*/
|
||||
|
||||
static String toString( final Bytes<?> buffer, long maxLen) throws
|
||||
BufferUnderflowException {
|
||||
|
||||
if (buffer.refCount() < 1)
|
||||
// added because something is crashing the JVM
|
||||
return "<unknown>";
|
||||
|
||||
ReferenceOwner toString = ReferenceOwner.temporary("toString");
|
||||
buffer.reserve(toString);
|
||||
try {
|
||||
|
||||
if (buffer.readRemaining() == 0)
|
||||
return "";
|
||||
|
||||
final long length = Math.min(maxLen + 1, buffer.readRemaining());
|
||||
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
try {
|
||||
buffer.readWithLength(length, b -> {
|
||||
while (buffer.readRemaining() > 0) {
|
||||
if (builder.length() >= maxLen) {
|
||||
builder.append("...");
|
||||
break;
|
||||
}
|
||||
builder.append((char) buffer.readByte());
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
builder.append(' ').append(e);
|
||||
}
|
||||
return builder.toString();
|
||||
} finally {
|
||||
buffer.release(toString);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The buffer is not modified by this call
|
||||
*
|
||||
* @param buffer the buffer to use
|
||||
* @param position the position to create the string from
|
||||
* @param len the number of characters to show in the string
|
||||
* @return a string contain the text from offset {@code position}
|
||||
*/
|
||||
|
||||
static String toString( final Bytes buffer, long position, long len)
|
||||
throws BufferUnderflowException {
|
||||
final long pos = buffer.readPosition();
|
||||
final long limit = buffer.readLimit();
|
||||
buffer.readPositionRemaining(position, len);
|
||||
|
||||
try {
|
||||
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
while (buffer.readRemaining() > 0) {
|
||||
builder.append((char) buffer.readByte());
|
||||
}
|
||||
|
||||
// remove the last comma
|
||||
return builder.toString();
|
||||
} finally {
|
||||
buffer.readLimit(limit);
|
||||
buffer.readPosition(pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new fix sized wrapper for native (64-bit address)
|
||||
* memory with the contents copied from the given {@code bytes} array.
|
||||
* <p>
|
||||
* Changes in the given {@code bytes} will not be affected by writes in
|
||||
* the returned wrapper or vice versa.
|
||||
*
|
||||
* @param bytes array to copy
|
||||
* @return a new fix sized wrapper for native (64-bit address)
|
||||
* memory with the contents copied from the given {@code bytes} array
|
||||
*/
|
||||
|
||||
static VanillaBytes allocateDirect( byte[] bytes) throws IllegalArgumentException {
|
||||
VanillaBytes<Void> result = allocateDirect(bytes.length);
|
||||
try {
|
||||
result.write(bytes);
|
||||
} catch (BufferOverflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static Bytes fromHexString( String s) {
|
||||
return BytesInternal.fromHexString(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Code shared by String and StringBuffer to do searches. The
|
||||
* source is the character array being searched, and the target
|
||||
* is the string being searched for.
|
||||
*
|
||||
* @param source the read bytes being searched.
|
||||
* @param target the read bytes being searched for.
|
||||
* @param fromIndex the index to begin searching from,
|
||||
* @return the index of where the text was found.
|
||||
*/
|
||||
static int indexOf( BytesStore source, BytesStore target, int fromIndex) {
|
||||
|
||||
long sourceOffset = source.readPosition();
|
||||
long targetOffset = target.readPosition();
|
||||
long sourceCount = source.readRemaining();
|
||||
long targetCount = target.readRemaining();
|
||||
|
||||
if (fromIndex >= sourceCount) {
|
||||
return Math.toIntExact(targetCount == 0 ? sourceCount : -1);
|
||||
}
|
||||
if (fromIndex < 0) {
|
||||
fromIndex = 0;
|
||||
}
|
||||
if (targetCount == 0) {
|
||||
return fromIndex;
|
||||
}
|
||||
|
||||
byte firstByte = target.readByte(targetOffset);
|
||||
long max = sourceOffset + (sourceCount - targetCount);
|
||||
|
||||
for (long i = sourceOffset + fromIndex; i <= max; i++) {
|
||||
/* Look for first character. */
|
||||
if (source.readByte(i) != firstByte) {
|
||||
while (++i <= max && source.readByte(i) != firstByte) ;
|
||||
}
|
||||
|
||||
/* Found first character, now look at the rest of v2 */
|
||||
if (i <= max) {
|
||||
long j = i + 1;
|
||||
long end = j + targetCount - 1;
|
||||
for (long k = targetOffset + 1; j < end && source.readByte(j) == target.readByte(k); j++, k++) {
|
||||
}
|
||||
|
||||
if (j == end) {
|
||||
/* Found whole string. */
|
||||
return Math.toIntExact(i - sourceOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Bytes which is optionally unchecked. This allows bounds checks to be turned off.
|
||||
* Note: this means that the result is no longer elastic, even if <code>this</code> is elastic.
|
||||
*
|
||||
* @param unchecked if true, minimal bounds checks will be performed.
|
||||
* @return Bytes without bounds checking.
|
||||
* @throws IllegalStateException if the underlying BytesStore has been released
|
||||
*/
|
||||
|
||||
default Bytes<Underlying> unchecked(boolean unchecked) throws IllegalStateException {
|
||||
if (unchecked) {
|
||||
if (isElastic())
|
||||
BytesUtil.WarnUncheckedElasticBytes.warn();
|
||||
Bytes<Underlying> underlyingBytes = start() == 0 && bytesStore().isDirectMemory() ?
|
||||
new UncheckedNativeBytes<>(this) :
|
||||
new UncheckedBytes<>(this);
|
||||
release(INIT);
|
||||
return underlyingBytes;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
default boolean unchecked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc <P>
|
||||
* If this Bytes {@link #isElastic()} the {@link #safeLimit()} can be
|
||||
* lower than the point it can safely write.
|
||||
*/
|
||||
@Override
|
||||
default long safeLimit() {
|
||||
return bytesStore().safeLimit();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isClear() {
|
||||
return start() == readPosition() && writeLimit() == capacity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc <P>
|
||||
* If this Bytes {@link #isElastic()} the {@link #realCapacity()} can be
|
||||
* lower than the virtual {@link #capacity()}.
|
||||
*/
|
||||
@Override
|
||||
default long realCapacity() {
|
||||
return BytesStore.super.realCapacity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a copy of this Bytes from position() to limit().
|
||||
*/
|
||||
@Override
|
||||
BytesStore<Bytes<Underlying>, Underlying> copy();
|
||||
|
||||
|
||||
default String toHexString() {
|
||||
return toHexString(1024);
|
||||
}
|
||||
|
||||
/**
|
||||
* display the hex data of {@link Bytes} from the position() to the limit()
|
||||
*
|
||||
* @param maxLength limit the number of bytes to be dumped.
|
||||
* @return hex representation of the buffer, from example [0D ,OA, FF]
|
||||
*/
|
||||
|
||||
default String toHexString(long maxLength) {
|
||||
return toHexString(readPosition(), maxLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* display the hex data of {@link Bytes} from the position() to the limit()
|
||||
*
|
||||
* @param maxLength limit the number of bytes to be dumped.
|
||||
* @return hex representation of the buffer, from example [0D ,OA, FF]
|
||||
*/
|
||||
|
||||
default String toHexString(long offset, long maxLength) {
|
||||
// if (Jvm.isDebug() && Jvm.stackTraceEndsWith("Bytes", 3))
|
||||
// return "Not Available";
|
||||
|
||||
long maxLength2 = Math.min(maxLength, readLimit() - offset);
|
||||
String ret = BytesInternal.toHexString(this, offset, maxLength2);
|
||||
return maxLength2 < readLimit() - offset ? ret + "... truncated" : ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this Bytes is elastic. I.e. it can resize when more data is written
|
||||
* than it's {@link #realCapacity()}.
|
||||
*
|
||||
* @return if this Bytes is elastic
|
||||
*/
|
||||
boolean isElastic();
|
||||
|
||||
/**
|
||||
* grow the buffer if the buffer is elastic, if the buffer is not elastic and there is not
|
||||
* enough capacity then this method will throws {@link java.nio.BufferOverflowException}
|
||||
*
|
||||
* @param size the capacity that you required
|
||||
* @throws IllegalArgumentException if the buffer is not elastic and there is not enough space
|
||||
*/
|
||||
default void ensureCapacity(long size) throws IllegalArgumentException {
|
||||
if (size > capacity())
|
||||
throw new IllegalArgumentException(isElastic() ? "todo" : "not elastic");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a slice of the current Bytes based on its position() and limit(). As a sub-section
|
||||
* of a Bytes it cannot be elastic.
|
||||
*
|
||||
* @return a slice of the existing Bytes where the start is moved to the position and the
|
||||
* current limit determines the capacity.
|
||||
* @throws IllegalStateException if the underlying BytesStore has been released
|
||||
*/
|
||||
|
||||
@Override
|
||||
default Bytes<Underlying> bytesForRead() throws IllegalStateException {
|
||||
return isClear() ? BytesStore.super.bytesForRead() : new SubBytes<>(this, readPosition(), readLimit() + start());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ByteStore this Bytes wraps.
|
||||
*/
|
||||
@Override
|
||||
|
||||
BytesStore bytesStore();
|
||||
|
||||
default boolean isEqual(String s) {
|
||||
return StringUtils.isEqual(this, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact these Bytes by moving the readPosition to the start.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
|
||||
Bytes<Underlying> compact();
|
||||
|
||||
/**
|
||||
* copy bytes from one ByteStore to another
|
||||
*
|
||||
* @param store to copy to
|
||||
* @return the number of bytes copied.
|
||||
*/
|
||||
@Override
|
||||
default long copyTo( BytesStore store) {
|
||||
return BytesStore.super.copyTo(store);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void copyTo( OutputStream out) throws IOException {
|
||||
BytesStore.super.copyTo(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean sharedMemory() {
|
||||
return bytesStore().sharedMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* will unwrite from the offset upto the current write position of the destination bytes
|
||||
*
|
||||
* @param fromOffset the offset from the target byytes
|
||||
* @param count the number of bytes to un-write
|
||||
*/
|
||||
default void unwrite(long fromOffset, int count) {
|
||||
long wp = writePosition();
|
||||
|
||||
if (wp < fromOffset)
|
||||
return;
|
||||
|
||||
write(fromOffset, this, fromOffset + count, wp - fromOffset - count);
|
||||
writeSkip(-count);
|
||||
}
|
||||
|
||||
|
||||
default BigDecimal readBigDecimal() {
|
||||
return new BigDecimal(readBigInteger(), Maths.toUInt31(readStopBit()));
|
||||
}
|
||||
|
||||
|
||||
default BigInteger readBigInteger() {
|
||||
int length = Maths.toUInt31(readStopBit());
|
||||
if (length == 0)
|
||||
if (lenient())
|
||||
return BigInteger.ZERO;
|
||||
else
|
||||
throw new BufferUnderflowException();
|
||||
byte[] bytes = new byte[length];
|
||||
read(bytes);
|
||||
return new BigInteger(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index within this bytes of the first occurrence of the
|
||||
* specified sub-bytes.
|
||||
* <p>
|
||||
* <p>The returned index is the smallest value <i>k</i> for which:
|
||||
* <blockquote><pre>
|
||||
* this.startsWith(bytes, <i>k</i>)
|
||||
* </pre></blockquote>
|
||||
* If no such value of <i>k</i> exists, then {@code -1} is returned.
|
||||
*
|
||||
* @param source the sub-bytes to search for.
|
||||
* @return the index of the first occurrence of the specified sub-bytes,
|
||||
* or {@code -1} if there is no such occurrence.
|
||||
*/
|
||||
default long indexOf( Bytes source) {
|
||||
return indexOf(source, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index within this bytes of the first occurrence of the
|
||||
* specified subbytes.
|
||||
* <p>
|
||||
* <p>The returned index is the smallest value <i>k</i> for which:
|
||||
* <blockquote><pre>
|
||||
* this.startsWith(bytes, <i>k</i>)
|
||||
* </pre></blockquote>
|
||||
* If no such value of <i>k</i> exists, then {@code -1} is returned.
|
||||
*
|
||||
* @param source the sub-bytes to search for.
|
||||
* @param fromIndex start the seach from this offset
|
||||
* @return the index of the first occurrence of the specified sub-bytes,
|
||||
* or {@code -1} if there is no such occurrence.
|
||||
*/
|
||||
default int indexOf( BytesStore source, int fromIndex) {
|
||||
return indexOf(this, source, fromIndex);
|
||||
}
|
||||
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
default long indexOf( Bytes source, int fromIndex) {
|
||||
return indexOf(this, source, fromIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Bytes<Underlying> clear();
|
||||
|
||||
@Override
|
||||
default boolean readWrite() {
|
||||
return bytesStore().readWrite();
|
||||
}
|
||||
|
||||
default void readWithLength(long length, BytesOut<Underlying> bytesOut)
|
||||
throws BufferUnderflowException, IORuntimeException {
|
||||
if (length > readRemaining())
|
||||
throw new BufferUnderflowException();
|
||||
long limit0 = readLimit();
|
||||
long limit = readPosition() + length;
|
||||
boolean lenient = lenient();
|
||||
try {
|
||||
lenient(true);
|
||||
readLimit(limit);
|
||||
bytesOut.write(this);
|
||||
} finally {
|
||||
readLimit(limit0);
|
||||
readPosition(limit);
|
||||
lenient(lenient);
|
||||
}
|
||||
}
|
||||
|
||||
default <T extends ReadBytesMarshallable> T readMarshallableLength16(Class<T> tClass, T object) {
|
||||
if (object == null) object = ObjectUtils.newInstance(tClass);
|
||||
int length = readUnsignedShort();
|
||||
long limit = readLimit();
|
||||
long end = readPosition() + length;
|
||||
boolean lenient = lenient();
|
||||
try {
|
||||
lenient(true);
|
||||
readLimit(end);
|
||||
object.readMarshallable(this);
|
||||
} finally {
|
||||
readPosition(end);
|
||||
readLimit(limit);
|
||||
lenient(lenient);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
default void writeMarshallableLength16(WriteBytesMarshallable marshallable) {
|
||||
long position = writePosition();
|
||||
writeUnsignedShort(0);
|
||||
marshallable.writeMarshallable(this);
|
||||
long length = writePosition() - position - 2;
|
||||
if (length >= 1 << 16)
|
||||
throw new IllegalStateException("Marshallable " + marshallable.getClass() + " too long was " + length);
|
||||
writeUnsignedShort(position, (int) length);
|
||||
}
|
||||
|
||||
default Bytes write(final InputStream inputStream) throws IOException {
|
||||
for (; ; ) {
|
||||
int read;
|
||||
read = inputStream.read();
|
||||
if (read == -1)
|
||||
break;
|
||||
writeByte((byte) read);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
public interface BytesComment<B extends BytesComment<B>> {
|
||||
/**
|
||||
* Do these Bytes support saving comments
|
||||
*
|
||||
* @return true if comments are kept
|
||||
*/
|
||||
default boolean retainsComments() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add comment as approriate for the toHexString format
|
||||
*
|
||||
* @param comment to add (or ignore)
|
||||
* @return this
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default B comment(CharSequence comment) {
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the indent for nested data
|
||||
*
|
||||
* @param n +1 indent in, -1 reduce indenting
|
||||
* @return this.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default B indent(int n) {
|
||||
return (B) this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface BytesConsumer {
|
||||
|
||||
/**
|
||||
* Retrieves and removes the head of this queue, or returns {@code true} if this queue is
|
||||
* empty.
|
||||
*
|
||||
* @param bytes to read into
|
||||
* @return false if this queue is empty
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
boolean read(BytesOut bytes) throws BufferOverflowException;
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.Closeable;
|
||||
|
||||
public interface BytesContext extends Closeable {
|
||||
|
||||
/**
|
||||
* @return a bytes to write to
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
Bytes bytes();
|
||||
|
||||
/**
|
||||
* @return the key to be written to
|
||||
*/
|
||||
int key();
|
||||
|
||||
@Override
|
||||
default boolean isClosed() {
|
||||
throw new UnsupportedOperationException("todo");
|
||||
}
|
||||
|
||||
default void rollbackOnClose() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public interface BytesIn<Underlying> extends
|
||||
RandomDataInput,
|
||||
ByteStringParser<Bytes<Underlying>> {
|
||||
/**
|
||||
* Reads messages from this tails as methods. It returns a BooleanSupplier which returns
|
||||
*
|
||||
* @param objects which implement the methods serialized to the file.
|
||||
* @return a reader which will read one Excerpt at a time
|
||||
*/
|
||||
|
||||
default MethodReader bytesMethodReader(Object... objects) {
|
||||
return new BytesMethodReaderBuilder(this).build(objects);
|
||||
}
|
||||
|
||||
|
||||
default BytesMethodReaderBuilder bytesMethodReaderBuilder() {
|
||||
return new BytesMethodReaderBuilder(this);
|
||||
}
|
||||
|
||||
<T extends ReadBytesMarshallable> T readMarshallableLength16(Class<T> tClass, T object);
|
||||
|
||||
default <T> T readObject(Class<T> componentType0) {
|
||||
Class<T> componentType = ObjectUtils.implementationToUse(componentType0);
|
||||
if (BytesMarshallable.class.isAssignableFrom(componentType)) {
|
||||
BytesMarshallable bm = (BytesMarshallable) ObjectUtils.newInstance(componentType);
|
||||
bm.readMarshallable(this);
|
||||
return (T) bm;
|
||||
}
|
||||
if (Enum.class.isAssignableFrom(componentType)) {
|
||||
return (T) readEnum((Class) componentType);
|
||||
}
|
||||
switch (componentType.getName()) {
|
||||
case "java.lang.String":
|
||||
return (T) readUtf8();
|
||||
case "java.lang.Double":
|
||||
return (T) (Double) readDouble();
|
||||
case "java.lang.Long":
|
||||
return (T) (Long) readLong();
|
||||
case "java.lang.Integer":
|
||||
return (T) (Integer) readInt();
|
||||
|
||||
default:
|
||||
if (BytesMarshallable.class.isAssignableFrom(componentType)) {
|
||||
BytesMarshallable bm = (BytesMarshallable) ObjectUtils.newInstance(componentType);
|
||||
bm.readMarshallable(this);
|
||||
return (T) bm;
|
||||
}
|
||||
throw new UnsupportedOperationException("Unsupported " + componentType);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.annotation.DontChain;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
|
||||
/**
|
||||
* An object which can be read or written directly to Bytes in a streaming manner.
|
||||
*/
|
||||
@DontChain
|
||||
public interface BytesMarshallable extends ReadBytesMarshallable, WriteBytesMarshallable {
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
default void readMarshallable(BytesIn bytes) throws IORuntimeException {
|
||||
BytesUtil.readMarshallable(this, bytes);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
default void writeMarshallable(BytesOut bytes) {
|
||||
BytesUtil.writeMarshallable(this, bytes);
|
||||
}
|
||||
|
||||
default String $toString() {
|
||||
HexDumpBytes bytes = new HexDumpBytes();
|
||||
writeMarshallable(bytes);
|
||||
String s = "# " + getClass().getName() + "\n" + bytes.toHexString();
|
||||
bytes.releaseLast();
|
||||
return s;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,759 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.ClassLocal;
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import net.openhft.chronicle.core.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class BytesMarshaller<T> {
|
||||
public static final ClassLocal<BytesMarshaller> BYTES_MARSHALLER_CL
|
||||
= ClassLocal.withInitial(BytesMarshaller::new);
|
||||
private final FieldAccess[] fields;
|
||||
|
||||
public BytesMarshaller( Class<T> tClass) {
|
||||
Map<String, Field> map = new LinkedHashMap<>();
|
||||
getAllField(tClass, map);
|
||||
fields = map.values().stream()
|
||||
.map(FieldAccess::create).toArray(FieldAccess[]::new);
|
||||
}
|
||||
|
||||
public static void getAllField( Class clazz, Map<String, Field> map) {
|
||||
if (clazz != Object.class)
|
||||
getAllField(clazz.getSuperclass(), map);
|
||||
for ( Field field : clazz.getDeclaredFields()) {
|
||||
if ((field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) != 0)
|
||||
continue;
|
||||
Jvm.setAccessible(field);
|
||||
map.put(field.getName(), field);
|
||||
}
|
||||
}
|
||||
|
||||
public void readMarshallable(ReadBytesMarshallable t, BytesIn in) {
|
||||
for ( FieldAccess field : fields) {
|
||||
field.read(t, in);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeMarshallable(WriteBytesMarshallable t, BytesOut out) {
|
||||
out.indent(+1);
|
||||
for ( FieldAccess field : fields) {
|
||||
field.write(t, out);
|
||||
}
|
||||
out.indent(-1);
|
||||
}
|
||||
|
||||
static abstract class FieldAccess<T> {
|
||||
final Field field;
|
||||
|
||||
FieldAccess(Field field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
|
||||
public static Object create( Field field) {
|
||||
Class<?> type = field.getType();
|
||||
switch (type.getName()) {
|
||||
case "boolean":
|
||||
return new BooleanFieldAccess(field);
|
||||
case "byte":
|
||||
return new ByteFieldAccess(field);
|
||||
case "char":
|
||||
return new CharFieldAccess(field);
|
||||
case "short":
|
||||
return new ShortFieldAccess(field);
|
||||
case "int":
|
||||
return new IntegerFieldAccess(field);
|
||||
case "float":
|
||||
return new FloatFieldAccess(field);
|
||||
case "long":
|
||||
return new LongFieldAccess(field);
|
||||
case "double":
|
||||
return new DoubleFieldAccess(field);
|
||||
default:
|
||||
if (type.isArray()) {
|
||||
if (type.getComponentType().isPrimitive()) {
|
||||
if (type == byte[].class)
|
||||
return new ByteArrayFieldAccess(field);
|
||||
if (type == int[].class)
|
||||
return new IntArrayFieldAccess(field);
|
||||
if (type == float[].class)
|
||||
return new FloatArrayFieldAccess(field);
|
||||
if (type == long[].class)
|
||||
return new LongArrayFieldAccess(field);
|
||||
if (type == double[].class)
|
||||
return new DoubleArrayFieldAccess(field);
|
||||
throw new UnsupportedOperationException("TODO " + field.getType());
|
||||
}
|
||||
return new ObjectArrayFieldAccess(field);
|
||||
}
|
||||
if (Collection.class.isAssignableFrom(type))
|
||||
return new CollectionFieldAccess(field);
|
||||
if (Map.class.isAssignableFrom(type))
|
||||
return new MapFieldAccess(field);
|
||||
if (BytesStore.class.isAssignableFrom(type))
|
||||
return new BytesFieldAccess(field);
|
||||
if (BytesMarshallable.class.isAssignableFrom(type))
|
||||
return new BytesMarshallableFieldAccess(field);
|
||||
return new ScalarFieldAccess(field);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Class extractClass(Type type0) {
|
||||
if (type0 instanceof Class)
|
||||
return (Class) type0;
|
||||
else if (type0 instanceof ParameterizedType)
|
||||
return (Class) ((ParameterizedType) type0).getRawType();
|
||||
else
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "{" +
|
||||
"field=" + field +
|
||||
'}';
|
||||
}
|
||||
|
||||
void write(Object o, BytesOut write) {
|
||||
try {
|
||||
write.comment(field.getName());
|
||||
getValue(o, write);
|
||||
} catch (IllegalAccessException iae) {
|
||||
throw new AssertionError(iae);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void getValue(Object o, BytesOut write) throws IllegalAccessException;
|
||||
|
||||
void read(Object o, BytesIn read) {
|
||||
try {
|
||||
setValue(o, read);
|
||||
} catch (IllegalAccessException iae) {
|
||||
throw new AssertionError(iae);
|
||||
} catch (IORuntimeException e) {
|
||||
throw Jvm.rethrow(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void setValue(Object o, BytesIn read) throws IllegalAccessException, IORuntimeException;
|
||||
|
||||
|
||||
protected Supplier<Map> newInstance( Class type) {
|
||||
try {
|
||||
return (Supplier<Map>) type.newInstance();
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (InstantiationException e) {
|
||||
throw Jvm.rethrow(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class ScalarFieldAccess extends FieldAccess<Object> {
|
||||
public ScalarFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
Object o2 = field.get(o);
|
||||
String s = o2 == null ? null : o2.toString();
|
||||
write.writeUtf8(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException, IORuntimeException {
|
||||
String s = read.readUtf8();
|
||||
field.set(o, ObjectUtils.convertTo(field.getType(), s));
|
||||
}
|
||||
}
|
||||
|
||||
static class BytesMarshallableFieldAccess extends FieldAccess<Object> {
|
||||
public BytesMarshallableFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
BytesMarshallable o2 = (BytesMarshallable) field.get(o);
|
||||
assert o2 != null;
|
||||
o2.writeMarshallable(write);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException, IORuntimeException {
|
||||
BytesMarshallable o2 = (BytesMarshallable) field.get(o);
|
||||
if (!field.getType().isInstance(o2))
|
||||
field.set(o, o2 = (BytesMarshallable) ObjectUtils.newInstance((Class) field.getType()));
|
||||
|
||||
o2.readMarshallable(read);
|
||||
}
|
||||
}
|
||||
|
||||
static class BytesFieldAccess extends FieldAccess<Bytes> {
|
||||
public BytesFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
BytesStore bytes = (BytesStore) field.get(o);
|
||||
if (bytes == null) {
|
||||
write.writeStopBit(-1);
|
||||
return;
|
||||
}
|
||||
long offset = bytes.readPosition();
|
||||
long length = bytes.readRemaining();
|
||||
write.writeStopBit(length);
|
||||
write.write(bytes, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException, IORuntimeException {
|
||||
Bytes bytes = (Bytes) field.get(o);
|
||||
long stopBit = read.readStopBit();
|
||||
if (stopBit == -1) {
|
||||
if (bytes != null)
|
||||
bytes.releaseLast();
|
||||
field.set(o, null);
|
||||
return;
|
||||
}
|
||||
int length = Maths.toUInt31(stopBit);
|
||||
Bytes bs;
|
||||
if (bytes == null) {
|
||||
bs = Bytes.allocateElasticOnHeap(length);
|
||||
field.set(o, bs);
|
||||
} else {
|
||||
bs = bytes;
|
||||
}
|
||||
bs.clear();
|
||||
read.read(bs, length);
|
||||
bs.readLimit(length);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
static class ArrayFieldAccess extends FieldAccess {
|
||||
private final Class componentType;
|
||||
|
||||
public ArrayFieldAccess( Field field) {
|
||||
super(field);
|
||||
componentType = field.getType().getComponentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static class ObjectArrayFieldAccess extends FieldAccess {
|
||||
Class componentType;
|
||||
|
||||
public ObjectArrayFieldAccess(Field field) {
|
||||
super(field);
|
||||
componentType = field.getType().getComponentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
Object[] c = (Object[]) field.get(o);
|
||||
if (c == null) {
|
||||
write.writeStopBit(-1);
|
||||
return;
|
||||
}
|
||||
int size = c.length;
|
||||
write.writeStopBit(size);
|
||||
if (size == 0)
|
||||
return;
|
||||
for (int i = 0; i < size; i++)
|
||||
write.writeObject(componentType, c[i]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
Object[] c = (Object[]) field.get(o);
|
||||
int length = Maths.toInt32(read.readStopBit());
|
||||
if (length < 0) {
|
||||
if (c != null)
|
||||
field.set(o, null);
|
||||
return;
|
||||
}
|
||||
if (c == null)
|
||||
field.set(o, c = (Object[]) Array.newInstance(field.getType().getComponentType(), length));
|
||||
else if (c.length != length)
|
||||
field.set(o, c = Arrays.copyOf(c, length));
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object o2 = c[i];
|
||||
if (o2 instanceof BytesMarshallable)
|
||||
((BytesMarshallable) o2).readMarshallable(read);
|
||||
else
|
||||
c[i] = read.readObject(componentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class CollectionFieldAccess extends FieldAccess {
|
||||
final Supplier<Collection> collectionSupplier;
|
||||
|
||||
private final Class componentType;
|
||||
private final Class<?> type;
|
||||
|
||||
public CollectionFieldAccess( Field field) {
|
||||
super(field);
|
||||
type = field.getType();
|
||||
if (type == List.class || type == Collection.class)
|
||||
collectionSupplier = ArrayList::new;
|
||||
else if (type == SortedSet.class || type == NavigableSet.class)
|
||||
collectionSupplier = TreeSet::new;
|
||||
else if (type == Set.class)
|
||||
collectionSupplier = LinkedHashSet::new;
|
||||
else
|
||||
collectionSupplier = newInstance(type);
|
||||
Type genericType = field.getGenericType();
|
||||
if (genericType instanceof ParameterizedType) {
|
||||
ParameterizedType pType = (ParameterizedType) genericType;
|
||||
Type type0 = pType.getActualTypeArguments()[0];
|
||||
componentType = extractClass(type0);
|
||||
} else {
|
||||
componentType = Object.class;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
Collection c = (Collection) field.get(o);
|
||||
if (c == null) {
|
||||
write.writeStopBit(-1);
|
||||
return;
|
||||
}
|
||||
write.writeStopBit(c.size());
|
||||
if (c.isEmpty())
|
||||
return;
|
||||
if (c instanceof RandomAccess && c instanceof List) {
|
||||
List l = (List) c;
|
||||
for (int i = 0, size = l.size(); i < size; i++)
|
||||
write.writeObject(componentType, l.get(i));
|
||||
} else {
|
||||
for (Object o2 : c) {
|
||||
write.writeObject(componentType, o2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
Collection c = (Collection) field.get(o);
|
||||
int length = Maths.toInt32(read.readStopBit());
|
||||
if (length < 0) {
|
||||
if (c != null)
|
||||
field.set(o, null);
|
||||
return;
|
||||
}
|
||||
c.clear();
|
||||
for (int i = 0; i < length; i++)
|
||||
c.add(read.readObject(componentType));
|
||||
}
|
||||
}
|
||||
|
||||
static class MapFieldAccess extends FieldAccess {
|
||||
final Supplier<Map> collectionSupplier;
|
||||
private final Class<?> type;
|
||||
|
||||
private final Class keyType;
|
||||
|
||||
private final Class valueType;
|
||||
|
||||
public MapFieldAccess( Field field) {
|
||||
super(field);
|
||||
type = field.getType();
|
||||
if (type == Map.class)
|
||||
collectionSupplier = LinkedHashMap::new;
|
||||
else if (type == SortedMap.class || type == NavigableMap.class)
|
||||
collectionSupplier = TreeMap::new;
|
||||
else
|
||||
collectionSupplier = newInstance(type);
|
||||
Type genericType = field.getGenericType();
|
||||
if (genericType instanceof ParameterizedType) {
|
||||
ParameterizedType pType = (ParameterizedType) genericType;
|
||||
Type[] actualTypeArguments = pType.getActualTypeArguments();
|
||||
keyType = extractClass(actualTypeArguments[0]);
|
||||
valueType = extractClass(actualTypeArguments[1]);
|
||||
|
||||
} else {
|
||||
keyType = Object.class;
|
||||
valueType = Object.class;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
Map<?, ?> m = (Map) field.get(o);
|
||||
if (m == null) {
|
||||
write.writeStopBit(-1);
|
||||
return;
|
||||
}
|
||||
write.writeStopBit(m.size());
|
||||
for (Map.Entry<?, ?> entry : m.entrySet()) {
|
||||
write.writeObject(keyType, entry.getKey());
|
||||
write.writeObject(valueType, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
Map m = (Map) field.get(o);
|
||||
long length = read.readStopBit();
|
||||
if (length < 0) {
|
||||
if (m != null)
|
||||
field.set(o, null);
|
||||
return;
|
||||
}
|
||||
if (m == null) {
|
||||
field.set(o, m = new LinkedHashMap<>());
|
||||
} else {
|
||||
m.clear();
|
||||
}
|
||||
for (int i = 0; i < length; i++) {
|
||||
m.put(read.readObject(keyType), read.readObject(valueType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class BooleanFieldAccess extends FieldAccess {
|
||||
public BooleanFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
write.writeBoolean(field.getBoolean(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
field.setBoolean(o, read.readBoolean());
|
||||
}
|
||||
}
|
||||
|
||||
static class ByteFieldAccess extends FieldAccess {
|
||||
public ByteFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
write.writeByte(field.getByte(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
field.setByte(o, read.readByte());
|
||||
}
|
||||
}
|
||||
|
||||
static class ByteArrayFieldAccess extends FieldAccess {
|
||||
public ByteArrayFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
byte[] array = (byte[]) field.get(o);
|
||||
if (array == null) {
|
||||
write.writeInt(~0);
|
||||
} else {
|
||||
write.writeInt(array.length);
|
||||
for (int i = 0; i < array.length; i++)
|
||||
write.writeByte(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
int len = read.readInt();
|
||||
if (len == ~0) {
|
||||
field.set(o, null);
|
||||
} else if (len >= 0) {
|
||||
byte[] array = (byte[]) field.get(o);
|
||||
if (array == null || array.length != len) {
|
||||
array = new byte[len];
|
||||
field.set(o, array);
|
||||
}
|
||||
for (int i = 0; i < len; i++)
|
||||
array[i] = read.readByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class CharFieldAccess extends FieldAccess {
|
||||
public CharFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
char aChar = field.getChar(o);
|
||||
if (aChar >= 65536 - 127)
|
||||
write.writeStopBit(aChar - 65536);
|
||||
else
|
||||
write.writeStopBit(aChar);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
field.setChar(o, read.readStopBitChar());
|
||||
}
|
||||
}
|
||||
|
||||
static class ShortFieldAccess extends FieldAccess {
|
||||
public ShortFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
write.writeShort(field.getShort(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
field.setShort(o, read.readShort());
|
||||
}
|
||||
}
|
||||
|
||||
static class IntegerFieldAccess extends FieldAccess {
|
||||
public IntegerFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
write.writeInt(field.getInt(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
field.setInt(o, read.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
static class IntArrayFieldAccess extends FieldAccess {
|
||||
public IntArrayFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
int[] array = (int[]) field.get(o);
|
||||
if (array == null) {
|
||||
write.writeInt(~0);
|
||||
} else {
|
||||
write.writeInt(array.length);
|
||||
for (int i = 0; i < array.length; i++)
|
||||
write.writeInt(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
int len = read.readInt();
|
||||
if (len == ~0) {
|
||||
field.set(o, null);
|
||||
} else if (len >= 0) {
|
||||
int[] array = (int[]) field.get(o);
|
||||
if (array == null || array.length != len) {
|
||||
array = new int[len];
|
||||
field.set(o, array);
|
||||
}
|
||||
for (int i = 0; i < len; i++)
|
||||
array[i] = read.readInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class FloatFieldAccess extends FieldAccess {
|
||||
public FloatFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
write.writeFloat(field.getFloat(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
field.setFloat(o, read.readFloat());
|
||||
}
|
||||
}
|
||||
|
||||
static class FloatArrayFieldAccess extends FieldAccess {
|
||||
public FloatArrayFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
float[] array = (float[]) field.get(o);
|
||||
if (array == null) {
|
||||
write.writeInt(~0);
|
||||
} else {
|
||||
write.writeInt(array.length);
|
||||
for (int i = 0; i < array.length; i++)
|
||||
write.writeFloat(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
int len = read.readInt();
|
||||
if (len == ~0) {
|
||||
field.set(o, null);
|
||||
} else if (len >= 0) {
|
||||
float[] array = (float[]) field.get(o);
|
||||
if (array == null || array.length != len) {
|
||||
array = new float[len];
|
||||
field.set(o, array);
|
||||
}
|
||||
for (int i = 0; i < len; i++)
|
||||
array[i] = read.readFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class LongFieldAccess extends FieldAccess {
|
||||
public LongFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
write.writeLong(field.getLong(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
field.setLong(o, read.readLong());
|
||||
}
|
||||
}
|
||||
|
||||
static class LongArrayFieldAccess extends FieldAccess {
|
||||
public LongArrayFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
long[] array = (long[]) field.get(o);
|
||||
if (array == null) {
|
||||
write.writeInt(~0);
|
||||
} else {
|
||||
write.writeInt(array.length);
|
||||
for (int i = 0; i < array.length; i++)
|
||||
write.writeLong(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
int len = read.readInt();
|
||||
if (len == ~0) {
|
||||
field.set(o, null);
|
||||
} else if (len >= 0) {
|
||||
long[] array = (long[]) field.get(o);
|
||||
if (array == null || array.length != len) {
|
||||
array = new long[len];
|
||||
field.set(o, array);
|
||||
}
|
||||
for (int i = 0; i < len; i++)
|
||||
array[i] = read.readLong();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class DoubleFieldAccess extends FieldAccess {
|
||||
public DoubleFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
write.writeDouble(field.getDouble(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
field.setDouble(o, read.readDouble());
|
||||
}
|
||||
}
|
||||
|
||||
static class DoubleArrayFieldAccess extends FieldAccess {
|
||||
public DoubleArrayFieldAccess(Field field) {
|
||||
super(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getValue(Object o, BytesOut write) throws IllegalAccessException {
|
||||
double[] array = (double[]) field.get(o);
|
||||
if (array == null) {
|
||||
write.writeInt(~0);
|
||||
} else {
|
||||
write.writeInt(array.length);
|
||||
for (int i = 0; i < array.length; i++)
|
||||
write.writeDouble(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValue(Object o, BytesIn read) throws IllegalAccessException {
|
||||
int len = read.readInt();
|
||||
if (len == ~0) {
|
||||
field.set(o, null);
|
||||
} else if (len >= 0) {
|
||||
double[] array = (double[]) field.get(o);
|
||||
if (array == null || array.length != len) {
|
||||
array = new double[len];
|
||||
field.set(o, array);
|
||||
}
|
||||
for (int i = 0; i < len; i++)
|
||||
array[i] = read.readDouble();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.io.SimpleCloseable;
|
||||
import net.openhft.chronicle.core.util.InvocationTargetRuntimeException;
|
||||
import net.openhft.chronicle.core.util.ObjectUtils;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class BytesMethodReader extends SimpleCloseable implements MethodReader {
|
||||
private final BytesIn in;
|
||||
private final BytesParselet defaultParselet;
|
||||
private final List<Consumer<BytesIn>> methodEncoders = new ArrayList<>();
|
||||
private final Map<Long, Consumer<BytesIn>> methodEncoderMap = new LinkedHashMap<>();
|
||||
|
||||
public BytesMethodReader(BytesIn in,
|
||||
BytesParselet defaultParselet,
|
||||
MethodEncoderLookup methodEncoderLookup,
|
||||
Object[] objects) {
|
||||
|
||||
this.in = in;
|
||||
this.defaultParselet = defaultParselet;
|
||||
|
||||
for (Object object : objects) {
|
||||
for (Method method : object.getClass().getMethods()) {
|
||||
MethodEncoder encoder = methodEncoderLookup.apply(method);
|
||||
if (encoder != null) {
|
||||
addEncoder(object, method, encoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addEncoder(Object object, Method method, MethodEncoder encoder) {
|
||||
Jvm.setAccessible(method);
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
int count = parameterTypes.length;
|
||||
BytesMarshallable[][] array = new BytesMarshallable[1][count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
array[0][i] = (BytesMarshallable) ObjectUtils.newInstance(parameterTypes[i]);
|
||||
}
|
||||
Consumer<BytesIn> reader = in -> {
|
||||
array[0] = (BytesMarshallable[]) encoder.decode(array[0], in);
|
||||
try {
|
||||
method.invoke(object, array[0]);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
Jvm.warn().on(getClass(), "Exception calling " + method + " " + Arrays.toString(array[0]), e);
|
||||
}
|
||||
};
|
||||
long messageId = encoder.messageId();
|
||||
if (messageId >= 0 && messageId < 1000) {
|
||||
while (methodEncoders.size() <= messageId)
|
||||
methodEncoders.add(null);
|
||||
methodEncoders.set((int) messageId, reader);
|
||||
} else {
|
||||
methodEncoderMap.put(messageId, reader);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodReaderInterceptorReturns methodReaderInterceptorReturns() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean readOne() throws InvocationTargetRuntimeException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
if (in.readRemaining() < 1)
|
||||
return false;
|
||||
long messageId = in.readStopBit();
|
||||
Consumer<BytesIn> consumer;
|
||||
if (messageId >= 0 && messageId < methodEncoders.size())
|
||||
consumer = methodEncoders.get((int) messageId);
|
||||
else
|
||||
consumer = methodEncoderMap.get(messageId);
|
||||
if (consumer == null) {
|
||||
defaultParselet.accept(messageId, in);
|
||||
} else {
|
||||
consumer.accept(in);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodReader closeIn(boolean closeIn) {
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class BytesMethodReaderBuilder implements MethodReaderBuilder {
|
||||
private final BytesIn in;
|
||||
private BytesParselet defaultParselet = createDefaultParselet();
|
||||
private MethodEncoderLookup methodEncoderLookup = MethodEncoderLookup.BY_ANNOTATION;
|
||||
|
||||
public BytesMethodReaderBuilder(BytesIn in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
|
||||
static BytesParselet createDefaultParselet() {
|
||||
return (msg, in) -> {
|
||||
Bytes bytes = (Bytes) in;
|
||||
throw new IllegalArgumentException("Unknown message type " + msg + " " + bytes.toHexString());
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodReaderBuilder warnMissing(boolean warnMissing) {
|
||||
// always true
|
||||
return this;
|
||||
}
|
||||
|
||||
public MethodEncoderLookup methodEncoderLookup() {
|
||||
return methodEncoderLookup;
|
||||
}
|
||||
|
||||
public BytesMethodReaderBuilder methodEncoderLookup(MethodEncoderLookup methodEncoderLookup) {
|
||||
this.methodEncoderLookup = methodEncoderLookup;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BytesParselet defaultParselet() {
|
||||
return defaultParselet;
|
||||
}
|
||||
|
||||
public BytesMethodReaderBuilder defaultParselet(BytesParselet defaultParselet) {
|
||||
this.defaultParselet = defaultParselet;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodReaderBuilder methodReaderInterceptorReturns(MethodReaderInterceptorReturns methodReaderInterceptorReturns) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public BytesMethodReader build(Object... objects) {
|
||||
return new BytesMethodReader(in, defaultParselet, methodEncoderLookup, objects);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.Closeable;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
|
||||
public interface BytesMethodWriterInvocationHandler extends InvocationHandler {
|
||||
|
||||
void onClose(Closeable closeable);
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.function.Function;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public interface BytesOut<Underlying> extends
|
||||
ByteStringAppender<Bytes<Underlying>>,
|
||||
BytesPrepender<Bytes<Underlying>>,
|
||||
BytesComment<BytesOut<Underlying>> {
|
||||
|
||||
/**
|
||||
* Proxy an interface so each message called is written to a file for replay.
|
||||
*
|
||||
* @param tClass primary interface
|
||||
* @param additional any additional interfaces
|
||||
* @return a proxy which implements the primary interface (additional interfaces have to be
|
||||
* cast)
|
||||
*/
|
||||
|
||||
default <T> T bytesMethodWriter( Class<T> tClass, Class... additional) {
|
||||
Class[] interfaces = ObjectUtils.addAll(tClass, additional);
|
||||
|
||||
//noinspection unchecked
|
||||
return (T) Proxy.newProxyInstance(tClass.getClassLoader(), interfaces,
|
||||
new BinaryBytesMethodWriterInvocationHandler(MethodEncoderLookup.BY_ANNOTATION, this));
|
||||
}
|
||||
|
||||
void writeMarshallableLength16(WriteBytesMarshallable marshallable);
|
||||
|
||||
/**
|
||||
* Write a limit set of writeObject types.
|
||||
*
|
||||
* @param componentType expected.
|
||||
* @param obj of componentType
|
||||
*/
|
||||
default void writeObject(Class componentType, Object obj) {
|
||||
if (!componentType.isInstance(obj))
|
||||
throw new IllegalArgumentException("Cannot serialize " + obj.getClass() + " as an " + componentType);
|
||||
if (obj instanceof BytesMarshallable) {
|
||||
((BytesMarshallable) obj).writeMarshallable(this);
|
||||
return;
|
||||
}
|
||||
if (obj instanceof Enum) {
|
||||
writeEnum((Enum) obj);
|
||||
return;
|
||||
}
|
||||
if (obj instanceof BytesStore) {
|
||||
BytesStore bs = (BytesStore) obj;
|
||||
writeStopBit(bs.readRemaining());
|
||||
write(bs);
|
||||
return;
|
||||
}
|
||||
switch (componentType.getName()) {
|
||||
case "java.lang.String":
|
||||
writeUtf8((String) obj);
|
||||
return;
|
||||
case "java.lang.Double":
|
||||
writeDouble((Double) obj);
|
||||
return;
|
||||
case "java.lang.Long":
|
||||
writeLong((Long) obj);
|
||||
return;
|
||||
case "java.lang.Integer":
|
||||
writeInt((Integer) obj);
|
||||
return;
|
||||
|
||||
default:
|
||||
throw new UnsupportedOperationException("Not supported " + componentType);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface BytesParselet {
|
||||
@SuppressWarnings("rawtypes")
|
||||
void accept(long messageType, BytesIn in);
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
|
||||
public interface BytesPrepender<B extends BytesPrepender<B>> {
|
||||
|
||||
/**
|
||||
* Clear a buffer, with a given padding to allow for prepending later. clearAndPad(0) is the same as clear()
|
||||
*
|
||||
* @param length to pad
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the length > capacity() - start()
|
||||
*/
|
||||
|
||||
B clearAndPad(long length) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Prepends a long in decimal, this method moves the readPosition() backwards.
|
||||
* <p>Note: it moves the readPosition not the writePosition / readLimit</p>
|
||||
*
|
||||
* @param value to prepend as text.
|
||||
* @return this
|
||||
* @throws BufferUnderflowException if the capacity of the underlying buffer was exceeded
|
||||
* @throws IORuntimeException if an error occurred while attempting to resize the underlying buffer
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
default B prepend(long value) throws BufferOverflowException {
|
||||
BytesInternal.prepend(this, value);
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write backward in binary a byte
|
||||
* <p>Note: it moves the readPosition not the writePosition / readLimit</p>
|
||||
*
|
||||
* @param bytes to prepend to.
|
||||
*/
|
||||
|
||||
B prewrite(byte[] bytes) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Write backward in binary a byte
|
||||
* <p>Note: it moves the readPosition not the writePosition / readLimit</p>
|
||||
*
|
||||
* @param bytes to prepend to.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
|
||||
B prewrite(BytesStore bytes) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Write backward in binary a byte
|
||||
* <p>Note: it moves the readPosition not the writePosition / readLimit</p>
|
||||
*
|
||||
* @param b byte to prepend to.
|
||||
*/
|
||||
|
||||
B prewriteByte(byte b) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Write backward in binary a 2 byte int
|
||||
* <p>Note: it moves the readPosition not the writePosition / readLimit</p>
|
||||
*
|
||||
* @param i short to prepend to.
|
||||
*/
|
||||
|
||||
B prewriteShort(short i) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Write backward in binary a 4 byte int
|
||||
* <p>Note: it moves the readPosition not the writePosition / readLimit</p>
|
||||
*
|
||||
* @param i integer to prepend to.
|
||||
*/
|
||||
|
||||
B prewriteInt(int i) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Write backward in binary an 8 byte long
|
||||
* <p>Note: it moves the readPosition not the writePosition / readLimit</p>
|
||||
*
|
||||
* @param l long to prepend to.
|
||||
*/
|
||||
|
||||
B prewriteLong(long l) throws BufferOverflowException;
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.io.Closeable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.BufferOverflowException;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public interface BytesRingBuffer extends BytesRingBufferStats, BytesConsumer, Closeable {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(BytesRingBuffer.class);
|
||||
|
||||
|
||||
static BytesRingBuffer newInstance( NativeBytesStore<Void> bytesStore) {
|
||||
return newInstance(bytesStore, 1);
|
||||
}
|
||||
|
||||
|
||||
static MultiReaderBytesRingBuffer newInstance(
|
||||
NativeBytesStore<Void> bytesStore,
|
||||
int numReaders) {
|
||||
try {
|
||||
final Class<MultiReaderBytesRingBuffer> aClass = clazz();
|
||||
final Constructor<MultiReaderBytesRingBuffer> constructor = aClass
|
||||
.getDeclaredConstructor(BytesStore.class, int.class);
|
||||
return constructor.newInstance(bytesStore, numReaders);
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error("This is a a commercial feature, please contact " +
|
||||
"sales@chronicle.software to unlock this feature.");
|
||||
|
||||
throw Jvm.rethrow(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Class<MultiReaderBytesRingBuffer> clazz() throws ClassNotFoundException {
|
||||
//noinspection AccessStaticViaInstance
|
||||
return (Class<MultiReaderBytesRingBuffer>) Class.forName(
|
||||
"software.chronicle.enterprise.ring.EnterpriseRingBuffer");
|
||||
}
|
||||
|
||||
static long sizeFor(long capacity) {
|
||||
return sizeFor(capacity, 1);
|
||||
}
|
||||
|
||||
static long sizeFor(long capacity, int numReaders) {
|
||||
try {
|
||||
//noinspection AccessStaticViaInstance
|
||||
final Method sizeFor = Class.forName(
|
||||
"software.chronicle.enterprise.queue.ChronicleRingBuffer").getMethod("sizeFor", long.class, int.class);
|
||||
return (long) sizeFor.invoke(null, capacity, numReaders);
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error("This is a a commercial feature, please contact " +
|
||||
"sales@chronicle.software to unlock this feature.");
|
||||
|
||||
throw Jvm.rethrow(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clears the ring buffer but moving the read position to the write position
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Inserts the specified element at the tail of this queue if it is possible to do so
|
||||
* immediately without exceeding the queue's capacity,
|
||||
*
|
||||
* @param bytes0 the {@code bytes0} that you wish to add to the ring buffer
|
||||
* @return returning {@code true} upon success and {@code false} if this queue is full.
|
||||
*/
|
||||
boolean offer( BytesStore bytes0);
|
||||
|
||||
/**
|
||||
* Retrieves and removes the head of this queue, or returns {@code null} if this queue is
|
||||
* empty.
|
||||
*
|
||||
* @param using Bytes to read into.
|
||||
* @return false if this queue is empty, or a populated buffer if the element was retried
|
||||
* @throws BufferOverflowException is the {@code using} buffer is not large enough
|
||||
*/
|
||||
@Override
|
||||
boolean read( BytesOut using);
|
||||
|
||||
long readRemaining();
|
||||
|
||||
boolean isEmpty();
|
||||
|
||||
BytesStore bytesStore();
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface BytesRingBufferStats {
|
||||
/**
|
||||
* each time the ring is read, this logs the number of bytes in the write buffer, calling this
|
||||
* method resets these statistics,
|
||||
*
|
||||
* @return Long.MAX_VALUE if no read calls were made since the last time this method was called.
|
||||
*/
|
||||
long minNumberOfWriteBytesRemaining();
|
||||
|
||||
/**
|
||||
* @return the total capacity in bytes
|
||||
*/
|
||||
long capacity();
|
||||
|
||||
long getAndClearWriteCount();
|
||||
|
||||
long getAndClearMissedWriteCount();
|
||||
|
||||
long getAndClearContentionCount();
|
||||
|
||||
List<RingBufferReaderStats> readers();
|
||||
}
|
|
@ -0,0 +1,570 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import net.openhft.chronicle.core.io.ReferenceCounted;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static java.lang.Math.min;
|
||||
|
||||
/**
|
||||
* A immutable reference to some bytes with fixed extents. This can be shared safely across thread
|
||||
* provided the data referenced is accessed in a thread safe manner. Only offset access within the
|
||||
* capacity is possible.
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public interface BytesStore<B extends BytesStore<B, Underlying>, Underlying>
|
||||
extends RandomDataInput, RandomDataOutput<B>, ReferenceCounted, CharSequence {
|
||||
|
||||
/**
|
||||
* This method builds a BytesStore using the bytes in a CharSequence. This chars are encoded
|
||||
* using ISO_8859_1
|
||||
*
|
||||
* @param cs to convert
|
||||
* @return BytesStore
|
||||
*/
|
||||
static BytesStore from( CharSequence cs) {
|
||||
if (cs instanceof BytesStore)
|
||||
return ((BytesStore) cs).copy();
|
||||
return HeapBytesStore.wrap(cs.toString().getBytes(StandardCharsets.ISO_8859_1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a byte[]. This means there is one copy in memory.
|
||||
*
|
||||
* @param bytes to wrap
|
||||
* @return BytesStore
|
||||
*/
|
||||
static HeapBytesStore<byte[]> wrap( byte[] bytes) {
|
||||
return HeapBytesStore.wrap(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a ByteBuffer which can be either on heap or off heap.
|
||||
*
|
||||
* @param bb to wrap
|
||||
* @return BytesStore
|
||||
*/
|
||||
|
||||
static BytesStore<?, ByteBuffer> wrap( ByteBuffer bb) {
|
||||
return bb.isDirect()
|
||||
? NativeBytesStore.wrap(bb)
|
||||
: HeapBytesStore.wrap(bb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a PointerBytesStore which can be set to any addressForRead
|
||||
*/
|
||||
|
||||
static PointerBytesStore nativePointer() {
|
||||
return new PointerBytesStore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the addressForRead and length as a BytesStore
|
||||
*
|
||||
* @param address for the start
|
||||
* @param length of data
|
||||
* @return as a BytesStore
|
||||
*/
|
||||
|
||||
static PointerBytesStore wrap(long address, long length) {
|
||||
PointerBytesStore pbs = nativePointer();
|
||||
pbs.set(address, length);
|
||||
return pbs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an empty, fixed sized Bytes
|
||||
*/
|
||||
static BytesStore empty() {
|
||||
return NoBytesStore.noBytesStore();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether it uses direct memory or not.
|
||||
*/
|
||||
@Override
|
||||
boolean isDirectMemory();
|
||||
|
||||
/**
|
||||
* @return a copy of this BytesStore.
|
||||
*/
|
||||
BytesStore<B, Underlying> copy();
|
||||
|
||||
/**
|
||||
* @return a Bytes to wrap this ByteStore from the start() to the realCapacity().
|
||||
* @throws IllegalStateException if this Bytes has been released.
|
||||
*/
|
||||
@Override
|
||||
|
||||
default Bytes<Underlying> bytesForRead() throws IllegalStateException {
|
||||
try {
|
||||
Bytes<Underlying> ret = bytesForWrite();
|
||||
ret.readLimit(writeLimit());
|
||||
ret.writeLimit(realCapacity());
|
||||
ret.readPosition(start());
|
||||
return ret;
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a Bytes for writing to this BytesStore
|
||||
*/
|
||||
@Override
|
||||
|
||||
default Bytes<Underlying> bytesForWrite() throws IllegalStateException {
|
||||
return new VanillaBytes<>(this, writePosition(), writeLimit());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the {@code readPosition} is at the {@code start} and
|
||||
* the {@code writeLimit} is at the {@code end}.
|
||||
* <p>
|
||||
* I.e {@code start() == readPosition() && writeLimit() == capacity()}
|
||||
*
|
||||
* @return if the {@code readPosition} is at the {@code start} and
|
||||
* the {@code writeLimit} is at the {@code end}
|
||||
*/
|
||||
default boolean isClear() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actual capacity available before resizing.
|
||||
*/
|
||||
@Override
|
||||
default long realCapacity() {
|
||||
return capacity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The maximum limit you can set.
|
||||
*/
|
||||
@Override
|
||||
long capacity();
|
||||
|
||||
/**
|
||||
* @return the underlying object being wrapped, if there is one, or null if not.
|
||||
*/
|
||||
|
||||
Underlying underlyingObject();
|
||||
|
||||
/**
|
||||
* Use this test to determine if an offset is considered safe.
|
||||
*/
|
||||
default boolean inside(long offset) {
|
||||
return start() <= offset && offset < safeLimit();
|
||||
}
|
||||
|
||||
default boolean inside(long offset, long buffer) {
|
||||
return start() <= offset && offset + buffer < safeLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return how many bytes can be safely read, i.e. what is the real capacity of the underlying data.
|
||||
*/
|
||||
default long safeLimit() {
|
||||
return capacity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the data to another BytesStore as long as there is space available in the destination store.
|
||||
*
|
||||
* @param store to copy to
|
||||
* @return how many bytes were copied
|
||||
*/
|
||||
default long copyTo( BytesStore store) {
|
||||
long readPos = readPosition();
|
||||
long writePos = store.writePosition();
|
||||
long copy = min(readRemaining(), store.capacity());
|
||||
long i = 0;
|
||||
try {
|
||||
for (; i < copy - 7; i += 8)
|
||||
store.writeLong(writePos + i, readLong(readPos + i));
|
||||
for (; i < copy; i++)
|
||||
store.writeByte(writePos + i, readByte(readPos + i));
|
||||
} catch (BufferOverflowException | BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
default void copyTo( OutputStream out) throws IOException {
|
||||
BytesInternal.copy(this, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the BytesStore with zeros
|
||||
*
|
||||
* @param start first byte inclusive
|
||||
* @param end last byte exclusive.
|
||||
* @return this.
|
||||
*/
|
||||
@Override
|
||||
|
||||
default B zeroOut(long start, long end) {
|
||||
if (end <= start)
|
||||
return (B) this;
|
||||
if (start < start())
|
||||
start = start();
|
||||
if (end > capacity())
|
||||
end = capacity();
|
||||
long i = start;
|
||||
try {
|
||||
for (; i < end - 7; i += 8L)
|
||||
writeLong(i, 0L);
|
||||
for (; i < end; i++)
|
||||
writeByte(i, 0);
|
||||
} catch (BufferOverflowException | IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is inherited from CharSequence so result should be the length of the contained
|
||||
* chars sequence although it actually returns the number of underlying bytes. These 2 numbers are only the same
|
||||
* if the encoding we are using is single char for single byte.
|
||||
*
|
||||
* @return length in bytes to read or Integer.MAX_VALUE if longer.
|
||||
*/
|
||||
@Override
|
||||
default int length() {
|
||||
return (int) Math.min(Integer.MAX_VALUE, readRemaining());
|
||||
}
|
||||
|
||||
/**
|
||||
* Assume ISO-8859-1 encoding, subclasses can override this.
|
||||
*/
|
||||
@Override
|
||||
default char charAt(int index) throws IndexOutOfBoundsException {
|
||||
try {
|
||||
return (char) readUnsignedByte(readPosition() + index);
|
||||
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new IndexOutOfBoundsException((readPosition() + index) + " >= " + readLimit());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*/
|
||||
|
||||
@Override
|
||||
default CharSequence subSequence(int start, int end) {
|
||||
throw new UnsupportedOperationException("todo");
|
||||
}
|
||||
|
||||
/**
|
||||
* By default the maximum length of data shown is 256 characters. Use toDebugString(long) if you want more.
|
||||
*
|
||||
* @return This BytesStore as a DebugString.
|
||||
*/
|
||||
|
||||
default String toDebugString() {
|
||||
return toDebugString(512);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxLength the maximum len of the output
|
||||
* @return This BytesStore as a DebugString.
|
||||
*/
|
||||
|
||||
default String toDebugString(long maxLength) {
|
||||
return BytesInternal.toDebugString(this, maxLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the underlying BytesStore
|
||||
*/
|
||||
|
||||
default BytesStore bytesStore() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a portion of a BytesStore matches this one.
|
||||
*
|
||||
* @param bytesStore to match against
|
||||
* @param length to match.
|
||||
* @return true if the bytes up to min(length, this.length(), bytesStore.length()) matched.
|
||||
*/
|
||||
default boolean equalBytes( BytesStore bytesStore, long length)
|
||||
throws BufferUnderflowException {
|
||||
return length == 8 && bytesStore.length() >= 8
|
||||
? readLong(readPosition()) == bytesStore.readLong(bytesStore.readPosition())
|
||||
: BytesInternal.equalBytesAny(this, bytesStore, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bytes sum of the readable bytes.
|
||||
*
|
||||
* @return unsigned byte sum.
|
||||
*/
|
||||
default int byteCheckSum() throws IORuntimeException {
|
||||
return byteCheckSum(readPosition(), readLimit());
|
||||
}
|
||||
|
||||
default int byteCheckSum(long start, long end) {
|
||||
int sum = 0;
|
||||
for (long i = start; i < end; i++) {
|
||||
sum += readByte(i);
|
||||
}
|
||||
return sum & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Does the BytesStore end with a character?
|
||||
*
|
||||
* @param c to look for
|
||||
* @return true if its the last character.
|
||||
*/
|
||||
default boolean endsWith(char c) {
|
||||
try {
|
||||
return readRemaining() > 0 && readUnsignedByte(readLimit() - 1) == c;
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the BytesStore start with a character?
|
||||
*
|
||||
* @param c to look for
|
||||
* @return true if its the last character.
|
||||
*/
|
||||
default boolean startsWith(char c) {
|
||||
try {
|
||||
return readRemaining() > 0 && readUnsignedByte(readPosition()) == c;
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the contents of the BytesStores.
|
||||
*
|
||||
* @param bytesStore to compare with
|
||||
* @return true if they contain the same data.
|
||||
*/
|
||||
default boolean contentEquals( BytesStore bytesStore) {
|
||||
return BytesInternal.contentEqual(this, bytesStore);
|
||||
}
|
||||
|
||||
default boolean startsWith( BytesStore bytesStore) {
|
||||
return BytesInternal.startsWith(this, bytesStore);
|
||||
}
|
||||
|
||||
|
||||
default String to8bitString() throws IllegalArgumentException {
|
||||
return BytesInternal.to8bitString(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform a <i>not</i> atomic add and get operation for an unsigned byte value. This method
|
||||
* <i>does not</i> check for unsigned byte overflow.
|
||||
*
|
||||
* @param offset to add and get
|
||||
* @param adding value to add, can be 1
|
||||
* @return the sum
|
||||
*/
|
||||
default int addAndGetUnsignedByteNotAtomic(long offset, int adding) throws BufferUnderflowException {
|
||||
try {
|
||||
int r = (readUnsignedByte(offset) + adding) & 0xFF;
|
||||
writeByte(offset, (byte) r);
|
||||
return r;
|
||||
} catch (BufferOverflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a <i>not</i> atomic add and get operation for a short value.
|
||||
*
|
||||
* @param offset to add and get
|
||||
* @param adding value to add, can be 1
|
||||
* @return the sum
|
||||
*/
|
||||
default short addAndGetShortNotAtomic(long offset, short adding) throws BufferUnderflowException {
|
||||
try {
|
||||
short r = (short) (readShort(offset) + adding);
|
||||
writeByte(offset, r);
|
||||
return r;
|
||||
} catch (BufferOverflowException | IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a <i>not</i> atomic add and get operation for an int value.
|
||||
*
|
||||
* @param offset to add and get
|
||||
* @param adding value to add, can be 1
|
||||
* @return the sum
|
||||
*/
|
||||
default int addAndGetIntNotAtomic(long offset, int adding) throws BufferUnderflowException {
|
||||
try {
|
||||
int r = readInt(offset) + adding;
|
||||
writeInt(offset, r);
|
||||
return r;
|
||||
} catch (BufferOverflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a <i>not</i> atomic add and get operation for a float value.
|
||||
*
|
||||
* @param offset to add and get
|
||||
* @param adding value to add, can be 1
|
||||
* @return the sum
|
||||
*/
|
||||
default double addAndGetDoubleNotAtomic(long offset, double adding) throws BufferUnderflowException {
|
||||
try {
|
||||
double r = readDouble(offset) + adding;
|
||||
writeDouble(offset, r);
|
||||
return r;
|
||||
} catch (BufferOverflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a <i>not</i> atomic add and get operation for a float value.
|
||||
*
|
||||
* @param offset to add and get
|
||||
* @param adding value to add, can be 1
|
||||
* @return the sum
|
||||
*/
|
||||
default float addAndGetFloatNotAtomic(long offset, float adding) throws BufferUnderflowException {
|
||||
try {
|
||||
float r = readFloat(offset) + adding;
|
||||
writeFloat(offset, r);
|
||||
return r;
|
||||
} catch (BufferOverflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
void move(long from, long to, long length) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Write a value which is not smaller.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param atLeast value it is at least.
|
||||
*/
|
||||
default void writeMaxLong(long offset, long atLeast) throws BufferUnderflowException {
|
||||
try {
|
||||
for (; ; ) {
|
||||
long v = readVolatileLong(offset);
|
||||
if (v >= atLeast)
|
||||
return;
|
||||
if (compareAndSwapLong(offset, v, atLeast))
|
||||
return;
|
||||
}
|
||||
} catch (BufferOverflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a value which is not smaller.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param atLeast value it is at least.
|
||||
*/
|
||||
default void writeMaxInt(long offset, int atLeast) throws BufferUnderflowException {
|
||||
try {
|
||||
for (; ; ) {
|
||||
int v = readVolatileInt(offset);
|
||||
if (v >= atLeast)
|
||||
return;
|
||||
if (compareAndSwapInt(offset, v, atLeast))
|
||||
return;
|
||||
}
|
||||
} catch (BufferOverflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
default boolean isEmpty() {
|
||||
return readRemaining() == 0;
|
||||
}
|
||||
|
||||
default void cipher( Cipher cipher, Bytes outBytes, ByteBuffer using1, ByteBuffer using2) throws IllegalStateException {
|
||||
long readPos = outBytes.readPosition();
|
||||
try {
|
||||
long writePos = outBytes.writePosition();
|
||||
BytesStore inBytes;
|
||||
long size = readRemaining();
|
||||
if (this.isDirectMemory()) {
|
||||
inBytes = this;
|
||||
} else {
|
||||
inBytes = NativeBytesStore.nativeStore(size);
|
||||
this.copyTo(inBytes);
|
||||
}
|
||||
BytesInternal.assignBytesStoreToByteBuffer(inBytes, using1);
|
||||
int outputSize = cipher.getOutputSize(Math.toIntExact(size));
|
||||
outBytes.ensureCapacity(writePos + outputSize);
|
||||
outBytes.readPositionRemaining(writePos, outputSize);
|
||||
BytesInternal.assignBytesStoreToByteBuffer(outBytes, using2);
|
||||
int len = cipher.update(using1, using2);
|
||||
len += cipher.doFinal(using1, using2);
|
||||
assert len == using2.position();
|
||||
outBytes.writePosition(writePos + using2.position());
|
||||
|
||||
} catch ( Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
} finally {
|
||||
try {
|
||||
outBytes.readPosition(readPos);
|
||||
} catch (BufferUnderflowException e) {
|
||||
//noinspection ThrowFromFinallyBlock
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default void cipher( Cipher cipher, Bytes outBytes) throws IllegalStateException {
|
||||
cipher(cipher, outBytes, BytesInternal.BYTE_BUFFER_TL.get(), BytesInternal.BYTE_BUFFER2_TL.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether this BytesStore is writable.
|
||||
*/
|
||||
default boolean readWrite() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Function;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class BytesTextMethodTester<T> {
|
||||
private final String input;
|
||||
private final Class<T> outputClass;
|
||||
private final String output;
|
||||
private final Function<T, Object> componentFunction;
|
||||
|
||||
private String setup;
|
||||
private Function<String, String> afterRun;
|
||||
|
||||
private String expected;
|
||||
private String actual;
|
||||
|
||||
public BytesTextMethodTester(String input, Function<T, Object> componentFunction, Class<T> outputClass, String output) {
|
||||
this.input = input;
|
||||
this.outputClass = outputClass;
|
||||
this.output = output;
|
||||
this.componentFunction = componentFunction;
|
||||
}
|
||||
|
||||
public String setup() {
|
||||
return setup;
|
||||
}
|
||||
|
||||
|
||||
public BytesTextMethodTester setup(String setup) {
|
||||
this.setup = setup;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Function<String, String> afterRun() {
|
||||
return afterRun;
|
||||
}
|
||||
|
||||
|
||||
public BytesTextMethodTester afterRun(Function<String, String> afterRun) {
|
||||
this.afterRun = afterRun;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public BytesTextMethodTester run() throws IOException {
|
||||
|
||||
Bytes<?> bytes2 = new HexDumpBytes();
|
||||
T writer = bytes2.bytesMethodWriter(outputClass);
|
||||
|
||||
Object component = componentFunction.apply(writer);
|
||||
Object[] components = component instanceof Object[]
|
||||
? (Object[]) component
|
||||
: new Object[]{component};
|
||||
|
||||
if (setup != null) {
|
||||
Bytes bytes0 = HexDumpBytes.fromText(BytesUtil.readFile(setup));
|
||||
|
||||
BytesMethodReader reader0 = bytes0.bytesMethodReaderBuilder()
|
||||
.defaultParselet(this::unknownMessageId)
|
||||
.build(components);
|
||||
while (reader0.readOne()) {
|
||||
bytes2.clear();
|
||||
}
|
||||
bytes2.clear();
|
||||
}
|
||||
|
||||
// expected
|
||||
expected = BytesUtil.readFile(output).toString().trim().replace("\r", "");
|
||||
|
||||
Bytes text = BytesUtil.readFile(input);
|
||||
for (String text2 : text.toString().split("###[^\n]*\n")) {
|
||||
if (text2.trim().length() <= 0)
|
||||
continue;
|
||||
Bytes bytes = HexDumpBytes.fromText(text2);
|
||||
|
||||
BytesMethodReader reader = bytes.bytesMethodReaderBuilder()
|
||||
.defaultParselet(this::unknownMessageId)
|
||||
.build(components);
|
||||
|
||||
while (reader.readOne()) {
|
||||
if (bytes.readRemaining() > 1)
|
||||
bytes2.comment("## End Of Message");
|
||||
}
|
||||
bytes.releaseLast();
|
||||
bytes2.comment("## End Of Block");
|
||||
}
|
||||
bytes2.comment("## End Of Test");
|
||||
|
||||
actual = bytes2.toHexString().trim();
|
||||
if (afterRun != null) {
|
||||
expected = afterRun.apply(expected);
|
||||
actual = afterRun.apply(actual);
|
||||
}
|
||||
bytes2.releaseLast();
|
||||
return this;
|
||||
}
|
||||
|
||||
private void unknownMessageId(long id, BytesIn b) {
|
||||
Jvm.warn().on(getClass(), "Unknown message id " + Long.toHexString(id));
|
||||
b.readPosition(b.readLimit());
|
||||
}
|
||||
|
||||
public String expected() {
|
||||
return expected;
|
||||
}
|
||||
|
||||
public String actual() {
|
||||
return actual;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.ClassLocal;
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import net.openhft.chronicle.core.UnsafeMemory;
|
||||
import net.openhft.chronicle.core.io.AbstractReferenceCounted;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import net.openhft.chronicle.core.io.IOTools;
|
||||
import net.openhft.chronicle.core.util.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static net.openhft.chronicle.core.io.IOTools.*;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public enum BytesUtil {
|
||||
;
|
||||
private static final int[] NO_INTS = {};
|
||||
private static final ClassLocal<int[]> TRIVIALLY_COPYABLE = ClassLocal.withInitial(BytesUtil::isTriviallyCopyable0);
|
||||
|
||||
/**
|
||||
* Is the whole class trivially copyable
|
||||
*
|
||||
* @param clazz to check
|
||||
* @return true if the whole class is trivially copyable
|
||||
*/
|
||||
public static boolean isTriviallyCopyable(Class clazz) {
|
||||
return TRIVIALLY_COPYABLE.get(clazz).length > 0;
|
||||
}
|
||||
|
||||
static int[] isTriviallyCopyable0(Class clazz) {
|
||||
if (clazz.isArray()) {
|
||||
Class componentType = clazz.getComponentType();
|
||||
if (componentType.isPrimitive())
|
||||
return new int[]{UnsafeMemory.UNSAFE.arrayBaseOffset(clazz)};
|
||||
return NO_INTS;
|
||||
}
|
||||
List<Field> fields = new ArrayList<>();
|
||||
while (clazz != null && clazz != Object.class) {
|
||||
Collections.addAll(fields, clazz.getDeclaredFields());
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
int min = Integer.MAX_VALUE;
|
||||
int max = Integer.MIN_VALUE;
|
||||
for (Field field : fields) {
|
||||
int modifiers = field.getModifiers();
|
||||
if (Modifier.isStatic(modifiers))
|
||||
continue;
|
||||
long offset2 = UnsafeMemory.UNSAFE.objectFieldOffset(field);
|
||||
int size = sizeOf(field.getType());
|
||||
min = (int) Math.min(min, offset2);
|
||||
max = (int) Math.max(max, offset2 + size);
|
||||
if (Modifier.isTransient(modifiers))
|
||||
return NO_INTS;
|
||||
if (!field.getType().isPrimitive())
|
||||
return NO_INTS;
|
||||
}
|
||||
return new int[]{min, max};
|
||||
}
|
||||
|
||||
/**
|
||||
* Are all the fields in the range given trivially copyable
|
||||
*
|
||||
* @param clazz to check
|
||||
* @return true if the fields in range are trivially copyable.
|
||||
*/
|
||||
public static boolean isTriviallyCopyable(Class clazz, int offset, int length) {
|
||||
int[] ints = TRIVIALLY_COPYABLE.get(clazz);
|
||||
if (ints.length == 0)
|
||||
return false;
|
||||
return offset >= ints[0] && (ints.length == 1 || offset + length <= ints[1]);
|
||||
}
|
||||
|
||||
public static int[] triviallyCopyableRange(Class clazz) {
|
||||
return TRIVIALLY_COPYABLE.get(clazz);
|
||||
}
|
||||
|
||||
private static int sizeOf(Class<?> type) {
|
||||
return type == boolean.class || type == byte.class ? 1
|
||||
: type == short.class || type == char.class ? 2
|
||||
: type == int.class || type == float.class ? 4
|
||||
: type == long.class || type == double.class ? 8
|
||||
: Unsafe.ARRAY_OBJECT_INDEX_SCALE;
|
||||
}
|
||||
|
||||
public static String findFile( String name) throws FileNotFoundException {
|
||||
File file = new File(name);
|
||||
URL url = null;
|
||||
if (!file.exists()) {
|
||||
url = urlFor(name);
|
||||
String file2 = url.getFile()
|
||||
.replace("target/test-classes", "src/test/resources");
|
||||
file = new File(file2);
|
||||
}
|
||||
if (!file.exists())
|
||||
throw new FileNotFoundException(name);
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
public static Bytes readFile( String name) throws IOException {
|
||||
if (name.startsWith("=")) {
|
||||
return Bytes.from(name.substring(1));
|
||||
}
|
||||
File file = new File(name);
|
||||
URL url = null;
|
||||
if (!file.exists()) {
|
||||
url = urlFor(name);
|
||||
file = new File(url.getFile());
|
||||
}
|
||||
return // name.endsWith(".gz") || !file.exists() || OS.isWindows() ?
|
||||
Bytes.wrapForRead(readAsBytes(url == null ? new FileInputStream(file) : open(url)));
|
||||
//: MappedFile.readOnly(file).acquireBytesForRead(0);
|
||||
|
||||
}
|
||||
|
||||
public static void writeFile(String file, Bytes<byte[]> bytes) throws IOException {
|
||||
try (OutputStream os = new FileOutputStream(file)) {
|
||||
os.write(bytes.underlyingObject());
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean bytesEqual(
|
||||
RandomDataInput a, long offset,
|
||||
RandomDataInput second, long secondOffset, long len)
|
||||
throws BufferUnderflowException {
|
||||
long i = 0;
|
||||
while (len - i >= 8L) {
|
||||
if (a.readLong(offset + i) != second.readLong(secondOffset + i))
|
||||
return false;
|
||||
i += 8L;
|
||||
}
|
||||
if (len - i >= 4L) {
|
||||
if (a.readInt(offset + i) != second.readInt(secondOffset + i))
|
||||
return false;
|
||||
i += 4L;
|
||||
}
|
||||
if (len - i >= 2L) {
|
||||
if (a.readShort(offset + i) != second.readShort(secondOffset + i))
|
||||
return false;
|
||||
i += 2L;
|
||||
}
|
||||
if (i < len)
|
||||
return a.readByte(offset + i) == second.readByte(secondOffset + i);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean bytesEqual( CharSequence cs, RandomDataInput bs, long offset, int length) {
|
||||
if (cs == null || cs.length() != length)
|
||||
return false;
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (cs.charAt(i) != bs.readUnsignedByte(offset + i))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean equals(Object o1, Object o2) {
|
||||
if (o1 == o2) return true;
|
||||
if (o1 instanceof CharSequence && o2 instanceof CharSequence)
|
||||
return StringUtils.isEqual((CharSequence) o1, (CharSequence) o2);
|
||||
return o1 != null && o1.equals(o2);
|
||||
}
|
||||
|
||||
public static int asInt( String str) {
|
||||
ByteBuffer bb = ByteBuffer.wrap(str.getBytes(StandardCharsets.ISO_8859_1)).order(ByteOrder.nativeOrder());
|
||||
return bb.getInt();
|
||||
}
|
||||
|
||||
public static int stopBitLength(long n) {
|
||||
if ((n & ~0x7F) == 0) {
|
||||
return 1;
|
||||
}
|
||||
if ((n & ~0x3FFF) == 0) {
|
||||
return 2;
|
||||
}
|
||||
return BytesInternal.stopBitLength0(n);
|
||||
}
|
||||
|
||||
|
||||
public static char[] toCharArray( Bytes bytes) {
|
||||
final char[] chars = new char[Maths.toUInt31(bytes.readRemaining())];
|
||||
|
||||
for (int i = 0; i < bytes.readRemaining(); i++) {
|
||||
chars[i] = (char) bytes.readUnsignedByte(i + bytes.readPosition());
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
|
||||
|
||||
public static char[] toCharArray( Bytes bytes, long position, int length) {
|
||||
final char[] chars = new char[length];
|
||||
|
||||
int j = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
chars[j++] = (char) bytes.readUnsignedByte(position + i);
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
|
||||
public static long readStopBit( StreamingDataInput in) throws IORuntimeException {
|
||||
return BytesInternal.readStopBit(in);
|
||||
}
|
||||
|
||||
public static void writeStopBit( StreamingDataOutput out, long n) {
|
||||
BytesInternal.writeStopBit(out, n);
|
||||
}
|
||||
|
||||
public static void parseUtf8(
|
||||
StreamingDataInput in, Appendable appendable, int utflen)
|
||||
throws UTFDataFormatRuntimeException {
|
||||
BytesInternal.parseUtf8(in, appendable, true, utflen);
|
||||
}
|
||||
|
||||
public static void appendUtf8( StreamingDataOutput out, CharSequence cs) {
|
||||
BytesInternal.appendUtf8(out, cs, 0, cs.length());
|
||||
}
|
||||
|
||||
// used by Chronicle FIX.
|
||||
public static void appendBytesFromStart( Bytes bytes, long startPosition, StringBuilder sb) {
|
||||
try {
|
||||
BytesInternal.parse8bit(startPosition, bytes, sb, (int) (bytes.readPosition() - startPosition));
|
||||
sb.append('\u2016');
|
||||
sb.append(bytes);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void readMarshallable( ReadBytesMarshallable marshallable, BytesIn bytes) {
|
||||
BytesMarshaller.BYTES_MARSHALLER_CL.get(marshallable.getClass())
|
||||
.readMarshallable(marshallable, bytes);
|
||||
}
|
||||
|
||||
public static void writeMarshallable( WriteBytesMarshallable marshallable, BytesOut bytes) {
|
||||
BytesMarshaller.BYTES_MARSHALLER_CL.get(marshallable.getClass())
|
||||
.writeMarshallable(marshallable, bytes);
|
||||
}
|
||||
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
public static long utf8Length( CharSequence toWrite) {
|
||||
return AppendableUtil.findUtf8Length(toWrite);
|
||||
}
|
||||
|
||||
static String asString(String s, Throwable t) {
|
||||
StringWriter sw = new StringWriter();
|
||||
sw.append(s).append("\n");
|
||||
t.printStackTrace(new PrintWriter(sw));
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
// calls the BackgroundResourceReleaser and AbstractCloseable.assertCloseableClose first.
|
||||
public static void checkRegisteredBytes() {
|
||||
AbstractReferenceCounted.assertReferencesReleased();
|
||||
}
|
||||
|
||||
public static boolean byteToBoolean(byte b) {
|
||||
return b != 0 && b != 'N' && b != 'n';
|
||||
}
|
||||
|
||||
public static long roundUpTo64ByteAlign(long x) {
|
||||
return (x + 63L) & ~63L;
|
||||
}
|
||||
|
||||
public static long roundUpTo8ByteAlign(long x) {
|
||||
return (x + 7L) & ~7L;
|
||||
}
|
||||
|
||||
public static void read8ByteAlignPadding(Bytes<?> bytes) {
|
||||
bytes.readPosition(roundUpTo8ByteAlign(bytes.readPosition()));
|
||||
}
|
||||
|
||||
public static void write8ByteAlignPadding(Bytes<?> bytes) {
|
||||
long start = bytes.writePosition();
|
||||
long end = roundUpTo8ByteAlign(start);
|
||||
bytes.writePosition(end);
|
||||
bytes.zeroOut(start, end);
|
||||
}
|
||||
|
||||
public static String toDebugString( RandomDataInput bytes, long start, long maxLength) {
|
||||
BytesStore bytes2 = bytes.subBytes(start, maxLength);
|
||||
return bytes2.toDebugString(maxLength);
|
||||
}
|
||||
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
public static boolean unregister(BytesStore bs) {
|
||||
IOTools.unmonitor(bs);
|
||||
return true;
|
||||
}
|
||||
|
||||
static class WarnUncheckedElasticBytes {
|
||||
static {
|
||||
Jvm.debug().on(WarnUncheckedElasticBytes.class, "Wrapping elastic bytes with unchecked() will require calling ensureCapacity() as needed!");
|
||||
}
|
||||
|
||||
static void warn() {
|
||||
// static block does the work.
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.annotation.DontChain;
|
||||
|
||||
@DontChain
|
||||
public interface CommonMarshallable {
|
||||
/**
|
||||
* @return whether this message should be written as self describing
|
||||
*/
|
||||
default boolean usesSelfDescribingMessage() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
|
||||
/**
|
||||
* thrown when the TcpChannelHub drops its connection to the server
|
||||
*/
|
||||
// TODO Move to network where it is used.
|
||||
public class ConnectionDroppedException extends IORuntimeException {
|
||||
public ConnectionDroppedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ConnectionDroppedException(Throwable e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
public ConnectionDroppedException(String s, Throwable e) {
|
||||
super(s, e);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
/**
|
||||
* Marker interface for implementors of {@link Byteable} that indicates
|
||||
* that size requirements can only be calculated on a user-supplied instance.
|
||||
*/
|
||||
public interface DynamicallySized {
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
|
||||
import static net.openhft.chronicle.bytes.BinaryWireCode.*;
|
||||
|
||||
public class GuardedNativeBytes<Underlying> extends NativeBytes<Underlying> {
|
||||
static final byte BYTE_T = (byte) INT8;
|
||||
static final byte SHORT_T = (byte) INT16;
|
||||
static final byte INT_T = (byte) INT32;
|
||||
static final byte LONG_T = (byte) INT64;
|
||||
static final byte STOP_T = (byte) STOP_BIT;
|
||||
static final byte FLOAT_T = (byte) FLOAT32;
|
||||
static final byte DOUBLE_T = (byte) FLOAT64;
|
||||
|
||||
private static final String[] STRING_FOR_CODE = _stringForCode(GuardedNativeBytes.class);
|
||||
|
||||
public GuardedNativeBytes( BytesStore store, long capacity) throws IllegalStateException {
|
||||
super(store, capacity);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeByte(byte i8) throws BufferOverflowException {
|
||||
super.writeByte(BYTE_T);
|
||||
return super.writeByte(i8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> rawWriteByte(byte i8) throws BufferOverflowException {
|
||||
return super.writeByte(i8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> rawWriteInt(int i) throws BufferOverflowException {
|
||||
return super.writeInt(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readByte() {
|
||||
expectByte(BYTE_T);
|
||||
return super.readByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte rawReadByte() {
|
||||
return super.readByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int rawReadInt() {
|
||||
return super.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedByte() {
|
||||
expectByte(BYTE_T);
|
||||
return super.readUnsignedByte();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeShort(short i16) throws BufferOverflowException {
|
||||
super.writeByte(SHORT_T);
|
||||
return super.writeShort(i16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readShort() throws BufferUnderflowException {
|
||||
expectByte(SHORT_T);
|
||||
return super.readShort();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeStopBit(char x) throws BufferOverflowException {
|
||||
super.writeByte(STOP_T);
|
||||
return super.writeStopBit(x);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeStopBit(long x) throws BufferOverflowException {
|
||||
super.writeByte(STOP_T);
|
||||
return super.writeStopBit(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readStopBit() throws IORuntimeException {
|
||||
expectByte(STOP_T);
|
||||
return super.readStopBit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char readStopBitChar() throws IORuntimeException {
|
||||
expectByte(STOP_T);
|
||||
return super.readStopBitChar();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeInt(int i) throws BufferOverflowException {
|
||||
super.writeByte(INT_T);
|
||||
return super.writeInt(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readInt() throws BufferUnderflowException {
|
||||
expectByte(INT_T);
|
||||
return super.readInt();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes writeLong(long i64) throws BufferOverflowException {
|
||||
super.writeByte(LONG_T);
|
||||
return super.writeLong(i64);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLong() throws BufferUnderflowException {
|
||||
expectByte(LONG_T);
|
||||
return super.readLong();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeFloat(float f) throws BufferOverflowException {
|
||||
super.writeByte(FLOAT_T);
|
||||
return super.writeFloat(f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float readFloat() throws BufferUnderflowException {
|
||||
expectByte(FLOAT_T);
|
||||
return super.readFloat();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeDouble(double d) throws BufferOverflowException {
|
||||
super.writeByte(DOUBLE_T);
|
||||
return super.writeDouble(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readDouble() throws BufferUnderflowException {
|
||||
expectByte(DOUBLE_T);
|
||||
return super.readDouble();
|
||||
}
|
||||
|
||||
private void expectByte(byte expected) {
|
||||
byte type = super.readByte();
|
||||
if (type != expected)
|
||||
throw new IllegalStateException("Expected " + STRING_FOR_CODE[expected & 0xFF]
|
||||
+ " but was " + STRING_FOR_CODE[type & 0xFF]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,402 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.bytes.util.DecoratedBufferOverflowException;
|
||||
import net.openhft.chronicle.bytes.util.DecoratedBufferUnderflowException;
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import net.openhft.chronicle.core.Memory;
|
||||
import net.openhft.chronicle.core.OS;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Wrapper for Heap ByteBuffers and arrays.
|
||||
*/
|
||||
@SuppressWarnings("restriction")
|
||||
public class HeapBytesStore<Underlying>
|
||||
extends AbstractBytesStore<HeapBytesStore<Underlying>, Underlying> {
|
||||
|
||||
private static final Memory MEMORY = OS.memory();
|
||||
|
||||
private final Object realUnderlyingObject;
|
||||
private final int dataOffset;
|
||||
private final long capacity;
|
||||
|
||||
private final Underlying underlyingObject;
|
||||
|
||||
private HeapBytesStore( ByteBuffer byteBuffer) {
|
||||
super(false);
|
||||
//noinspection unchecked
|
||||
this.underlyingObject = (Underlying) byteBuffer;
|
||||
this.realUnderlyingObject = byteBuffer.array();
|
||||
this.dataOffset = Jvm.arrayByteBaseOffset() + byteBuffer.arrayOffset();
|
||||
this.capacity = byteBuffer.capacity();
|
||||
}
|
||||
|
||||
private HeapBytesStore( byte [] byteArray) {
|
||||
super(false);
|
||||
//noinspection unchecked
|
||||
this.underlyingObject = (Underlying) byteArray;
|
||||
this.realUnderlyingObject = byteArray;
|
||||
this.dataOffset = Jvm.arrayByteBaseOffset();
|
||||
this.capacity = byteArray.length;
|
||||
}
|
||||
|
||||
// Used by Chronicle-Map.
|
||||
|
||||
public static HeapBytesStore<byte[]> wrap( byte[] byteArray) {
|
||||
return new HeapBytesStore<>(byteArray);
|
||||
}
|
||||
|
||||
// Used by Chronicle-Map.
|
||||
|
||||
public static HeapBytesStore<ByteBuffer> wrap( ByteBuffer bb) {
|
||||
return new HeapBytesStore<>(bb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectMemory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(long from, long to, long length) {
|
||||
if (from < 0 || to < 0) throw new BufferUnderflowException();
|
||||
//noinspection SuspiciousSystemArraycopy
|
||||
System.arraycopy(realUnderlyingObject, Maths.toUInt31(from), realUnderlyingObject, Maths.toUInt31(to), Maths.toUInt31(length));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return BytesInternal.toString(this);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
return e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BytesStore<HeapBytesStore<Underlying>, Underlying> copy() {
|
||||
throw new UnsupportedOperationException("todo");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performRelease() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public long capacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Underlying underlyingObject() {
|
||||
return underlyingObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compareAndSwapInt(long offset, int expected, int value) {
|
||||
return MEMORY.compareAndSwapInt(realUnderlyingObject, dataOffset + offset, expected, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testAndSetInt(long offset, int expected, int value) {
|
||||
MEMORY.testAndSetInt(realUnderlyingObject, dataOffset + offset, expected, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compareAndSwapLong(long offset, long expected, long value) {
|
||||
return MEMORY.compareAndSwapLong(
|
||||
realUnderlyingObject, dataOffset + offset, expected, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readByte(long offset) throws BufferUnderflowException {
|
||||
checkOffset(offset, 1);
|
||||
return MEMORY.readByte(realUnderlyingObject, dataOffset + offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readShort(long offset) throws BufferUnderflowException {
|
||||
checkOffset(offset, 2);
|
||||
return MEMORY.readShort(realUnderlyingObject, dataOffset + offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readInt(long offset) throws BufferUnderflowException {
|
||||
checkOffset(offset, 4);
|
||||
return MEMORY.readInt(realUnderlyingObject, dataOffset + offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLong(long offset) throws BufferUnderflowException {
|
||||
checkOffset(offset, 8);
|
||||
return MEMORY.readLong(realUnderlyingObject, dataOffset + offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float readFloat(long offset) throws BufferUnderflowException {
|
||||
checkOffset(offset, 4);
|
||||
return MEMORY.readFloat(realUnderlyingObject, dataOffset + offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readDouble(long offset) throws BufferUnderflowException {
|
||||
checkOffset(offset, 8);
|
||||
return MEMORY.readDouble(realUnderlyingObject, dataOffset + offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readVolatileByte(long offset) throws BufferUnderflowException {
|
||||
checkOffset(offset, 1);
|
||||
return MEMORY.readVolatileByte(realUnderlyingObject, dataOffset + offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readVolatileShort(long offset) throws BufferUnderflowException {
|
||||
checkOffset(offset, 2);
|
||||
return MEMORY.readVolatileShort(realUnderlyingObject, dataOffset + offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readVolatileInt(long offset) throws BufferUnderflowException {
|
||||
checkOffset(offset, 4);
|
||||
return MEMORY.readVolatileInt(realUnderlyingObject, dataOffset + offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readVolatileLong(long offset) throws BufferUnderflowException {
|
||||
checkOffset(offset, 8);
|
||||
return MEMORY.readVolatileLong(realUnderlyingObject, dataOffset + offset);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> writeByte(long offset, byte b)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 1);
|
||||
MEMORY.writeByte(realUnderlyingObject, dataOffset + offset, b);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> writeShort(long offset, short i16)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 2);
|
||||
MEMORY.writeShort(realUnderlyingObject, dataOffset + offset, i16);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> writeInt(long offset, int i32)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 4);
|
||||
MEMORY.writeInt(realUnderlyingObject, dataOffset + offset, i32);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> writeOrderedInt(long offset, int i32)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 4);
|
||||
MEMORY.writeOrderedInt(realUnderlyingObject, dataOffset + offset, i32);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> writeLong(long offset, long i64)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 8);
|
||||
MEMORY.writeLong(realUnderlyingObject, dataOffset + offset, i64);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> writeOrderedLong(long offset, long i)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 8);
|
||||
MEMORY.writeOrderedLong(realUnderlyingObject, dataOffset + offset, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> writeFloat(long offset, float f)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 4);
|
||||
MEMORY.writeFloat(realUnderlyingObject, dataOffset + offset, f);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> writeDouble(long offset, double d)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 8);
|
||||
MEMORY.writeDouble(realUnderlyingObject, dataOffset + offset, d);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> writeVolatileByte(long offset, byte i8)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 1);
|
||||
MEMORY.writeVolatileByte(realUnderlyingObject, dataOffset + offset, i8);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> writeVolatileShort(long offset, short i16)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 2);
|
||||
MEMORY.writeVolatileShort(realUnderlyingObject, dataOffset + offset, i16);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> writeVolatileInt(long offset, int i32)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 4);
|
||||
MEMORY.writeVolatileInt(realUnderlyingObject, dataOffset + offset, i32);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> writeVolatileLong(long offset, long i64)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 8);
|
||||
MEMORY.writeVolatileLong(realUnderlyingObject, dataOffset + offset, i64);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> write(
|
||||
long offsetInRDO, byte[] bytes, int offset, int length) throws BufferOverflowException {
|
||||
writeCheckOffset(offsetInRDO, length);
|
||||
MEMORY.copyMemory(
|
||||
bytes, offset, realUnderlyingObject, this.dataOffset + offsetInRDO, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(
|
||||
long offsetInRDO, ByteBuffer bytes, int offset, int length) throws BufferOverflowException {
|
||||
writeCheckOffset(offsetInRDO, length);
|
||||
assert realUnderlyingObject == null || dataOffset >= (Jvm.is64bit() ? 12 : 8);
|
||||
if (bytes.isDirect()) {
|
||||
MEMORY.copyMemory(Jvm.address(bytes), realUnderlyingObject,
|
||||
this.dataOffset + offsetInRDO, length);
|
||||
|
||||
} else {
|
||||
MEMORY.copyMemory(bytes.array(), offset, realUnderlyingObject,
|
||||
this.dataOffset + offsetInRDO, length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HeapBytesStore<Underlying> write(long writeOffset,
|
||||
RandomDataInput bytes, long readOffset, long length) {
|
||||
long i;
|
||||
for (i = 0; i < length - 7; i += 8) {
|
||||
long x = bytes.readLong(readOffset + i);
|
||||
writeLong(writeOffset + i, x);
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
byte x = bytes.readByte(readOffset + i);
|
||||
writeByte(writeOffset + i, x);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForRead(long offset) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForWrite(long offset) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForWritePosition() throws UnsupportedOperationException, BufferOverflowException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nativeRead(long position, long address, long size) {
|
||||
throw new UnsupportedOperationException("todo");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nativeWrite(long address, long position, long size) {
|
||||
throw new UnsupportedOperationException("todo");
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof BytesStore && BytesInternal.contentEqual(this, (BytesStore) obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sharedMemory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void checkOffset(long offset, int size) throws BufferUnderflowException {
|
||||
checkBounds(offset, size, DecoratedBufferUnderflowException::new);
|
||||
}
|
||||
|
||||
private void writeCheckOffset(long offset, int size) throws BufferOverflowException {
|
||||
checkBounds(offset, size, DecoratedBufferOverflowException::new);
|
||||
}
|
||||
|
||||
private void checkBounds(final long offset, final int size,
|
||||
final Function<String, RuntimeException> exceptionFunction) {
|
||||
if (offset < start() || offset + size > capacity) {
|
||||
throw exceptionFunction.apply(
|
||||
String.format("Offset: %d, start: %d, size: %d, capacity: %d",
|
||||
offset, start(), size, capacity));
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,9 @@
|
|||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Invocation {
|
||||
Object invoke(Method m, Object o, Object[] args) throws InvocationTargetException;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.OS;
|
||||
import net.openhft.chronicle.core.io.ReferenceOwner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* BytesStore to wrap memory mapped data.
|
||||
*/
|
||||
public class MappedBytesStore extends NativeBytesStore<Void> {
|
||||
private final MappedFile mappedFile;
|
||||
private final long start;
|
||||
private final long safeLimit;
|
||||
|
||||
protected MappedBytesStore(ReferenceOwner owner, MappedFile mappedFile, long start, long address, long capacity, long safeCapacity) throws IllegalStateException {
|
||||
super(address, start + capacity, new OS.Unmapper(address, capacity), false);
|
||||
this.mappedFile = mappedFile;
|
||||
this.start = start;
|
||||
this.safeLimit = start + safeCapacity;
|
||||
reserveTransfer(INIT, owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the capacity of the underlying file
|
||||
* This can differ from the exposed capacity() of this bytes store (which has been page aligned)
|
||||
*
|
||||
* @return - capacity of the underlying file
|
||||
*/
|
||||
public long underlyingCapacity() {
|
||||
return mappedFile.capacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bytes<Void> bytesForRead() throws IllegalStateException {
|
||||
try {
|
||||
return new VanillaBytes<Void>(this)
|
||||
.readLimit(writeLimit())
|
||||
.readPosition(start());
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public VanillaBytes<Void> bytesForWrite() throws IllegalStateException {
|
||||
return new VanillaBytes<>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inside(long offset) {
|
||||
return start <= offset && offset < safeLimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inside(long offset, long buffer) {
|
||||
// this is correct that it uses the maximumLimit, yes it is different than the method above.
|
||||
return start <= offset && offset + buffer < limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long safeLimit() {
|
||||
return safeLimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readByte(long offset) {
|
||||
return memory.readByte(address - start + offset);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> writeOrderedInt(long offset, int i) {
|
||||
memory.writeOrderedInt(address - start + offset, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long translate(long offset) {
|
||||
assert offset >= start;
|
||||
assert offset < limit;
|
||||
|
||||
return offset - start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long start() {
|
||||
return start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readPosition() {
|
||||
return start();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.ReferenceOwner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface MappedBytesStoreFactory {
|
||||
|
||||
MappedBytesStore create(ReferenceOwner owner, MappedFile mappedFile, long start, long address, long capacity, long safeCapacity);
|
||||
}
|
|
@ -0,0 +1,541 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.CleaningRandomAccessFile;
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.OS;
|
||||
import net.openhft.chronicle.core.io.AbstractCloseableReferenceCounted;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import net.openhft.chronicle.core.io.ReferenceOwner;
|
||||
import net.openhft.chronicle.core.onoes.Slf4jExceptionHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.channels.ClosedByInterruptException;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.FileChannel.MapMode;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.openhft.chronicle.core.io.Closeable.closeQuietly;
|
||||
|
||||
/**
|
||||
* A memory mapped files which can be randomly accessed in chunks. It has overlapping regions to
|
||||
* avoid wasting bytes at the end of chunks.
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked", "restriction"})
|
||||
public class MappedFile extends AbstractCloseableReferenceCounted {
|
||||
static final boolean RETAIN = Jvm.getBoolean("mappedFile.retain");
|
||||
private static final long DEFAULT_CAPACITY = 128L << 40;
|
||||
|
||||
|
||||
private final RandomAccessFile raf;
|
||||
private final FileChannel fileChannel;
|
||||
private final long chunkSize;
|
||||
private final long overlapSize;
|
||||
private final List<MappedBytesStore> stores = new ArrayList<>();
|
||||
private final long capacity;
|
||||
|
||||
private final File file;
|
||||
private final String canonicalPath;
|
||||
private final boolean readOnly;
|
||||
private NewChunkListener newChunkListener = MappedFile::logNewChunk;
|
||||
|
||||
protected MappedFile( final File file,
|
||||
final RandomAccessFile raf,
|
||||
final long chunkSize,
|
||||
final long overlapSize,
|
||||
final long capacity,
|
||||
final boolean readOnly) {
|
||||
this.file = file;
|
||||
try {
|
||||
this.canonicalPath = file.getCanonicalPath().intern();
|
||||
} catch (IOException ioe) {
|
||||
throw new IllegalStateException("Unable to obtain the canonical path for " + file.getAbsolutePath(), ioe);
|
||||
}
|
||||
this.raf = raf;
|
||||
this.fileChannel = raf.getChannel();
|
||||
this.chunkSize = OS.mapAlign(chunkSize);
|
||||
this.overlapSize = overlapSize > 0 && overlapSize < 64 << 10 ? chunkSize : OS.mapAlign(overlapSize);
|
||||
this.capacity = capacity;
|
||||
this.readOnly = readOnly;
|
||||
|
||||
Jvm.doNotCloseOnInterrupt(getClass(), this.fileChannel);
|
||||
}
|
||||
|
||||
private static void logNewChunk(final String filename,
|
||||
final int chunk,
|
||||
final long delayMicros) {
|
||||
if (delayMicros < 100 || !Jvm.isDebugEnabled(MappedFile.class))
|
||||
return;
|
||||
|
||||
// avoid a GC while trying to memory map.
|
||||
final String message = BytesInternal.acquireStringBuilder()
|
||||
.append("Allocation of ").append(chunk)
|
||||
.append(" chunk in ").append(filename)
|
||||
.append(" took ").append(delayMicros / 1e3).append(" ms.")
|
||||
.toString();
|
||||
Jvm.perf().on(MappedFile.class, message);
|
||||
}
|
||||
|
||||
|
||||
public static MappedFile of( final File file,
|
||||
final long chunkSize,
|
||||
final long overlapSize,
|
||||
final boolean readOnly) throws FileNotFoundException {
|
||||
// if (readOnly && OS.isWindows()) {
|
||||
// Jvm.warn().on(MappedFile.class, "Read only mode not supported on Windows, defaulting to read/write");
|
||||
// readOnly = false;
|
||||
// }
|
||||
|
||||
RandomAccessFile raf = new CleaningRandomAccessFile(file, readOnly ? "r" : "rw");
|
||||
// try {
|
||||
final long capacity = /*readOnly ? raf.length() : */DEFAULT_CAPACITY;
|
||||
return new MappedFile(file, raf, chunkSize, overlapSize, capacity, readOnly);
|
||||
/*
|
||||
} catch (IOException e) {
|
||||
Closeable.closeQuietly(raf);
|
||||
FileNotFoundException fnfe = new FileNotFoundException("Unable to open " + file);
|
||||
fnfe.initCause(e);
|
||||
throw fnfe;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public static MappedFile mappedFile( final File file, final long chunkSize) throws FileNotFoundException {
|
||||
return mappedFile(file, chunkSize, OS.pageSize());
|
||||
}
|
||||
|
||||
/*
|
||||
private void check(Throwable throwable, int[] count) {
|
||||
for (int i = 0; i < stores.size(); i++) {
|
||||
WeakReference<MappedBytesStore> storeRef = stores.get(i);
|
||||
if (storeRef == null)
|
||||
continue;
|
||||
MappedBytesStore mbs = storeRef.get();
|
||||
if (mbs != null && mbs.refCount() > 0) {
|
||||
mbs.releaseLast();
|
||||
throwable.printStackTrace();
|
||||
count[0]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
public static MappedFile mappedFile( final String filename, final long chunkSize) throws FileNotFoundException {
|
||||
return mappedFile(filename, chunkSize, OS.pageSize());
|
||||
}
|
||||
|
||||
|
||||
public static MappedFile mappedFile( final String filename,
|
||||
final long chunkSize,
|
||||
final long overlapSize) throws FileNotFoundException {
|
||||
return mappedFile(new File(filename), chunkSize, overlapSize);
|
||||
}
|
||||
|
||||
|
||||
public static MappedFile mappedFile( final File file,
|
||||
final long chunkSize,
|
||||
final long overlapSize) throws FileNotFoundException {
|
||||
return mappedFile(file, chunkSize, overlapSize, false);
|
||||
}
|
||||
|
||||
|
||||
public static MappedFile mappedFile( final File file,
|
||||
final long chunkSize,
|
||||
final long overlapSize,
|
||||
final boolean readOnly) throws FileNotFoundException {
|
||||
return MappedFile.of(file, chunkSize, overlapSize, readOnly);
|
||||
}
|
||||
|
||||
|
||||
public static MappedFile readOnly( final File file) throws FileNotFoundException {
|
||||
long chunkSize = file.length();
|
||||
long overlapSize = 0;
|
||||
// Chunks of 4 GB+ not supported on Windows.
|
||||
if (OS.isWindows() && chunkSize > 2L << 30) {
|
||||
chunkSize = 2L << 30;
|
||||
overlapSize = OS.pageSize();
|
||||
}
|
||||
return MappedFile.of(file, chunkSize, overlapSize, true);
|
||||
}
|
||||
|
||||
|
||||
public static MappedFile mappedFile( final File file,
|
||||
final long capacity,
|
||||
final long chunkSize,
|
||||
final long overlapSize,
|
||||
final boolean readOnly) throws IOException {
|
||||
final RandomAccessFile raf = new CleaningRandomAccessFile(file, readOnly ? "r" : "rw");
|
||||
// Windows throws an exception when setting the length when you re-open
|
||||
if (raf.length() < capacity)
|
||||
raf.setLength(capacity);
|
||||
return new MappedFile(file, raf, chunkSize, overlapSize, capacity, readOnly);
|
||||
}
|
||||
|
||||
public static void warmup() {
|
||||
final List<IOException> errorsDuringWarmup = new ArrayList<>();
|
||||
try {
|
||||
Jvm.setExceptionHandlers(Slf4jExceptionHandler.FATAL, null, null);
|
||||
|
||||
final File file = File.createTempFile("delete_warming_up", "me");
|
||||
file.deleteOnExit();
|
||||
final long mapAlignment = OS.mapAlignment();
|
||||
final int chunks = 64;
|
||||
final int compileThreshold = Jvm.compileThreshold();
|
||||
for (int j = 0; j <= compileThreshold; j += chunks) {
|
||||
try {
|
||||
try ( RandomAccessFile raf = new CleaningRandomAccessFile(file, "rw")) {
|
||||
try (final MappedFile mappedFile = new MappedFile(file, raf, mapAlignment, 0, mapAlignment * chunks, false)) {
|
||||
warmup0(mapAlignment, chunks, mappedFile);
|
||||
}
|
||||
}
|
||||
Thread.yield();
|
||||
} catch (IOException e) {
|
||||
errorsDuringWarmup.add(e);
|
||||
}
|
||||
}
|
||||
Thread.yield();
|
||||
Files.delete(file.toPath());
|
||||
} catch (IOException e) {
|
||||
Jvm.resetExceptionHandlers();
|
||||
Jvm.warn().on(MappedFile.class, "Error during warmup", e);
|
||||
} finally {
|
||||
Jvm.resetExceptionHandlers();
|
||||
if (errorsDuringWarmup.size() > 0)
|
||||
Jvm.warn().on(MappedFile.class, errorsDuringWarmup.size() + " errors during warmup: " + errorsDuringWarmup);
|
||||
}
|
||||
}
|
||||
|
||||
private static void warmup0(final long mapAlignment,
|
||||
final int chunks,
|
||||
final MappedFile mappedFile) throws IOException {
|
||||
ReferenceOwner warmup = ReferenceOwner.temporary("warmup");
|
||||
for (int i = 0; i < chunks; i++) {
|
||||
mappedFile.acquireBytesForRead(warmup, i * mapAlignment)
|
||||
.release(warmup);
|
||||
mappedFile.acquireBytesForWrite(warmup, i * mapAlignment)
|
||||
.release(warmup);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public File file() {
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalStateException if closed.
|
||||
*/
|
||||
|
||||
public MappedBytesStore acquireByteStore(
|
||||
ReferenceOwner owner,
|
||||
final long position)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException {
|
||||
return acquireByteStore(owner, position, null, readOnly ? ReadOnlyMappedBytesStore::new : MappedBytesStore::new);
|
||||
}
|
||||
|
||||
|
||||
public MappedBytesStore acquireByteStore(
|
||||
ReferenceOwner owner,
|
||||
final long position,
|
||||
BytesStore oldByteStore)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException {
|
||||
return acquireByteStore(owner, position, oldByteStore, readOnly ? ReadOnlyMappedBytesStore::new : MappedBytesStore::new);
|
||||
}
|
||||
|
||||
|
||||
public MappedBytesStore acquireByteStore(
|
||||
ReferenceOwner owner,
|
||||
final long position,
|
||||
BytesStore oldByteStore,
|
||||
final MappedBytesStoreFactory mappedBytesStoreFactory)
|
||||
throws IOException,
|
||||
IllegalArgumentException,
|
||||
IllegalStateException {
|
||||
|
||||
throwExceptionIfClosed();
|
||||
|
||||
if (position < 0)
|
||||
throw new IOException("Attempt to access a negative position: " + position);
|
||||
final int chunk = (int) (position / chunkSize);
|
||||
Jvm.safepoint();
|
||||
|
||||
final MappedBytesStore mbs;
|
||||
synchronized (stores) {
|
||||
while (stores.size() <= chunk)
|
||||
stores.add(null);
|
||||
mbs = stores.get(chunk);
|
||||
}
|
||||
if (mbs != null) {
|
||||
// don't reserve it again if we are already holding it.
|
||||
if (mbs == oldByteStore) {
|
||||
return mbs;
|
||||
}
|
||||
if (mbs.tryReserve(owner)) {
|
||||
return mbs;
|
||||
}
|
||||
}
|
||||
|
||||
// its important we perform this outside the synchronized below, as this operation can take a while and if synchronized can block slow tailer
|
||||
// from acquiring the next block
|
||||
resizeRafIfTooSmall(chunk);
|
||||
|
||||
synchronized (stores) {
|
||||
|
||||
// We are back, protected by synchronized, and need to
|
||||
// update our view on previous existence (we might have been stalled
|
||||
// for a long time since we last checked dues to resizing and another
|
||||
// thread might have added a MappedByteStore (very unlikely but still possible))
|
||||
final MappedBytesStore mbs1 = stores.get(chunk);
|
||||
if (mbs1 != null && mbs1.tryReserve(owner)) {
|
||||
return mbs1;
|
||||
}
|
||||
// *** THIS CAN TAKE A LONG TIME IF A RESIZE HAS TO OCCUR ***
|
||||
// let double check it to make sure no other thread change it in the meantime.
|
||||
//resizeRafIfTooSmall(chunk);
|
||||
|
||||
final long mappedSize = chunkSize + overlapSize;
|
||||
final MapMode mode = readOnly ? MapMode.READ_ONLY : MapMode.READ_WRITE;
|
||||
final long startOfMap = chunk * chunkSize;
|
||||
|
||||
final long beginNs = System.nanoTime();
|
||||
|
||||
final long address = OS.map(fileChannel, mode, startOfMap, mappedSize);
|
||||
final MappedBytesStore mbs2 = mappedBytesStoreFactory.create(owner, this, chunk * this.chunkSize, address, mappedSize, this.chunkSize);
|
||||
if (RETAIN)
|
||||
mbs2.reserve(this);
|
||||
stores.set(chunk, mbs2);
|
||||
|
||||
final long elapsedNs = System.nanoTime() - beginNs;
|
||||
if (newChunkListener != null)
|
||||
newChunkListener.onNewChunk(file.getPath(), chunk, elapsedNs / 1000);
|
||||
|
||||
if (elapsedNs >= 2_000_000L)
|
||||
Jvm.perf().on(getClass(), "Took " + elapsedNs / 1_000_000L + " ms to add mapping for " + file());
|
||||
|
||||
return mbs2;
|
||||
}
|
||||
}
|
||||
|
||||
private void resizeRafIfTooSmall(final int chunk) throws IOException {
|
||||
Jvm.safepoint();
|
||||
|
||||
final long minSize = (chunk + 1L) * chunkSize + overlapSize;
|
||||
long size = fileChannel.size();
|
||||
Jvm.safepoint();
|
||||
if (size >= minSize || readOnly)
|
||||
return;
|
||||
|
||||
// handle a possible race condition between processes.
|
||||
try {
|
||||
// A single JVM cannot lock a distinct canonical file more than once.
|
||||
|
||||
// We might have several MappedFile objects that maps to
|
||||
// the same underlying file (possibly via hard or soft links)
|
||||
// so we use the canonical path as a lock key
|
||||
|
||||
// Ensure exclusivity for any and all MappedFile objects handling
|
||||
// the same canonical file.
|
||||
synchronized (canonicalPath) {
|
||||
size = fileChannel.size();
|
||||
if (size < minSize) {
|
||||
final long beginNs = System.nanoTime();
|
||||
try (FileLock ignore = fileChannel.lock()) {
|
||||
size = fileChannel.size();
|
||||
if (size < minSize) {
|
||||
Jvm.safepoint();
|
||||
raf.setLength(minSize);
|
||||
Jvm.safepoint();
|
||||
}
|
||||
}
|
||||
final long elapsedNs = System.nanoTime() - beginNs;
|
||||
if (elapsedNs >= 1_000_000L) {
|
||||
Jvm.perf().on(getClass(), "Took " + elapsedNs / 1000L + " us to grow file " + file());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new IOException("Failed to resize to " + minSize, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method so you don't need to release the BytesStore
|
||||
*/
|
||||
|
||||
public Bytes acquireBytesForRead(ReferenceOwner owner, final long position)
|
||||
throws IOException, IllegalStateException, IllegalArgumentException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
final MappedBytesStore mbs = acquireByteStore(owner, position, null);
|
||||
final Bytes bytes = mbs.bytesForRead();
|
||||
bytes.readPositionUnlimited(position);
|
||||
bytes.reserveTransfer(INIT, owner);
|
||||
mbs.release(owner);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public void acquireBytesForRead(ReferenceOwner owner, final long position, final VanillaBytes bytes)
|
||||
throws IOException, IllegalStateException, IllegalArgumentException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
final MappedBytesStore mbs = acquireByteStore(owner, position, null);
|
||||
bytes.bytesStore(mbs, position, mbs.capacity() - position);
|
||||
}
|
||||
|
||||
|
||||
public Bytes acquireBytesForWrite(ReferenceOwner owner, final long position)
|
||||
throws IOException, IllegalStateException, IllegalArgumentException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
MappedBytesStore mbs = acquireByteStore(owner, position, null);
|
||||
Bytes bytes = mbs.bytesForWrite();
|
||||
bytes.writePosition(position);
|
||||
bytes.reserveTransfer(INIT, owner);
|
||||
mbs.release(owner);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public void acquireBytesForWrite(ReferenceOwner owner, final long position, final VanillaBytes bytes)
|
||||
throws IOException, IllegalStateException, IllegalArgumentException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
final MappedBytesStore mbs = acquireByteStore(owner, position, null);
|
||||
bytes.bytesStore(mbs, position, mbs.capacity() - position);
|
||||
bytes.writePosition(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean performReleaseInBackground() {
|
||||
// don't perform the close in the background as that just sets a flag. This does the real work.
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void performRelease() {
|
||||
try {
|
||||
synchronized (stores) {
|
||||
for (int i = 0; i < stores.size(); i++) {
|
||||
final MappedBytesStore mbs = stores.get(i);
|
||||
if (mbs != null && RETAIN) {
|
||||
// this MappedFile is the only referrer to the MappedBytesStore at this point,
|
||||
// so ensure that it is released
|
||||
mbs.release(this);
|
||||
}
|
||||
// Dereference released entities
|
||||
stores.set(i, null);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
closeQuietly(raf);
|
||||
setClosed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String referenceCounts() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("refCount: ").append(refCount());
|
||||
for ( final MappedBytesStore mbs : stores) {
|
||||
long count = 0;
|
||||
if (mbs != null)
|
||||
count = mbs.refCount();
|
||||
sb.append(", ").append(count);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public long capacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
public long chunkSize() {
|
||||
return chunkSize;
|
||||
}
|
||||
|
||||
public long overlapSize() {
|
||||
return overlapSize;
|
||||
}
|
||||
|
||||
public NewChunkListener getNewChunkListener() {
|
||||
return newChunkListener;
|
||||
}
|
||||
|
||||
public void setNewChunkListener(final NewChunkListener listener) {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
this.newChunkListener = listener;
|
||||
}
|
||||
|
||||
public long actualSize() throws IORuntimeException {
|
||||
|
||||
boolean interrupted = Thread.interrupted();
|
||||
try {
|
||||
return fileChannel.size();
|
||||
|
||||
// this was seen once deep in the JVM.
|
||||
} catch (ArrayIndexOutOfBoundsException aiooe) {
|
||||
// try again.
|
||||
return actualSize();
|
||||
|
||||
} catch (ClosedByInterruptException cbie) {
|
||||
close();
|
||||
interrupted = true;
|
||||
throw new IllegalStateException(cbie);
|
||||
|
||||
} catch (IOException e) {
|
||||
final boolean open = fileChannel.isOpen();
|
||||
if (open) {
|
||||
throw new IORuntimeException(e);
|
||||
} else {
|
||||
close();
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
} finally {
|
||||
if (interrupted)
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public RandomAccessFile raf() {
|
||||
return raf;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
warnAndReleaseIfNotReleased();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean threadSafetyCheck(boolean isUsed) {
|
||||
// component is thread safe
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.OS;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import net.openhft.chronicle.core.io.IOTools;
|
||||
import net.openhft.chronicle.core.io.ReferenceOwner;
|
||||
import net.openhft.chronicle.core.time.SystemTimeProvider;
|
||||
import net.openhft.chronicle.core.time.TimeProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Timestamps are unique across threads/processes on a single machine.
|
||||
*
|
||||
* @deprecated Use {@link MappedUniqueTimeProvider} instead.
|
||||
*/
|
||||
@Deprecated(/* to be removed in x.23 */)
|
||||
public enum MappedUniqueMicroTimeProvider implements TimeProvider {
|
||||
INSTANCE;
|
||||
|
||||
private static final int LAST_TIME = 128;
|
||||
|
||||
private final MappedFile file;
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final Bytes bytes;
|
||||
private TimeProvider provider = SystemTimeProvider.INSTANCE;
|
||||
|
||||
MappedUniqueMicroTimeProvider() {
|
||||
try {
|
||||
String user = System.getProperty("user.name", "unknown");
|
||||
file = MappedFile.mappedFile(OS.TMP + "/.time-stamp." + user + ".dat", OS.pageSize(), 0);
|
||||
IOTools.unmonitor(file);
|
||||
ReferenceOwner mumtp = ReferenceOwner.temporary("mumtp");
|
||||
bytes = file.acquireBytesForWrite(mumtp, 0);
|
||||
bytes.append8bit("&TSF\nTime stamp file uses for sharing a unique id\n");
|
||||
IOTools.unmonitor(bytes);
|
||||
} catch (IOException ioe) {
|
||||
throw new IORuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public MappedUniqueMicroTimeProvider provider(TimeProvider provider) {
|
||||
this.provider = provider;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long currentTimeMillis() {
|
||||
return provider.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long currentTimeMicros() {
|
||||
long timeus = provider.currentTimeMicros();
|
||||
while (true) {
|
||||
long time0 = bytes.readVolatileLong(LAST_TIME);
|
||||
long time0us = time0 / 1000;
|
||||
long time;
|
||||
if (time0us >= timeus)
|
||||
time = (time0us + 1) * 1000;
|
||||
else
|
||||
time = timeus * 1000;
|
||||
if (bytes.compareAndSwapLong(LAST_TIME, time0, time))
|
||||
return time / 1_000;
|
||||
Jvm.nanoPause();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long currentTimeNanos() {
|
||||
long time = provider.currentTimeNanos();
|
||||
while (true) {
|
||||
long time0 = bytes.readVolatileLong(LAST_TIME);
|
||||
if (time0 >= time)
|
||||
time = time0 + 1;
|
||||
if (bytes.compareAndSwapLong(LAST_TIME, time0, time))
|
||||
return time;
|
||||
Jvm.nanoPause();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.OS;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import net.openhft.chronicle.core.io.IOTools;
|
||||
import net.openhft.chronicle.core.io.ReferenceOwner;
|
||||
import net.openhft.chronicle.core.time.SystemTimeProvider;
|
||||
import net.openhft.chronicle.core.time.TimeProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Timestamps are unique across threads/processes on a single machine.
|
||||
*/
|
||||
public enum MappedUniqueTimeProvider implements TimeProvider {
|
||||
INSTANCE;
|
||||
|
||||
private static final int LAST_TIME = 128;
|
||||
|
||||
private final MappedFile file;
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final Bytes bytes;
|
||||
private TimeProvider provider = SystemTimeProvider.INSTANCE;
|
||||
|
||||
MappedUniqueTimeProvider() {
|
||||
try {
|
||||
String user = System.getProperty("user.name", "unknown");
|
||||
file = MappedFile.mappedFile(OS.TMP + "/.time-stamp." + user + ".dat", OS.pageSize(), 0);
|
||||
IOTools.unmonitor(file);
|
||||
ReferenceOwner mumtp = ReferenceOwner.temporary("mumtp");
|
||||
bytes = file.acquireBytesForWrite(mumtp, 0);
|
||||
bytes.append8bit("&TSF\nTime stamp file uses for sharing a unique id\n");
|
||||
IOTools.unmonitor(bytes);
|
||||
} catch (IOException ioe) {
|
||||
throw new IORuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public MappedUniqueTimeProvider provider(TimeProvider provider) {
|
||||
this.provider = provider;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long currentTimeMillis() {
|
||||
return provider.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long currentTimeMicros() {
|
||||
long timeus = provider.currentTimeMicros();
|
||||
while (true) {
|
||||
long time0 = bytes.readVolatileLong(LAST_TIME);
|
||||
long time0us = time0 / 1000;
|
||||
long time;
|
||||
if (time0us >= timeus)
|
||||
time = (time0us + 1) * 1000;
|
||||
else
|
||||
time = timeus * 1000;
|
||||
if (bytes.compareAndSwapLong(LAST_TIME, time0, time))
|
||||
return time / 1_000;
|
||||
Jvm.nanoPause();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long currentTimeNanos() {
|
||||
long time = provider.currentTimeNanos();
|
||||
long time5 = time >>> 5;
|
||||
|
||||
long time0 = bytes.readVolatileLong(LAST_TIME);
|
||||
long timeNanos5 = time0 >>> 5;
|
||||
|
||||
if (time5 > timeNanos5)
|
||||
if (bytes.compareAndSwapLong(LAST_TIME, time0, time))
|
||||
return time;
|
||||
|
||||
while (true) {
|
||||
time0 = bytes.readVolatileLong(LAST_TIME);
|
||||
long next = (time0 + 0x20) & ~0x1f;
|
||||
if (bytes.compareAndSwapLong(LAST_TIME, time0, next))
|
||||
return next;
|
||||
Jvm.nanoPause();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
public interface MethodEncoder {
|
||||
long messageId();
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
void encode(Object[] objects, BytesOut out);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
Object[] decode(Object[] lastObjects, BytesIn in);
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.util.Annotations;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Function;
|
||||
|
||||
public enum MethodEncoderLookup implements Function<Method, MethodEncoder> {
|
||||
BY_ANNOTATION;
|
||||
|
||||
@Override
|
||||
public MethodEncoder apply(Method method) {
|
||||
MethodId methodId = Annotations.getAnnotation(method, MethodId.class);
|
||||
if (methodId == null) return null;
|
||||
long messageId = methodId.value();
|
||||
return new MethodEncoder() {
|
||||
@Override
|
||||
public long messageId() {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public void encode(Object[] objects, BytesOut out) {
|
||||
for (Object object : objects) {
|
||||
if (object instanceof BytesMarshallable) {
|
||||
((BytesMarshallable) object).writeMarshallable(out);
|
||||
continue;
|
||||
}
|
||||
throw new IllegalArgumentException("Object type " + object + " not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Object[] decode(Object[] lastObjects, BytesIn in) {
|
||||
for (Object lastObject : lastObjects)
|
||||
((BytesMarshallable) lastObject).readMarshallable(in);
|
||||
return lastObjects;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Inherited
|
||||
public @interface MethodId {
|
||||
long value();
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.Closeable;
|
||||
import net.openhft.chronicle.core.util.InvocationTargetRuntimeException;
|
||||
|
||||
public interface MethodReader extends Closeable {
|
||||
String HISTORY = "history";
|
||||
|
||||
MethodReaderInterceptorReturns methodReaderInterceptorReturns();
|
||||
|
||||
/**
|
||||
* Moves the queue to read a message if there is one, but is more expensive than {@link #lazyReadOne()}.
|
||||
* If there is an exception in the dispatching mechanics then this should be caught and Jvm.warn'd.
|
||||
* If there is an exception in the invocation then this is wrapped in a {@link InvocationTargetRuntimeException}
|
||||
* and thrown.
|
||||
*
|
||||
* @return true if there was a message, false if no more messages.
|
||||
* @throws InvocationTargetRuntimeException if the receiver (target method) throws
|
||||
*/
|
||||
boolean readOne() throws InvocationTargetRuntimeException;
|
||||
|
||||
/**
|
||||
* Does a quick read which is simpler but might not read the next message. readOne() has to be called periodically.
|
||||
* See also javadoc for {@link #readOne()}
|
||||
*
|
||||
* @return true if there was a message, false if there is probably not a message.
|
||||
*/
|
||||
default boolean lazyReadOne() {
|
||||
return readOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call close on the input when closed
|
||||
*/
|
||||
MethodReader closeIn(boolean closeIn);
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
public interface MethodReaderBuilder {
|
||||
default MethodReaderBuilder methodReaderInterceptor(MethodReaderInterceptor methodReaderInterceptor) {
|
||||
return methodReaderInterceptorReturns((m, o, a, i) -> {
|
||||
methodReaderInterceptor.intercept(m, o, a, i);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
MethodReaderBuilder methodReaderInterceptorReturns(MethodReaderInterceptorReturns methodReaderInterceptorReturns);
|
||||
|
||||
MethodReaderBuilder warnMissing(boolean warnMissing);
|
||||
|
||||
MethodReader build(Object... components);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link MethodReaderInterceptorReturns}
|
||||
*/
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
@FunctionalInterface
|
||||
public interface MethodReaderInterceptor {
|
||||
void intercept(Method m, Object o, Object[] args, Invocation invocation) throws InvocationTargetException;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface MethodReaderInterceptorReturns {
|
||||
Object intercept(Method m, Object o, Object[] args, Invocation invocation) throws InvocationTargetException;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.Closeable;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface MethodWriterBuilder<T> extends Supplier<T> {
|
||||
|
||||
MethodWriterBuilder<T> genericEvent(String genericEvent);
|
||||
|
||||
default MethodWriterBuilder<T> metaData(boolean metaData) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated(/* to be removed in x.23 */)
|
||||
MethodWriterBuilder<T> useMethodIds(boolean useMethodIds);
|
||||
|
||||
MethodWriterBuilder<T> onClose(Closeable closeable);
|
||||
|
||||
// sourceId enables this, this isn't useful unless it's set.
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
MethodWriterBuilder<T> recordHistory(boolean recordHistory);
|
||||
|
||||
default MethodWriterBuilder<T> updateInterceptor(UpdateInterceptor updateInterceptor) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
default T build() {
|
||||
return get();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Invoked around method writing allowing you to take action before or after method invocation,
|
||||
* or even not to call the method
|
||||
*
|
||||
* @deprecated Use MethodWriterInterceptorReturns
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
public interface MethodWriterInterceptor {
|
||||
|
||||
static MethodWriterInterceptor of( final MethodWriterListener methodWriterListener, final MethodWriterInterceptor interceptor) {
|
||||
if (methodWriterListener == null && interceptor == null)
|
||||
throw new IllegalArgumentException("both methodWriterListener and interceptor are NULL");
|
||||
|
||||
if (methodWriterListener == null)
|
||||
return interceptor::intercept;
|
||||
|
||||
if (interceptor == null)
|
||||
return (method, args, invoker) -> {
|
||||
methodWriterListener.onWrite(method.getName(), args);
|
||||
invoker.accept(method, args);
|
||||
};
|
||||
|
||||
return (method, args, invoker) -> {
|
||||
interceptor.intercept(method, args, invoker);
|
||||
methodWriterListener.onWrite(method.getName(), args);
|
||||
};
|
||||
}
|
||||
|
||||
void intercept(Method method, Object[] args, BiConsumer<Method, Object[]> invoker);
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/*
|
||||
* Peter Lawrey so interceptors can return an object to use for chaining.
|
||||
* <p>
|
||||
* Invoked around method writing allowing you to take action before or after method invocation,
|
||||
* or even not to call the method
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface MethodWriterInterceptorReturns {
|
||||
static MethodWriterInterceptorReturns of(MethodWriterInterceptor interceptor) {
|
||||
return (m, a, i) -> {
|
||||
interceptor.intercept(m, a, i::apply);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
static MethodWriterInterceptorReturns of( final MethodWriterListener methodWriterListener, final MethodWriterInterceptorReturns interceptor) {
|
||||
if (methodWriterListener == null && interceptor == null)
|
||||
throw new IllegalArgumentException("both methodWriterListener and interceptor are NULL");
|
||||
|
||||
if (methodWriterListener == null)
|
||||
return interceptor;
|
||||
|
||||
if (interceptor == null)
|
||||
return (method, args, invoker) -> {
|
||||
methodWriterListener.onWrite(method.getName(), args);
|
||||
return invoker.apply(method, args);
|
||||
};
|
||||
|
||||
return (method, args, invoker) -> {
|
||||
methodWriterListener.onWrite(method.getName(), args);
|
||||
return interceptor.intercept(method, args, invoker);
|
||||
};
|
||||
}
|
||||
|
||||
Object intercept(Method method, Object[] args, BiFunction<Method, Object[], Object> invoker);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.Closeable;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
|
||||
public interface MethodWriterInvocationHandler extends InvocationHandler {
|
||||
void recordHistory(boolean recordHistory);
|
||||
|
||||
void onClose(Closeable closeable);
|
||||
|
||||
default void methodWriterInterceptorReturns(MethodWriterListener methodWriterListener, MethodWriterInterceptorReturns interceptor) {
|
||||
if (methodWriterListener != null || interceptor != null)
|
||||
methodWriterInterceptorReturns(MethodWriterInterceptorReturns.of(methodWriterListener, interceptor));
|
||||
}
|
||||
|
||||
void methodWriterInterceptorReturns(MethodWriterInterceptorReturns methodWriterInterceptor);
|
||||
|
||||
void genericEvent(String genericEvent);
|
||||
|
||||
void useMethodIds(boolean useMethodIds);
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
/**
|
||||
* Invoked before writing out this method and args.
|
||||
*
|
||||
* @deprecated Use MethodWriterInterceptorReturns
|
||||
*/
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
@FunctionalInterface
|
||||
public interface MethodWriterListener {
|
||||
void onWrite(String name, Object[] args);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface MultiReaderBytesRingBuffer extends BytesRingBuffer {
|
||||
|
||||
|
||||
default RingBufferReader createReader() {
|
||||
return createReader(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a reader
|
||||
*
|
||||
* @param id of reader as each reader has separate read position etc.
|
||||
* @return reader
|
||||
*/
|
||||
|
||||
RingBufferReader createReader(int id);
|
||||
}
|
|
@ -0,0 +1,409 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.bytes.util.DecoratedBufferOverflowException;
|
||||
import net.openhft.chronicle.core.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static net.openhft.chronicle.bytes.NativeBytesStore.nativeStoreWithFixedCapacity;
|
||||
import static net.openhft.chronicle.bytes.NoBytesStore.noBytesStore;
|
||||
|
||||
/**
|
||||
* Elastic memory accessor which can wrap either a ByteBuffer or malloc'ed memory.
|
||||
* <p>
|
||||
* <p>This class can wrap <i>heap</i> ByteBuffers, called <i>Native</i>Bytes for historical reasons.
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class NativeBytes<Underlying>
|
||||
extends VanillaBytes<Underlying> {
|
||||
private static final boolean BYTES_GUARDED = Jvm.getBoolean("bytes.guarded");
|
||||
private static boolean s_newGuarded = BYTES_GUARDED;
|
||||
private final long capacity;
|
||||
|
||||
public NativeBytes( final BytesStore store, final long capacity) throws IllegalStateException {
|
||||
super(store, 0, capacity);
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
public NativeBytes( final BytesStore store) throws IllegalStateException {
|
||||
super(store, 0, store.capacity());
|
||||
capacity = store.capacity();
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing
|
||||
*
|
||||
* @return will new NativeBytes be guarded.
|
||||
*/
|
||||
public static boolean areNewGuarded() {
|
||||
return s_newGuarded;
|
||||
}
|
||||
|
||||
/**
|
||||
* turn guarding on/off. Can be enabled by assertion with
|
||||
* <code>
|
||||
* assert NativeBytes.setNewGuarded(true);
|
||||
* </code>
|
||||
*
|
||||
* @param guarded turn on if true
|
||||
*/
|
||||
public static boolean setNewGuarded(final boolean guarded) {
|
||||
s_newGuarded = guarded;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing
|
||||
*/
|
||||
public static void resetNewGuarded() {
|
||||
s_newGuarded = BYTES_GUARDED;
|
||||
}
|
||||
|
||||
|
||||
public static NativeBytes<Void> nativeBytes() {
|
||||
try {
|
||||
return NativeBytes.wrapWithNativeBytes(noBytesStore(), Bytes.MAX_CAPACITY);
|
||||
} catch (IllegalStateException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static NativeBytes<Void> nativeBytes(final long initialCapacity) throws IllegalArgumentException {
|
||||
final NativeBytesStore<Void> store = nativeStoreWithFixedCapacity(initialCapacity);
|
||||
try {
|
||||
try {
|
||||
return NativeBytes.wrapWithNativeBytes(store, Bytes.MAX_CAPACITY);
|
||||
} finally {
|
||||
store.release(INIT);
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static BytesStore<Bytes<Void>, Void> copyOf( final Bytes bytes) {
|
||||
final long remaining = bytes.readRemaining();
|
||||
|
||||
try {
|
||||
final NativeBytes<Void> bytes2 = Bytes.allocateElasticDirect(remaining);
|
||||
bytes2.write(bytes, 0, remaining);
|
||||
return bytes2;
|
||||
} catch (IllegalArgumentException | BufferOverflowException | BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static long alignToPageSize(final long size) {
|
||||
long mask = OS.pageSize() - 1;
|
||||
return (size + mask) & ~mask;
|
||||
}
|
||||
|
||||
|
||||
public static <T> NativeBytes<T> wrapWithNativeBytes( final BytesStore<?, T> bs, long capacity) {
|
||||
return s_newGuarded
|
||||
? new GuardedNativeBytes(bs, capacity)
|
||||
: new NativeBytes<>(bs, capacity);
|
||||
}
|
||||
|
||||
protected static <T> long maxCapacityFor( BytesStore<?, T> bs) {
|
||||
return bs.underlyingObject() instanceof ByteBuffer
|
||||
|| bs.underlyingObject() instanceof byte[]
|
||||
? MAX_HEAP_CAPACITY
|
||||
: Bytes.MAX_CAPACITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long capacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeCheckOffset(final long offset, final long adding) throws BufferOverflowException {
|
||||
if (offset >= bytesStore.start()) {
|
||||
final long writeEnd = offset + adding;
|
||||
if (writeEnd <= bytesStore.safeLimit()) {
|
||||
return; // do nothing.
|
||||
}
|
||||
if (writeEnd >= capacity)
|
||||
throw new BufferOverflowException(/*"Write exceeds capacity"*/);
|
||||
checkResize(writeEnd);
|
||||
} else {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void prewriteCheckOffset(long offset, long subtracting) throws BufferOverflowException {
|
||||
if (offset - subtracting >= bytesStore.start()) {
|
||||
if (offset <= bytesStore.safeLimit()) {
|
||||
return; // do nothing.
|
||||
}
|
||||
if (offset >= capacity)
|
||||
throw new BufferOverflowException(/*"Write exceeds capacity"*/);
|
||||
checkResize(offset);
|
||||
} else {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ensureCapacity(final long size) throws IllegalArgumentException {
|
||||
try {
|
||||
assert size >= 0;
|
||||
writeCheckOffset(writePosition(), size);
|
||||
} catch (BufferOverflowException e) {
|
||||
IllegalArgumentException iae = new IllegalArgumentException("Bytes cannot be resized to " + size + " limit: " + capacity());
|
||||
iae.printStackTrace();
|
||||
throw iae;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkResize(final long endOfBuffer) throws BufferOverflowException {
|
||||
if (isElastic())
|
||||
resize(endOfBuffer);
|
||||
else
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isElastic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// the endOfBuffer is the minimum capacity and one byte more than the last addressable byte.
|
||||
private void resize(final long endOfBuffer)
|
||||
throws BufferOverflowException {
|
||||
throwExceptionIfReleased();
|
||||
if (endOfBuffer < 0)
|
||||
throw new DecoratedBufferOverflowException(endOfBuffer + "< 0");
|
||||
if (endOfBuffer > capacity())
|
||||
throw new DecoratedBufferOverflowException(endOfBuffer + ">" + capacity());
|
||||
final long realCapacity = realCapacity();
|
||||
if (endOfBuffer <= realCapacity) {
|
||||
// System.out.println("no resize " + endOfBuffer + " < " + realCapacity);
|
||||
return;
|
||||
}
|
||||
|
||||
// Grow by 50%
|
||||
long size = Math.max(endOfBuffer + 7, realCapacity * 3 / 2 + 32);
|
||||
if (isDirectMemory() || size > MAX_HEAP_CAPACITY) {
|
||||
// Allocate direct memory of page granularity
|
||||
size = alignToPageSize(size);
|
||||
} else {
|
||||
size &= ~0x7;
|
||||
}
|
||||
// Cap the size with capacity() again
|
||||
size = Math.min(size, capacity());
|
||||
|
||||
final boolean isByteBufferBacked = bytesStore.underlyingObject() instanceof ByteBuffer;
|
||||
if (isByteBufferBacked && size > MAX_HEAP_CAPACITY) {
|
||||
|
||||
// Add a stack trace to this relatively unusual event which will
|
||||
// enable tracing of potentially derailed code or excessive buffer use.
|
||||
final StackTrace stackTrace = new StackTrace();
|
||||
final String stack = BytesUtil.asString("Calling stack is", stackTrace);
|
||||
|
||||
Jvm.warn().on(getClass(), "Going to try to replace ByteBuffer-backed BytesStore with " +
|
||||
"raw NativeBytesStore to grow to " + size / 1024 + " KB. If later it is assumed that " +
|
||||
"this bytes' underlyingObject() is ByteBuffer, NullPointerException is likely to be thrown. " +
|
||||
stack);
|
||||
}
|
||||
// System.out.println("resize " + endOfBuffer + " to " + size);
|
||||
if (endOfBuffer > 1 << 20)
|
||||
Jvm.warn().on(getClass(), "Resizing buffer was " + realCapacity / 1024 + " KB, " +
|
||||
"needs " + (endOfBuffer - realCapacity) + " bytes more, " +
|
||||
"new-size " + size / 1024 + " KB");
|
||||
final BytesStore store;
|
||||
int position = 0;
|
||||
try {
|
||||
if (isByteBufferBacked && size <= MAX_HEAP_CAPACITY) {
|
||||
position = ((ByteBuffer) bytesStore.underlyingObject()).position();
|
||||
store = allocateNewByteBufferBackedStore(Maths.toInt32(size));
|
||||
} else {
|
||||
store = NativeBytesStore.lazyNativeBytesStoreWithFixedCapacity(size);
|
||||
}
|
||||
store.reserveTransfer(INIT, this);
|
||||
} catch (IllegalArgumentException e) {
|
||||
BufferOverflowException boe = new BufferOverflowException();
|
||||
boe.initCause(e);
|
||||
throw boe;
|
||||
}
|
||||
|
||||
throwExceptionIfReleased();
|
||||
final BytesStore<Bytes<Underlying>, Underlying> tempStore = this.bytesStore;
|
||||
this.bytesStore.copyTo(store);
|
||||
this.bytesStore(store);
|
||||
try {
|
||||
tempStore.release(this);
|
||||
} catch (IllegalStateException e) {
|
||||
Jvm.debug().on(getClass(), e);
|
||||
}
|
||||
|
||||
if (this.bytesStore.underlyingObject() instanceof ByteBuffer) {
|
||||
final ByteBuffer byteBuffer = (ByteBuffer) this.bytesStore.underlyingObject();
|
||||
byteBuffer.position(0);
|
||||
byteBuffer.limit(byteBuffer.capacity());
|
||||
byteBuffer.position(position);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private BytesStore allocateNewByteBufferBackedStore(final int size) {
|
||||
if (isDirectMemory()) {
|
||||
return NativeBytesStore.elasticByteBuffer(size, capacity());
|
||||
} else {
|
||||
return HeapBytesStore.wrap(ByteBuffer.allocate(size));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> write( final byte[] bytes,
|
||||
final int offset,
|
||||
final int length) throws BufferOverflowException, IllegalArgumentException {
|
||||
if (length > writeRemaining())
|
||||
throw new BufferOverflowException();
|
||||
ensureCapacity(length);
|
||||
super.write(bytes, offset, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public Bytes<Underlying> write( final BytesStore bytes,
|
||||
final long offset,
|
||||
final long length) throws BufferOverflowException, IllegalArgumentException, BufferUnderflowException {
|
||||
ensureCapacity(length);
|
||||
super.write(bytes, offset, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public NativeBytes writeSome( final Bytes bytes) {
|
||||
try {
|
||||
long length = Math.min(bytes.readRemaining(), writeRemaining());
|
||||
if (length + writePosition() >= 1 << 20)
|
||||
length = Math.min(bytes.readRemaining(), realCapacity() - writePosition());
|
||||
final long offset = bytes.readPosition();
|
||||
ensureCapacity(length);
|
||||
optimisedWrite(bytes, offset, length);
|
||||
if (length == bytes.readRemaining()) {
|
||||
bytes.clear();
|
||||
} else {
|
||||
bytes.readSkip(length);
|
||||
if (bytes.writePosition() > bytes.realCapacity() / 2)
|
||||
bytes.compact();
|
||||
}
|
||||
return this;
|
||||
} catch (IllegalArgumentException | BufferUnderflowException | BufferOverflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long writeOffsetPositionMoved(final long adding, final long advance) throws BufferOverflowException {
|
||||
final long oldPosition = writePosition;
|
||||
if (writePosition < bytesStore.start())
|
||||
throw new BufferOverflowException();
|
||||
final long writeEnd = writePosition + adding;
|
||||
if (writeEnd > writeLimit)
|
||||
throwBeyondWriteLimit(advance, writeEnd);
|
||||
else if (writeEnd > bytesStore.safeLimit())
|
||||
checkResize(writeEnd);
|
||||
this.writePosition = writePosition + advance;
|
||||
return oldPosition;
|
||||
}
|
||||
|
||||
private void throwBeyondWriteLimit(long advance, long writeEnd) {
|
||||
throw new DecoratedBufferOverflowException("attempt to write " + advance + " bytes to " + writeEnd + " limit: " + writeLimit);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeByte(final byte i8) throws BufferOverflowException {
|
||||
final long offset = writeOffsetPositionMoved(1, 1);
|
||||
bytesStore.writeByte(offset, i8);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> write8bit( final BytesStore bs) throws BufferOverflowException {
|
||||
if (bs == null) {
|
||||
writeStopBit(-1);
|
||||
} else {
|
||||
final long offset = bs.readPosition();
|
||||
final long readRemaining = Math.min(writeRemaining(), bs.readLimit() - offset);
|
||||
writeStopBit(readRemaining);
|
||||
write(bs, offset, readRemaining);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeLong(final long i64) throws BufferOverflowException {
|
||||
final long offset = writeOffsetPositionMoved(8L, 8L);
|
||||
bytesStore.writeLong(offset, i64);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readRemaining() {
|
||||
return writePosition - readPosition;
|
||||
}
|
||||
|
||||
public final static class NativeSubBytes extends SubBytes {
|
||||
private final NativeBytesStore nativeBytesStore;
|
||||
|
||||
public NativeSubBytes( final BytesStore bytesStore,
|
||||
final long start,
|
||||
final long capacity) throws IllegalStateException {
|
||||
super(bytesStore, start, capacity);
|
||||
nativeBytesStore = (NativeBytesStore) this.bytesStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read(final long offsetInRDI,
|
||||
final byte[] bytes,
|
||||
final int offset,
|
||||
final int length) {
|
||||
|
||||
final int len = (int) Math.min(length, readLimit() - offsetInRDI);
|
||||
int i;
|
||||
final long address = nativeBytesStore.address + nativeBytesStore.translate(offsetInRDI);
|
||||
for (i = 0; i < len - 7; i += 8)
|
||||
UnsafeMemory.unsafePutLong(bytes, i, nativeBytesStore.memory.readLong(address + i));
|
||||
if (i < len - 3) {
|
||||
UnsafeMemory.unsafePutInt(bytes, i, nativeBytesStore.memory.readInt(address + i));
|
||||
i += 4;
|
||||
}
|
||||
for (; i < len; i++)
|
||||
UnsafeMemory.unsafePutByte(bytes, i, nativeBytesStore.memory.readByte(address + i));
|
||||
return len;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,852 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.*;
|
||||
import net.openhft.chronicle.core.annotation.ForceInline;
|
||||
import net.openhft.chronicle.core.cleaner.CleanerServiceLocator;
|
||||
import net.openhft.chronicle.core.cleaner.spi.ByteBufferCleanerService;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import net.openhft.chronicle.core.util.SimpleCleaner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static net.openhft.chronicle.bytes.Bytes.MAX_CAPACITY;
|
||||
|
||||
@SuppressWarnings({"restriction", "rawtypes", "unchecked"})
|
||||
public class NativeBytesStore<Underlying>
|
||||
extends AbstractBytesStore<NativeBytesStore<Underlying>, Underlying> {
|
||||
private static final long MEMORY_MAPPED_SIZE = 128 << 10;
|
||||
private static final Field BB_ADDRESS, BB_CAPACITY, BB_ATT;
|
||||
private static final ByteBufferCleanerService CLEANER_SERVICE = CleanerServiceLocator.cleanerService();
|
||||
// static MappedBytes last;
|
||||
|
||||
static {
|
||||
Class directBB = ByteBuffer.allocateDirect(0).getClass();
|
||||
BB_ADDRESS = Jvm.getField(directBB, "address");
|
||||
BB_CAPACITY = Jvm.getField(directBB, "capacity");
|
||||
BB_ATT = Jvm.getField(directBB, "att");
|
||||
}
|
||||
|
||||
protected long address;
|
||||
// on release, set this to null.
|
||||
protected Memory memory = OS.memory();
|
||||
protected long limit, maximumLimit;
|
||||
|
||||
private SimpleCleaner cleaner;
|
||||
private boolean elastic;
|
||||
|
||||
private Underlying underlyingObject;
|
||||
private final Finalizer finalizer;
|
||||
|
||||
private NativeBytesStore() {
|
||||
finalizer = null;
|
||||
}
|
||||
|
||||
private NativeBytesStore( ByteBuffer bb, boolean elastic) {
|
||||
this(bb, elastic, Bytes.MAX_HEAP_CAPACITY);
|
||||
}
|
||||
|
||||
public NativeBytesStore( ByteBuffer bb, boolean elastic, int maximumLimit) {
|
||||
this();
|
||||
init(bb, elastic);
|
||||
this.maximumLimit = elastic ? maximumLimit : Math.min(limit, maximumLimit);
|
||||
}
|
||||
|
||||
public NativeBytesStore(
|
||||
long address, long limit) {
|
||||
this(address, limit, null, false);
|
||||
}
|
||||
|
||||
public NativeBytesStore(
|
||||
long address, long limit, Runnable deallocator, boolean elastic) {
|
||||
this(address, limit, deallocator, elastic, false);
|
||||
}
|
||||
|
||||
protected NativeBytesStore(
|
||||
long address, long limit, Runnable deallocator, boolean elastic, boolean monitored) {
|
||||
super(monitored);
|
||||
setAddress(address);
|
||||
this.limit = limit;
|
||||
this.maximumLimit = elastic ? MAX_CAPACITY : limit;
|
||||
this.cleaner = deallocator == null ? null : new SimpleCleaner(deallocator);
|
||||
underlyingObject = null;
|
||||
this.elastic = elastic;
|
||||
if (cleaner == null)
|
||||
finalizer = null;
|
||||
else
|
||||
finalizer = new Finalizer();
|
||||
}
|
||||
|
||||
|
||||
public static NativeBytesStore<ByteBuffer> wrap( ByteBuffer bb) {
|
||||
return new NativeBytesStore<>(bb, false);
|
||||
}
|
||||
|
||||
|
||||
public static <T> NativeBytesStore<T> uninitialized() {
|
||||
return new NativeBytesStore<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* this is an elastic native store
|
||||
*
|
||||
* @param capacity of the buffer.
|
||||
*/
|
||||
|
||||
public static NativeBytesStore<Void> nativeStore(long capacity)
|
||||
throws IllegalArgumentException {
|
||||
return of(capacity, true, true);
|
||||
}
|
||||
|
||||
|
||||
private static NativeBytesStore<Void> of(long capacity, boolean zeroOut, boolean elastic)
|
||||
throws IllegalArgumentException {
|
||||
if (capacity <= 0)
|
||||
return new NativeBytesStore<>(NoBytesStore.NO_PAGE, 0, null, elastic);
|
||||
Memory memory = OS.memory();
|
||||
long address = memory.allocate(capacity);
|
||||
if (zeroOut || capacity < MEMORY_MAPPED_SIZE) {
|
||||
memory.setMemory(address, capacity, (byte) 0);
|
||||
memory.storeFence();
|
||||
}
|
||||
Deallocator deallocator = new Deallocator(address, capacity);
|
||||
return new NativeBytesStore<>(address, capacity, deallocator, elastic);
|
||||
}
|
||||
|
||||
|
||||
public static NativeBytesStore<Void> nativeStoreWithFixedCapacity(long capacity)
|
||||
throws IllegalArgumentException {
|
||||
return of(capacity, true, false);
|
||||
}
|
||||
|
||||
|
||||
public static NativeBytesStore<Void> lazyNativeBytesStoreWithFixedCapacity(long capacity)
|
||||
throws IllegalArgumentException {
|
||||
return of(capacity, false, false);
|
||||
}
|
||||
|
||||
|
||||
public static NativeBytesStore<ByteBuffer> elasticByteBuffer() {
|
||||
return elasticByteBuffer(OS.pageSize(), MAX_CAPACITY);
|
||||
}
|
||||
|
||||
|
||||
public static NativeBytesStore<ByteBuffer> elasticByteBuffer(int size, long maxSize) {
|
||||
return new NativeBytesStore<>(ByteBuffer.allocateDirect(size), true, Math.toIntExact(maxSize));
|
||||
}
|
||||
|
||||
|
||||
public static NativeBytesStore from( String text) {
|
||||
return from(text.getBytes(StandardCharsets.ISO_8859_1));
|
||||
}
|
||||
|
||||
|
||||
public static NativeBytesStore from( byte[] bytes) {
|
||||
try {
|
||||
NativeBytesStore nbs = nativeStoreWithFixedCapacity(bytes.length);
|
||||
Bytes<byte[]> bytes2 = Bytes.wrapForRead(bytes);
|
||||
bytes2.copyTo(nbs);
|
||||
bytes2.releaseLast();
|
||||
return nbs;
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectMemory() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canReadDirect(long length) {
|
||||
return limit >= length;
|
||||
}
|
||||
|
||||
public void init( ByteBuffer bb, boolean elastic) {
|
||||
this.elastic = elastic;
|
||||
underlyingObject = (Underlying) bb;
|
||||
setAddress(Jvm.address(bb));
|
||||
this.limit = bb.capacity();
|
||||
}
|
||||
|
||||
public void uninit() {
|
||||
underlyingObject = null;
|
||||
address = 0;
|
||||
limit = 0;
|
||||
maximumLimit = 0;
|
||||
cleaner = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(long from, long to, long length) throws BufferUnderflowException {
|
||||
if (from < 0 || to < 0) throw new BufferUnderflowException();
|
||||
long address = this.address;
|
||||
if (address == 0) throwException(null);
|
||||
memoryCopyMemory(address + from, address + to, length);
|
||||
}
|
||||
|
||||
private void memoryCopyMemory(long fromAddress, long toAddress, long length) {
|
||||
try {
|
||||
memory.copyMemory(fromAddress, toAddress, length);
|
||||
} catch (NullPointerException ifReleased) {
|
||||
throwException(ifReleased);
|
||||
}
|
||||
}
|
||||
|
||||
private void throwException(Throwable ifReleased) {
|
||||
throwExceptionIfReleased();
|
||||
throw new IllegalStateException(ifReleased);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BytesStore<NativeBytesStore<Underlying>, Underlying> copy() {
|
||||
try {
|
||||
if (underlyingObject == null) {
|
||||
NativeBytesStore<Void> copy = of(realCapacity(), false, true);
|
||||
memoryCopyMemory(address, copy.address, capacity());
|
||||
return (BytesStore) copy;
|
||||
|
||||
} else if (underlyingObject instanceof ByteBuffer) {
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(Maths.toInt32(capacity()));
|
||||
bb.put((ByteBuffer) underlyingObject);
|
||||
bb.clear();
|
||||
return (BytesStore) wrap(bb);
|
||||
|
||||
} else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public VanillaBytes<Underlying> bytesForWrite() throws IllegalStateException {
|
||||
return elastic
|
||||
? NativeBytes.wrapWithNativeBytes(this, this.capacity())
|
||||
: new VanillaBytes<>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long realCapacity() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long capacity() {
|
||||
return maximumLimit;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Underlying underlyingObject() {
|
||||
return underlyingObject;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> zeroOut(long start, long end) {
|
||||
if (end <= start)
|
||||
return this;
|
||||
if (start < start())
|
||||
start = start();
|
||||
if (end > capacity())
|
||||
end = capacity();
|
||||
|
||||
memory.setMemory(address + translate(start), end - start, (byte) 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public boolean compareAndSwapInt(long offset, int expected, int value) {
|
||||
return memory.compareAndSwapInt(address + translate(offset), expected, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testAndSetInt(long offset, int expected, int value) {
|
||||
memory.testAndSetInt(address + translate(offset), offset, expected, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public boolean compareAndSwapLong(long offset, long expected, long value) {
|
||||
return memory.compareAndSwapLong(address + translate(offset), expected, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long addAndGetLong(long offset, long adding) throws BufferUnderflowException {
|
||||
return memory.addLong(address + translate(offset), adding);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public int addAndGetInt(long offset, int adding) throws BufferUnderflowException {
|
||||
return memory.addInt(address + translate(offset), adding);
|
||||
}
|
||||
|
||||
protected long translate(long offset) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public byte readByte(long offset) {
|
||||
return memory.readByte(address + translate(offset));
|
||||
}
|
||||
|
||||
public int readUnsignedByte(long offset) throws BufferUnderflowException {
|
||||
return readByte(offset) & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public short readShort(long offset) {
|
||||
return memory.readShort(address + translate(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public int readInt(long offset) {
|
||||
return memory.readInt(address + translate(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long readLong(long offset) {
|
||||
long address = this.address;
|
||||
assert address != 0;
|
||||
return memory.readLong(address + translate(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public float readFloat(long offset) {
|
||||
return memory.readFloat(address + translate(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public double readDouble(long offset) {
|
||||
return memory.readDouble(address + translate(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public byte readVolatileByte(long offset) {
|
||||
return memory.readVolatileByte(address + translate(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public short readVolatileShort(long offset) {
|
||||
return memory.readVolatileShort(address + translate(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public int readVolatileInt(long offset) {
|
||||
return memory.readVolatileInt(address + translate(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long readVolatileLong(long offset) {
|
||||
return memory.readVolatileLong(address + translate(offset));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> writeByte(long offset, byte i8) {
|
||||
memory.writeByte(address + translate(offset), i8);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> writeShort(long offset, short i16) {
|
||||
memory.writeShort(address + translate(offset), i16);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> writeInt(long offset, int i32) {
|
||||
try {
|
||||
memory.writeInt(address + translate(offset), i32);
|
||||
return this;
|
||||
} catch (NullPointerException e) {
|
||||
throwExceptionIfReleased();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> writeOrderedInt(long offset, int i) {
|
||||
memory.writeOrderedInt(address + translate(offset), i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> writeLong(long offset, long i64) {
|
||||
memory.writeLong(address + translate(offset), i64);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> writeOrderedLong(long offset, long i) {
|
||||
memory.writeOrderedLong(address + translate(offset), i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> writeFloat(long offset, float f) {
|
||||
memory.writeFloat(address + translate(offset), f);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> writeDouble(long offset, double d) {
|
||||
memory.writeDouble(address + translate(offset), d);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> writeVolatileByte(long offset, byte i8) {
|
||||
memory.writeVolatileByte(address + translate(offset), i8);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> writeVolatileShort(long offset, short i16) {
|
||||
memory.writeVolatileShort(address + translate(offset), i16);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> writeVolatileInt(long offset, int i32) {
|
||||
memory.writeVolatileInt(address + translate(offset), i32);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> writeVolatileLong(long offset, long i64) {
|
||||
memory.writeVolatileLong(address + translate(offset), i64);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> write(
|
||||
long offsetInRDO, byte[] bytes, int offset, int length) {
|
||||
memory.copyMemory(bytes, offset, address + translate(offsetInRDO), length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public void write(
|
||||
long offsetInRDO, ByteBuffer bytes, int offset, int length) {
|
||||
if (bytes.isDirect()) {
|
||||
memoryCopyMemory(Jvm.address(bytes) + offset, address + translate(offsetInRDO), length);
|
||||
|
||||
} else {
|
||||
memory.copyMemory(bytes.array(), offset, address + translate(offsetInRDO), length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public NativeBytesStore<Underlying> write(
|
||||
long writeOffset, RandomDataInput bytes, long readOffset, long length)
|
||||
throws BufferOverflowException, BufferUnderflowException {
|
||||
if (bytes.isDirectMemory()) {
|
||||
memoryCopyMemory(bytes.addressForRead(readOffset), addressForWrite(writeOffset), length);
|
||||
} else {
|
||||
write0(writeOffset, bytes, readOffset, length);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void write0(long offsetInRDO, RandomDataInput bytes, long offset, long length) throws BufferUnderflowException {
|
||||
long i = 0;
|
||||
for (; i < length - 7; i += 8) {
|
||||
writeLong(offsetInRDO + i, bytes.readLong(offset + i));
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
writeByte(offsetInRDO + i, bytes.readByte(offset + i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForRead(long offset) throws BufferUnderflowException {
|
||||
if (offset < start() || offset > realCapacity())
|
||||
throw new BufferUnderflowException();
|
||||
return address + translate(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForWrite(long offset) throws BufferOverflowException {
|
||||
if (offset < start() || offset > realCapacity())
|
||||
throw new BufferOverflowException();
|
||||
return address + translate(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForWritePosition() throws UnsupportedOperationException, BufferOverflowException {
|
||||
return addressForWrite(start());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performRelease() {
|
||||
memory = null;
|
||||
if (cleaner != null) {
|
||||
cleaner.clean();
|
||||
|
||||
} else if (underlyingObject instanceof ByteBuffer) {
|
||||
ByteBuffer underlyingObject = (ByteBuffer) this.underlyingObject;
|
||||
if (underlyingObject.isDirect())
|
||||
CLEANER_SERVICE.clean(underlyingObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return BytesInternal.toString(this);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
return e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public void nativeRead(long position, long address, long size) throws BufferUnderflowException {
|
||||
// TODO add bounds checking.
|
||||
memoryCopyMemory(addressForRead(position), address, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public void nativeWrite(long address, long position, long size) throws BufferOverflowException {
|
||||
// TODO add bounds checking.
|
||||
memoryCopyMemory(address, addressForWrite(position), size);
|
||||
}
|
||||
|
||||
void write8bit(long position, char[] chars, int offset, int length) {
|
||||
long addr = address + translate(position);
|
||||
Memory memory = this.memory;
|
||||
for (int i = 0; i < length; i++)
|
||||
memory.writeByte(addr + i, (byte) chars[offset + i]);
|
||||
}
|
||||
|
||||
void read8bit(long position, char[] chars, int length) {
|
||||
long addr = address + translate(position);
|
||||
Memory memory = this.memory;
|
||||
for (int i = 0; i < length; i++)
|
||||
chars[i] = (char) (memory.readByte(addr + i) & 0xFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readIncompleteLong(long offset) {
|
||||
int remaining = (int) Math.min(8, readRemaining() - offset);
|
||||
long l = 0;
|
||||
for (int i = 0; i < remaining; i++) {
|
||||
byte b = memory.readByte(address + offset + i);
|
||||
l |= (long) (b & 0xFF) << (i * 8);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof BytesStore && BytesInternal.contentEqual(this, (BytesStore) obj);
|
||||
}
|
||||
|
||||
public void setAddress(long address) {
|
||||
if ((address & ~0x3FFF) == 0)
|
||||
throw new AssertionError("Invalid addressForRead " + Long.toHexString(address));
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
public long appendUTF(long pos, char[] chars, int offset, int length) throws BufferOverflowException {
|
||||
return appendUtf8(pos, chars, offset, length);
|
||||
}
|
||||
|
||||
public long appendUtf8(long pos, char[] chars, int offset, int length) throws BufferOverflowException {
|
||||
if (pos + length > realCapacity())
|
||||
throw new BufferOverflowException();
|
||||
|
||||
long address = this.address + translate(0);
|
||||
Memory memory = this.memory;
|
||||
if (memory == null) throw new NullPointerException();
|
||||
int i;
|
||||
ascii:
|
||||
{
|
||||
for (i = 0; i < length - 3; i += 4) {
|
||||
final int i2 = offset + i;
|
||||
char c0 = chars[i2];
|
||||
char c1 = chars[i2 + 1];
|
||||
char c2 = chars[i2 + 2];
|
||||
char c3 = chars[i2 + 3];
|
||||
if ((c0 | c1 | c2 | c3) > 0x007F)
|
||||
break ascii;
|
||||
final int value = (c0) | (c1 << 8) | (c2 << 16) | (c3 << 24);
|
||||
UnsafeMemory.unsafePutInt(address + pos, value);
|
||||
pos += 4;
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
char c = chars[offset + i];
|
||||
if (c > 0x007F)
|
||||
break ascii;
|
||||
UnsafeMemory.unsafePutByte(address + pos++, (byte) c);
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
return appendUtf8a(pos, chars, offset, length, i);
|
||||
}
|
||||
|
||||
private long appendUtf8a(long pos, char[] chars, int offset, int length, int i) {
|
||||
for (; i < length; i++) {
|
||||
char c = chars[offset + i];
|
||||
if (c <= 0x007F) {
|
||||
writeByte(pos++, (byte) c);
|
||||
|
||||
} else if (c <= 0x07FF) {
|
||||
writeByte(pos++, (byte) (0xC0 | ((c >> 6) & 0x1F)));
|
||||
writeByte(pos++, (byte) (0x80 | c & 0x3F));
|
||||
|
||||
} else {
|
||||
writeByte(pos++, (byte) (0xE0 | ((c >> 12) & 0x0F)));
|
||||
writeByte(pos++, (byte) (0x80 | ((c >> 6) & 0x3F)));
|
||||
writeByte(pos++, (byte) (0x80 | (c & 0x3F)));
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long copyTo( BytesStore store) {
|
||||
if (store.isDirectMemory())
|
||||
return copyToDirect(store);
|
||||
else
|
||||
return super.copyTo(store);
|
||||
}
|
||||
|
||||
public long copyToDirect( BytesStore store) {
|
||||
long toCopy = Math.min(limit, store.safeLimit());
|
||||
if (toCopy > 0) {
|
||||
try {
|
||||
long addr = address;
|
||||
long addr2 = store.addressForWrite(0);
|
||||
memoryCopyMemory(addr, addr2, toCopy);
|
||||
} catch (BufferOverflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
return toCopy;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ByteBuffer toTemporaryDirectByteBuffer() {
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(0);
|
||||
try {
|
||||
BB_ADDRESS.setLong(bb, address);
|
||||
BB_CAPACITY.setInt(bb, Maths.toUInt31(readRemaining()));
|
||||
BB_ATT.set(bb, this);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
bb.clear();
|
||||
return bb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int byteCheckSum() throws IORuntimeException {
|
||||
return byteCheckSum(start(), readLimit());
|
||||
}
|
||||
|
||||
public int byteCheckSum(long position, long limit) {
|
||||
Memory memory = this.memory;
|
||||
assert memory != null;
|
||||
int b = 0;
|
||||
long ptr = address + position;
|
||||
long end = address + limit;
|
||||
for (; ptr < end - 7; ptr += 8) {
|
||||
b += memory.readByte(ptr)
|
||||
+ memory.readByte(ptr + 1)
|
||||
+ memory.readByte(ptr + 2)
|
||||
+ memory.readByte(ptr + 3)
|
||||
+ memory.readByte(ptr + 4)
|
||||
+ memory.readByte(ptr + 5)
|
||||
+ memory.readByte(ptr + 6)
|
||||
+ memory.readByte(ptr + 7);
|
||||
}
|
||||
for (; ptr < end; ptr++) {
|
||||
b += memory.readByte(ptr);
|
||||
}
|
||||
return b & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sharedMemory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read(long offsetInRDI, byte[] bytes, int offset, int length) {
|
||||
int len = (int) Math.min(length, readLimit() - offsetInRDI);
|
||||
int i;
|
||||
final long address = this.address + translate(offsetInRDI);
|
||||
for (i = 0; i < len - 7; i += 8)
|
||||
UnsafeMemory.unsafePutLong(bytes, i, memory.readLong(address + i));
|
||||
if (i < len - 3) {
|
||||
UnsafeMemory.unsafePutInt(bytes, i, memory.readInt(address + i));
|
||||
i += 4;
|
||||
}
|
||||
for (; i < len; i++)
|
||||
UnsafeMemory.unsafePutByte(bytes, i, memory.readByte(address + i));
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int peekUnsignedByte(long offset) {
|
||||
final long address = this.address;
|
||||
final Memory memory = this.memory;
|
||||
final long translate = translate(offset);
|
||||
// assert translate >= 0;
|
||||
final long address2 = address + translate;
|
||||
// last.writeLong(8, Thread.currentThread().getId());
|
||||
// last.writeLong(0, offset);
|
||||
// last.writeLong(16, translate);
|
||||
// last.writeLong(32, maximumLimit);
|
||||
// last.writeLong(48, addressForRead);
|
||||
// last.writeLong(64, address2);
|
||||
// last.writeBoolean(80, memory != null);
|
||||
// last.writeVolatileByte(88, (byte) 1);
|
||||
int ret = translate >= limit ? -1 :
|
||||
memory.readByte(address2) & 0xFF;
|
||||
// last.writeVolatileByte(88, (byte) 0xFF);
|
||||
// last.writeLong(24, Thread.currentThread().getId());
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fastHash(long offset, int length) throws BufferUnderflowException {
|
||||
long ret;
|
||||
switch (length) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
ret = readByte(offset);
|
||||
break;
|
||||
case 2:
|
||||
ret = readShort(offset);
|
||||
break;
|
||||
case 4:
|
||||
ret = readInt(offset);
|
||||
break;
|
||||
case 8:
|
||||
ret = readInt(offset) * 0x6d0f27bdL + readInt(offset + 4);
|
||||
break;
|
||||
default:
|
||||
return super.fastHash(offset, length);
|
||||
}
|
||||
long hash = ret * 0x855dd4db;
|
||||
return (int) (hash ^ (hash >> 32));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long safeLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
static class Deallocator implements Runnable {
|
||||
|
||||
private volatile long address;
|
||||
private final long size;
|
||||
|
||||
Deallocator(long address, long size) {
|
||||
assert address != 0;
|
||||
this.address = address;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// System.out.println("Release " + Long.toHexString(addressForRead));
|
||||
if (address == 0)
|
||||
return;
|
||||
long addressToFree = address;
|
||||
address = 0;
|
||||
OS.memory().freeMemory(addressToFree, size);
|
||||
}
|
||||
}
|
||||
|
||||
private class Finalizer {
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
warnAndReleaseIfNotReleased();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface NewChunkListener {
|
||||
void onNewChunk(String filename, int chunk, long delayMicros);
|
||||
}
|
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.OS;
|
||||
import net.openhft.chronicle.core.io.IOTools;
|
||||
import net.openhft.chronicle.core.io.ReferenceOwner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* This is a ByteStore which uses no space but could be resized to be larger (by replacing it with a ByteStire with space)
|
||||
*
|
||||
* @see ReleasedBytesStore
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public enum NoBytesStore implements BytesStore {
|
||||
NO_BYTES_STORE;
|
||||
|
||||
public static final long NO_PAGE;
|
||||
|
||||
|
||||
public static final Bytes NO_BYTES;
|
||||
|
||||
static {
|
||||
try {
|
||||
NO_PAGE = OS.memory().allocate(OS.pageSize());
|
||||
NO_BYTES = new VanillaBytes(noBytesStore());
|
||||
IOTools.unmonitor(NO_BYTES);
|
||||
|
||||
} catch ( IllegalArgumentException | IllegalStateException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static <T, B extends BytesStore<B, T>> BytesStore<B, T> noBytesStore() {
|
||||
return NO_BYTES_STORE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reserve(ReferenceOwner owner) throws IllegalStateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(ReferenceOwner owner) throws IllegalStateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseLast(ReferenceOwner id) throws IllegalStateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int refCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryReserve(ReferenceOwner owner) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reservedBy(ReferenceOwner owner) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeByte(long offset, byte i8) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeShort(long offset, short i) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeInt(long offset, int i) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeOrderedInt(long offset, int i) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeLong(long offset, long i) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeOrderedLong(long offset, long i) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeFloat(long offset, float d) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeDouble(long offset, double d) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeVolatileByte(long offset, byte i8) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeVolatileShort(long offset, short i16) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeVolatileInt(long offset, int i32) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeVolatileLong(long offset, long i64) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput write(long offsetInRDO, byte[] bytes, int offset, int length) {
|
||||
if (length != 0)
|
||||
throw new UnsupportedOperationException();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(long offsetInRDO, ByteBuffer bytes, int offset, int length) {
|
||||
if (length != 0)
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput write(long writeOffset, RandomDataInput bytes, long readOffset, long length) {
|
||||
if (length != 0)
|
||||
throw new UnsupportedOperationException();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readByte(long offset) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int peekUnsignedByte(long offset) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readShort(long offset) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readInt(long offset) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLong(long offset) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float readFloat(long offset) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readDouble(long offset) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readVolatileByte(long offset) throws BufferUnderflowException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readVolatileShort(long offset) throws BufferUnderflowException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readVolatileInt(long offset) throws BufferUnderflowException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readVolatileLong(long offset) throws BufferUnderflowException {
|
||||
throw new BufferUnderflowException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectMemory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BytesStore copy() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long capacity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void underlyingObject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inside(long offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inside(long offset, long buffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long copyTo( BytesStore store) {
|
||||
// nothing to copy.
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nativeWrite(long address, long position, long size) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nativeRead(long position, long address, long size) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compareAndSwapInt(long offset, int expected, int value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testAndSetInt(long offset, int expected, int value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compareAndSwapLong(long offset, long expected, long value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equalBytes( BytesStore bytesStore, long length) {
|
||||
return length == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(long from, long to, long length) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForRead(long offset) throws BufferUnderflowException {
|
||||
if (offset != 0)
|
||||
throw new BufferUnderflowException();
|
||||
return NO_PAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForWrite(long offset) throws BufferOverflowException {
|
||||
if (offset != 0)
|
||||
throw new BufferOverflowException();
|
||||
return NO_PAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForWritePosition() throws UnsupportedOperationException, BufferOverflowException {
|
||||
return NO_PAGE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes bytesForWrite() {
|
||||
throw new UnsupportedOperationException("todo");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sharedMemory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface OffsetFormat {
|
||||
@SuppressWarnings("rawtypes")
|
||||
void append(long offset, Bytes bytes);
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.bytes.util.DecoratedBufferOverflowException;
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
|
||||
public class OnHeapBytes extends VanillaBytes<byte[]> {
|
||||
public static final int MAX_CAPACITY = Bytes.MAX_HEAP_CAPACITY;
|
||||
private final boolean elastic;
|
||||
private final long capacity;
|
||||
|
||||
public OnHeapBytes( BytesStore bytesStore, boolean elastic) throws IllegalStateException {
|
||||
super(bytesStore);
|
||||
this.elastic = elastic;
|
||||
this.capacity = elastic ? MAX_CAPACITY : bytesStore.capacity();
|
||||
|
||||
writePosition(0);
|
||||
writeLimit(capacity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long capacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isElastic() {
|
||||
return elastic;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeCheckOffset(long offset, long adding)
|
||||
throws BufferOverflowException {
|
||||
if (offset >= bytesStore.start()) {
|
||||
long writeEnd = offset + adding;
|
||||
if (writeEnd > writeLimit)
|
||||
throwBeyondWriteLimit(adding, writeEnd);
|
||||
if (writeEnd <= bytesStore.safeLimit()) {
|
||||
return; // do nothing.
|
||||
}
|
||||
checkResize(writeEnd);
|
||||
} else {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
}
|
||||
|
||||
private void throwBeyondWriteLimit(long advance, long writeEnd) {
|
||||
throw new DecoratedBufferOverflowException("attempt to write " + advance + " bytes to " + writeEnd + " limit: " + writeLimit);
|
||||
}
|
||||
|
||||
private void checkResize(long endOfBuffer)
|
||||
throws BufferOverflowException {
|
||||
if (isElastic())
|
||||
resize(endOfBuffer);
|
||||
else
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
|
||||
// the endOfBuffer is the minimum capacity and one byte more than the last addressable byte.
|
||||
private void resize(long endOfBuffer)
|
||||
throws BufferOverflowException {
|
||||
if (endOfBuffer < 0)
|
||||
throw new BufferOverflowException();
|
||||
if (endOfBuffer > capacity())
|
||||
throw new BufferOverflowException();
|
||||
final long realCapacity = realCapacity();
|
||||
if (endOfBuffer <= realCapacity) {
|
||||
// System.out.println("no resize " + endOfBuffer + " < " + realCapacity);
|
||||
return;
|
||||
}
|
||||
|
||||
// Grow by 50%
|
||||
long size0 = Math.max(endOfBuffer, realCapacity * 3 / 2);
|
||||
// Size must not be more than capacity(), it may break some assumptions in BytesStore or elsewhere
|
||||
int size = (int) Math.min(size0, capacity());
|
||||
|
||||
// System.out.println("resize " + endOfBuffer + " to " + size);
|
||||
if (endOfBuffer > 1 << 20)
|
||||
Jvm.warn().on(getClass(), "Resizing buffer was " + realCapacity / 1024 + " KB, " +
|
||||
"needs " + (endOfBuffer - realCapacity) + " bytes more, " +
|
||||
"new-size " + size / 1024 + " KB");
|
||||
HeapBytesStore store;
|
||||
try {
|
||||
store = HeapBytesStore.wrap(new byte[size]);
|
||||
store.reserveTransfer(INIT, this);
|
||||
} catch (IllegalArgumentException e) {
|
||||
BufferOverflowException boe = new BufferOverflowException();
|
||||
boe.initCause(e);
|
||||
throw boe;
|
||||
}
|
||||
|
||||
BytesStore<Bytes<byte[]>, byte[]> tempStore = this.bytesStore;
|
||||
this.bytesStore.copyTo(store);
|
||||
this.bytesStore(store);
|
||||
try {
|
||||
tempStore.release(this);
|
||||
} catch (IllegalStateException e) {
|
||||
Jvm.debug().on(getClass(), e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A BytesStore which can point to arbitrary memory.
|
||||
*/
|
||||
public class PointerBytesStore extends NativeBytesStore<Void> {
|
||||
private boolean isPresent = false;
|
||||
|
||||
public PointerBytesStore() {
|
||||
super(NoBytesStore.NO_PAGE, 0, null, false, false);
|
||||
}
|
||||
|
||||
public void set(long address, long capacity) {
|
||||
isPresent = true;
|
||||
setAddress(address);
|
||||
this.limit = maximumLimit = capacity;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public VanillaBytes<Void> bytesForWrite() throws IllegalStateException {
|
||||
return new VanillaBytes<>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long safeLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long start() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.annotation.ForceInline;
|
||||
import net.openhft.chronicle.core.io.ReferenceCounted;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
interface RandomCommon extends ReferenceCounted {
|
||||
/**
|
||||
* @return The smallest position allowed in this buffer.
|
||||
*/
|
||||
@ForceInline
|
||||
default long start() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the highest limit allowed for this buffer.
|
||||
*/
|
||||
@ForceInline
|
||||
default long capacity() {
|
||||
return Bytes.MAX_CAPACITY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the limit for this buffer without resizing
|
||||
*/
|
||||
default long realCapacity() {
|
||||
return capacity();
|
||||
}
|
||||
|
||||
/**
|
||||
* The read position must be start() <= readPosition() && readPosition() <= readLimit() && readPosition < safeLimit()
|
||||
*
|
||||
* @return position to read from.
|
||||
*/
|
||||
@ForceInline
|
||||
default long readPosition() {
|
||||
return start();
|
||||
}
|
||||
|
||||
/**
|
||||
* The read position must be readPosition() <= writePosition() && writePosition() <= writeLimit()
|
||||
*
|
||||
* @return position to write to.
|
||||
*/
|
||||
@ForceInline
|
||||
default long writePosition() {
|
||||
return start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return How many more bytes can we read.
|
||||
*/
|
||||
@ForceInline
|
||||
default long readRemaining() {
|
||||
long remaining = readLimit() - readPosition();
|
||||
return remaining;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return How many more bytes can we written.
|
||||
*/
|
||||
@ForceInline
|
||||
default long writeRemaining() {
|
||||
return writeLimit() - writePosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the highest offset or position allowed for this buffer.
|
||||
*/
|
||||
@ForceInline
|
||||
default long readLimit() {
|
||||
return realCapacity();
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
default long writeLimit() {
|
||||
return realCapacity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the underlying addressForRead. This is for expert users only.
|
||||
*
|
||||
* @param offset within this buffer. addressForRead(start()) is the actual addressForRead of the first byte.
|
||||
* @return the underlying addressForRead of the buffer
|
||||
* @throws UnsupportedOperationException if the underlying buffer is on the heap
|
||||
* @throws BufferUnderflowException if the offset is before the start() or the after the capacity()
|
||||
*/
|
||||
long addressForRead(long offset)
|
||||
throws UnsupportedOperationException, BufferUnderflowException;
|
||||
|
||||
default long addressForRead(long offset, int buffer)
|
||||
throws UnsupportedOperationException, BufferUnderflowException {
|
||||
return addressForRead(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the underlying addressForRead. This is for expert users only.
|
||||
*
|
||||
* @param offset within this buffer. addressForRead(start()) is the actual addressForRead of the first byte.
|
||||
* @return the underlying addressForRead of the buffer
|
||||
* @throws UnsupportedOperationException if the underlying buffer is on the heap
|
||||
* @throws BufferOverflowException if the offset is before the start() or the after the capacity()
|
||||
*/
|
||||
long addressForWrite(long offset)
|
||||
throws UnsupportedOperationException, BufferOverflowException;
|
||||
|
||||
long addressForWritePosition()
|
||||
throws UnsupportedOperationException, BufferOverflowException;
|
||||
|
||||
default ByteOrder byteOrder() {
|
||||
return ByteOrder.nativeOrder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the streaming bytes for reading.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
|
||||
Bytes bytesForRead() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* @return the streaming bytes for writing.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
|
||||
Bytes bytesForWrite() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Perform a 32-bit CAS at a given offset.
|
||||
*
|
||||
* @param offset to perform CAS
|
||||
* @param expected value
|
||||
* @param value to set
|
||||
* @return true, if successful.
|
||||
*/
|
||||
boolean compareAndSwapInt(long offset, int expected, int value)
|
||||
throws BufferOverflowException;
|
||||
|
||||
void testAndSetInt(long offset, int expected, int value);
|
||||
|
||||
/**
|
||||
* Perform a 64-bit CAS at a given offset.
|
||||
*
|
||||
* @param offset to perform CAS
|
||||
* @param expected value
|
||||
* @param value to set
|
||||
* @return true, if successful.
|
||||
*/
|
||||
boolean compareAndSwapLong(long offset, long expected, long value)
|
||||
throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Perform a 32-bit float CAS at a given offset.
|
||||
*
|
||||
* @param offset to perform CAS
|
||||
* @param expected value
|
||||
* @param value to set
|
||||
* @return true, if successful.
|
||||
*/
|
||||
default boolean compareAndSwapFloat(long offset, float expected, float value)
|
||||
throws BufferOverflowException {
|
||||
return compareAndSwapInt(offset, Float.floatToRawIntBits(expected), Float.floatToRawIntBits(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a 64-bit double CAS at a given offset.
|
||||
*
|
||||
* @param offset to perform CAS
|
||||
* @param expected value
|
||||
* @param value to set
|
||||
* @return true, if successful.
|
||||
*/
|
||||
default boolean compareAndSwapDouble(long offset, double expected, double value)
|
||||
throws BufferOverflowException {
|
||||
return compareAndSwapLong(offset, Double.doubleToRawLongBits(expected), Double.doubleToRawLongBits(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if these Bytes use shared memory.
|
||||
*/
|
||||
boolean sharedMemory();
|
||||
|
||||
boolean isDirectMemory();
|
||||
}
|
|
@ -0,0 +1,578 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import net.openhft.chronicle.core.annotation.ForceInline;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* This allows random access to the underling bytes. This instance can be used across threads as it is stateless.
|
||||
* The thread safety of the underlying data depends on how the methods are used.
|
||||
*/
|
||||
public interface RandomDataInput extends RandomCommon {
|
||||
String[] charToString = createCharToString();
|
||||
|
||||
|
||||
static String[] createCharToString() {
|
||||
String[] charToString = new String[256];
|
||||
charToString[0] = "\u0660";
|
||||
for (int i = 1; i < 21; i++)
|
||||
charToString[i] = Character.toString((char) (i + 0x2487));
|
||||
for (int i = ' '; i < 256; i++)
|
||||
charToString[i] = Character.toString((char) i);
|
||||
for (int i = 21; i < ' '; i++)
|
||||
charToString[i] = "\\u00" + Integer.toHexString(i).toUpperCase();
|
||||
for (int i = 0x80; i < 0xA0; i++)
|
||||
charToString[i] = "\\u00" + Integer.toHexString(i).toUpperCase();
|
||||
return charToString;
|
||||
}
|
||||
|
||||
default int peekVolatileInt() throws BufferUnderflowException {
|
||||
return readVolatileInt(readPosition());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read boolean at an offset
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the boolean
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
@ForceInline
|
||||
default boolean readBoolean(long offset)
|
||||
throws BufferUnderflowException {
|
||||
return BytesUtil.byteToBoolean(readByte(offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read byte at an offset
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the byte
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
byte readByte(long offset) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Read an unsigned byte at an offset
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the unsigned byte
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
@ForceInline
|
||||
default int readUnsignedByte(long offset) throws BufferUnderflowException {
|
||||
return readByte(offset) & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an unsigned byte at an offset, or -1
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the unsigned byte or -1
|
||||
*/
|
||||
int peekUnsignedByte(long offset) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Read a short at an offset
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the short
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
short readShort(long offset) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Read an unsigned short at an offset
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the unsigned short
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
@ForceInline
|
||||
default int readUnsignedShort(long offset) throws BufferUnderflowException {
|
||||
return readShort(offset) & 0xFFFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an unsigned int at an offset
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the int
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
default int readUnsignedInt24(long offset) throws BufferUnderflowException {
|
||||
return readUnsignedShort(offset) | (readUnsignedByte(offset) << 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an int at an offset
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the int
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
int readInt(long offset) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Read an unsigned int at an offset
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the unsigned int
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
@ForceInline
|
||||
default long readUnsignedInt(long offset) throws BufferUnderflowException {
|
||||
return readInt(offset) & 0xFFFFFFFFL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a long at an offset
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the long
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
long readLong(long offset) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Read a float at an offset
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the float
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
float readFloat(long offset) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Read a double at an offset
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the double
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
double readDouble(long offset) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Read the byte at an offset and converts it into a printable
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the byte in a printable form.
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
default String printable(long offset) throws BufferUnderflowException {
|
||||
return charToString[readUnsignedByte(offset)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 8-bit byte from memory with a load barrier.
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the byte value
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
byte readVolatileByte(long offset) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Read a 16-bit short from memory with a load barrier.
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the short value
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
short readVolatileShort(long offset) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Read a 32-bit int from memory with a load barrier.
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the int value
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
int readVolatileInt(long offset) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Read a float from memory with a load barrier.
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the float value
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
default float readVolatileFloat(long offset) throws BufferUnderflowException {
|
||||
return Float.intBitsToFloat(readVolatileInt(offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 64-bit long from memory with a load barrier.
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the long value
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
long readVolatileLong(long offset) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Read a 64-bit double from memory with a load barrier.
|
||||
*
|
||||
* @param offset to read
|
||||
* @return the double value
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
default double readVolatileDouble(long offset) throws BufferUnderflowException {
|
||||
return Double.longBitsToDouble(readVolatileLong(offset));
|
||||
}
|
||||
|
||||
default long parseLong(long offset) throws BufferUnderflowException {
|
||||
return BytesInternal.parseLong(this, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* expert level method for copying data to native memory.
|
||||
*
|
||||
* @param position within the ByteStore to copy.
|
||||
* @param address in native memory
|
||||
* @param size in bytes
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
void nativeRead(long position, long address, long size) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Read a byte[] from memory.
|
||||
*
|
||||
* @return the length actually read.
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
default int copyTo( byte[] bytes) throws BufferUnderflowException {
|
||||
int len = (int) Math.min(bytes.length, readRemaining());
|
||||
for (int i = 0; i < len; i++)
|
||||
bytes[i] = readByte(start() + i);
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy data from this RandomDataInput to the ByteBuffer. The minimum of {@link #readRemaining()} and
|
||||
* {@link ByteBuffer#remaining()}. Starting from {@link #start()} in this RandomDataInput and from {@link
|
||||
* ByteBuffer#position()} of the given bb. Does NOT change the position or limit or mark of the given ByteBuffer.
|
||||
* Returns the number of the copied bytes.
|
||||
*/
|
||||
default int copyTo( ByteBuffer bb) throws BufferUnderflowException {
|
||||
int pos = bb.position();
|
||||
int len = (int) Math.min(bb.remaining(), readRemaining());
|
||||
int i;
|
||||
for (i = 0; i < len - 7; i += 8)
|
||||
bb.putLong(pos + i, readLong(start() + i));
|
||||
for (; i < len; i++)
|
||||
bb.put(pos + i, readByte(start() + i));
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a long which is zero padded (high bytes) if the available bytes is less than 8.
|
||||
* If the offset is at or beyond the readLimit, this will return 0L.
|
||||
*
|
||||
* @param offset to read from
|
||||
* @return the long which might be padded.
|
||||
*/
|
||||
default long readIncompleteLong(long offset) {
|
||||
long left = readLimit() - offset;
|
||||
long l;
|
||||
try {
|
||||
if (left >= 8)
|
||||
return readLong(offset);
|
||||
if (left == 4)
|
||||
return readInt(offset);
|
||||
l = 0;
|
||||
for (int i = 0, remaining = (int) left; i < remaining; i++) {
|
||||
l |= (long) readUnsignedByte(offset + i) << (i * 8);
|
||||
}
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual capacity that can be potentially read.
|
||||
*
|
||||
* @return the actual capacity that can be potentially read.
|
||||
*/
|
||||
long realCapacity();
|
||||
|
||||
/**
|
||||
* Perform an atomic add and get operation for a 32-bit int
|
||||
*
|
||||
* @param offset to add and get
|
||||
* @param adding value to add, can be 1
|
||||
* @return the sum
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
default int addAndGetInt(long offset, int adding)
|
||||
throws BufferUnderflowException {
|
||||
return BytesInternal.addAndGetInt(this, offset, adding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an atomic add and get operation for a 64-bit long
|
||||
*
|
||||
* @param offset to add and get
|
||||
* @param adding value to add, can be 1
|
||||
* @return the sum
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
default long addAndGetLong(long offset, long adding)
|
||||
throws BufferUnderflowException {
|
||||
return BytesInternal.addAndGetLong(this, offset, adding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an atomic add and get operation for a 32-bit float
|
||||
*
|
||||
* @param offset to add and get
|
||||
* @param adding value to add, can be 1
|
||||
* @return the sum
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
default float addAndGetFloat(long offset, float adding)
|
||||
throws BufferUnderflowException {
|
||||
return BytesInternal.addAndGetFloat(this, offset, adding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an atomic add and get operation for a 64-bit double
|
||||
*
|
||||
* @param offset to add and get
|
||||
* @param adding value to add, can be 1
|
||||
* @return the sum
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
default double addAndGetDouble(long offset, double adding)
|
||||
throws BufferUnderflowException {
|
||||
return BytesInternal.addAndGetDouble(this, offset, adding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a sub sequence of bytes as a BytesStore.
|
||||
*
|
||||
* @param start of bytes
|
||||
* @param length of bytes
|
||||
* @return ByteStore copy.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
|
||||
default BytesStore subBytes(long start, long length) throws BufferUnderflowException {
|
||||
return BytesInternal.subBytes(this, start, length);
|
||||
}
|
||||
|
||||
default long findByte(byte stopByte) {
|
||||
return BytesInternal.findByte(this, stopByte);
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates {@code sb} (it must be a {@link StringBuilder} or {@link Bytes}) and reads a char
|
||||
* sequence from the given {@code offset}, encoded as Utf8, into it. Returns offset <i>after</i>
|
||||
* the read Utf8, if a normal char sequence was read, or {@code -1 - offset}, if {@code null}
|
||||
* was observed (in this case, {@code sb} is truncated too, but not updated then, by querying
|
||||
* {@code sb} only this case is indistinguishable from reading an empty char sequence).
|
||||
*
|
||||
* @param offset the offset in this {@code RandomDataInput} to read char sequence from
|
||||
* @param sb the buffer to read char sequence into (truncated first)
|
||||
* @param <ACS> buffer type, must be {@code StringBuilder} or {@code Bytes}
|
||||
* @return offset after the normal read char sequence, or -1 - offset, if char sequence is
|
||||
* {@code null}
|
||||
* @see RandomDataOutput#writeUtf8(long, CharSequence)
|
||||
*/
|
||||
default <ACS extends Appendable & CharSequence> long readUtf8(long offset, ACS sb)
|
||||
throws IORuntimeException, IllegalArgumentException, BufferUnderflowException {
|
||||
AppendableUtil.setLength(sb, 0);
|
||||
// TODO insert some bounds check here
|
||||
|
||||
long utfLen;
|
||||
if ((utfLen = readByte(offset++)) < 0) {
|
||||
utfLen &= 0x7FL;
|
||||
long b;
|
||||
int count = 7;
|
||||
while ((b = readByte(offset++)) < 0) {
|
||||
utfLen |= (b & 0x7FL) << count;
|
||||
count += 7;
|
||||
}
|
||||
if (b != 0) {
|
||||
if (count > 56)
|
||||
throw new IORuntimeException(
|
||||
"Cannot read more than 9 stop bits of positive value");
|
||||
utfLen |= (b << count);
|
||||
} else {
|
||||
if (count > 63)
|
||||
throw new IORuntimeException(
|
||||
"Cannot read more than 10 stop bits of negative value");
|
||||
utfLen = ~utfLen;
|
||||
}
|
||||
}
|
||||
if (utfLen == -1)
|
||||
return ~offset;
|
||||
int len = Maths.toUInt31(utfLen);
|
||||
BytesInternal.parseUtf8(this, offset, sb, true, len);
|
||||
return offset + utfLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates {@code sb} (it must be a {@link StringBuilder} or {@link Bytes}) and reads a char
|
||||
* sequence from the given {@code offset}, encoded as Utf8, into it. Returns offset <i>after</i>
|
||||
* the read Utf8, if a normal char sequence was read, or {@code -1 - offset}, if {@code null}
|
||||
* was observed (in this case, {@code sb} is truncated too, but not updated then, by querying
|
||||
* {@code sb} only this case is indistinguishable from reading an empty char sequence). If
|
||||
* length of Utf8 encoding of the char sequence exceeds {@code maxUtf8Len},
|
||||
* {@code IllegalStateException} is thrown.
|
||||
*
|
||||
* @param offset the offset in this {@code RandomDataInput} to read char sequence from
|
||||
* @param sb the buffer to read char sequence into (truncated first)
|
||||
* @param maxUtf8Len the maximum allowed length of the char sequence in Utf8 encoding
|
||||
* @param <ACS> buffer type, must be {@code StringBuilder} or {@code Bytes}
|
||||
* @return offset after the normal read char sequence, or -1 - offset, if char sequence is
|
||||
* {@code null}
|
||||
* @see RandomDataOutput#writeUtf8Limited(long, CharSequence, int)
|
||||
*/
|
||||
default <ACS extends Appendable & CharSequence> long readUtf8Limited(
|
||||
long offset, ACS sb, int maxUtf8Len)
|
||||
throws IORuntimeException, IllegalArgumentException, BufferUnderflowException,
|
||||
IllegalStateException {
|
||||
AppendableUtil.setLength(sb, 0);
|
||||
// TODO insert some bounds check here
|
||||
|
||||
long utfLen;
|
||||
if ((utfLen = readByte(offset++)) < 0) {
|
||||
utfLen &= 0x7FL;
|
||||
long b;
|
||||
int count = 7;
|
||||
while ((b = readByte(offset++)) < 0) {
|
||||
utfLen |= (b & 0x7FL) << count;
|
||||
count += 7;
|
||||
}
|
||||
if (b != 0) {
|
||||
if (count > 56)
|
||||
throw new IORuntimeException(
|
||||
"Cannot read more than 9 stop bits of positive value");
|
||||
utfLen |= (b << count);
|
||||
} else {
|
||||
if (count > 63)
|
||||
throw new IORuntimeException(
|
||||
"Cannot read more than 10 stop bits of negative value");
|
||||
utfLen = ~utfLen;
|
||||
}
|
||||
}
|
||||
if (utfLen == -1)
|
||||
return ~offset;
|
||||
if (utfLen > maxUtf8Len)
|
||||
throw new IllegalStateException("Attempted to read a char sequence of " +
|
||||
"utf8 size " + utfLen + ", when only " + maxUtf8Len + " allowed");
|
||||
BytesInternal.parseUtf8(this, offset, sb, true, (int) utfLen);
|
||||
return offset + utfLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a char sequence from the given {@code offset}, encoded as Utf8. If length of Utf8
|
||||
* encoding of the char sequence exceeds {@code maxUtf8Len}, {@code IllegalStateException}
|
||||
* is thrown.
|
||||
*
|
||||
* @param offset the offset in this {@code RandomDataInput} to read char sequence from
|
||||
* @param maxUtf8Len the maximum allowed length of the char sequence in Utf8 encoding
|
||||
* @return the char sequence was read
|
||||
* @see RandomDataOutput#writeUtf8Limited(long, CharSequence, int)
|
||||
*/
|
||||
|
||||
default String readUtf8Limited(long offset, int maxUtf8Len)
|
||||
throws BufferUnderflowException, IORuntimeException, IllegalArgumentException,
|
||||
IllegalStateException {
|
||||
return BytesInternal.readUtf8(this, offset, maxUtf8Len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the UTF-8 encoded char sequence, written in this {@code RandomDataInput} at the
|
||||
* given offset, with the given char sequence. Returns {@code true}, if they are equal. Both
|
||||
* char sequences (encoded in bytes and the given) may be {@code null}.
|
||||
*
|
||||
* @param offset the offset in this {@code RandomDataInput} where the char sequence to compare
|
||||
* is written
|
||||
* @param other the second char sequence to compare
|
||||
* @return {@code true} if two char sequences are equal
|
||||
* @throws IORuntimeException if the contents are not a valid string.
|
||||
*/
|
||||
default boolean compareUtf8(long offset, CharSequence other) throws IORuntimeException {
|
||||
return BytesInternal.compareUtf8(this, offset, other);
|
||||
}
|
||||
|
||||
|
||||
default byte[] toByteArray() throws IllegalArgumentException {
|
||||
return BytesInternal.toByteArray(this);
|
||||
}
|
||||
|
||||
default long read(long offsetInRDI, byte[] bytes, int offset, int length) {
|
||||
try {
|
||||
int len = (int) Math.min(length, readLimit() - offsetInRDI);
|
||||
for (int i = 0; i < len; i++)
|
||||
bytes[offset + i] = readByte(offsetInRDI + i);
|
||||
return len;
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
default ByteBuffer toTemporaryDirectByteBuffer() throws IllegalArgumentException {
|
||||
int len = Maths.toUInt31(readRemaining());
|
||||
try {
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(len);
|
||||
copyTo(bb);
|
||||
bb.clear();
|
||||
return bb;
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
default int fastHash(long offset, int length) throws BufferUnderflowException {
|
||||
long hash = 0;
|
||||
int i = 0;
|
||||
if (length >= 4) {
|
||||
hash = readInt(offset + i);
|
||||
i += 4;
|
||||
}
|
||||
for (; i < length - 3; i += 4) {
|
||||
hash *= 0x6d0f27bd;
|
||||
hash += readInt(offset + i);
|
||||
}
|
||||
if (i < length - 1) {
|
||||
hash *= 0x6d0f27bdL;
|
||||
hash += readShort(offset + i);
|
||||
i += 2;
|
||||
}
|
||||
if (i < length)
|
||||
hash += readByte(offset + i);
|
||||
hash *= 0x855dd4db;
|
||||
return (int) (hash ^ (hash >> 32));
|
||||
}
|
||||
|
||||
default boolean canReadDirect(long length) {
|
||||
return isDirectMemory() && readRemaining() >= length;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,351 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public interface RandomDataOutput<R extends RandomDataOutput<R>> extends RandomCommon {
|
||||
/**
|
||||
* Write a byte at an offset.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param i the value
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
* @throws IllegalArgumentException if the value cannot be cast to the type without loss.
|
||||
*/
|
||||
|
||||
default R writeByte(long offset, int i)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
return writeByte(offset, Maths.toInt8(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an unsigned byte at an offset.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param i the value
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
* @throws IllegalArgumentException if the value cannot be cast to the type without loss.
|
||||
*/
|
||||
|
||||
default R writeUnsignedByte(long offset, int i)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
return writeByte(offset, (byte) Maths.toUInt8(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a boolean at an offset.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param flag the value
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
*/
|
||||
|
||||
default R writeBoolean(long offset, boolean flag)
|
||||
throws BufferOverflowException {
|
||||
try {
|
||||
return writeByte(offset, flag ? 'Y' : 'N');
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an unsigned byte at an offset.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param i the value
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
* @throws IllegalArgumentException if the value cannot be cast to the type without loss.
|
||||
*/
|
||||
|
||||
default R writeUnsignedShort(long offset, int i)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
return writeShort(offset, (short) Maths.toUInt16(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an unsigned byte at an offset.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param i the value
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
* @throws IllegalArgumentException if the value cannot be cast to the type without loss.
|
||||
*/
|
||||
|
||||
default R writeUnsignedInt(long offset, long i)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
return writeInt(offset, (int) Maths.toUInt32(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an unsigned byte at an offset.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param i8 the value
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
*/
|
||||
|
||||
R writeByte(long offset, byte i8) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Write a short at an offset.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param i the value
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
*/
|
||||
|
||||
R writeShort(long offset, short i) throws BufferOverflowException;
|
||||
|
||||
|
||||
default R writeInt24(long offset, int i) throws BufferOverflowException {
|
||||
writeShort(offset, (short) i);
|
||||
return writeByte(offset + 2, (byte) (i >> 16));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an int at an offset.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param i the value
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
*/
|
||||
|
||||
R writeInt(long offset, int i) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Perform a non stalling write with a store barrier.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param i value to write
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
*/
|
||||
|
||||
R writeOrderedInt(long offset, int i) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Perform a non stalling write with a store barrier.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param f value to write
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
*/
|
||||
|
||||
default R writeOrderedFloat(long offset, float f) throws BufferOverflowException {
|
||||
return writeOrderedInt(offset, Float.floatToRawIntBits(f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a long at an offset.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param i the value
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
*/
|
||||
|
||||
R writeLong(long offset, long i) throws BufferOverflowException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Perform a non stalling write with a store barrier.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param i value to write
|
||||
* @return this
|
||||
*/
|
||||
|
||||
R writeOrderedLong(long offset, long i) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Perform a non stalling write with a store barrier.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param d value to write
|
||||
* @return this
|
||||
*/
|
||||
|
||||
default R writeOrderedDouble(long offset, double d) throws BufferOverflowException {
|
||||
return writeOrderedLong(offset, Double.doubleToRawLongBits(d));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a float at an offset.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param d the value
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
*/
|
||||
|
||||
R writeFloat(long offset, float d) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Write a double at an offset.
|
||||
*
|
||||
* @param offset to write to
|
||||
* @param d the value
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
*/
|
||||
|
||||
R writeDouble(long offset, double d) throws BufferOverflowException;
|
||||
|
||||
|
||||
R writeVolatileByte(long offset, byte i8) throws BufferOverflowException;
|
||||
|
||||
|
||||
R writeVolatileShort(long offset, short i16) throws BufferOverflowException;
|
||||
|
||||
|
||||
R writeVolatileInt(long offset, int i32) throws BufferOverflowException;
|
||||
|
||||
|
||||
R writeVolatileLong(long offset, long i64) throws BufferOverflowException;
|
||||
|
||||
|
||||
default R writeVolatileFloat(long offset, float f) throws BufferOverflowException {
|
||||
return writeVolatileInt(offset, Float.floatToRawIntBits(f));
|
||||
}
|
||||
|
||||
|
||||
default R writeVolatileDouble(long offset, double d) throws BufferOverflowException {
|
||||
return writeVolatileLong(offset, Double.doubleToRawLongBits(d));
|
||||
}
|
||||
|
||||
|
||||
default R write(long offsetInRDO, byte[] bytes) throws BufferOverflowException {
|
||||
return write(offsetInRDO, bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
|
||||
R write(long offsetInRDO, byte[] bytes, int offset, int length)
|
||||
throws BufferOverflowException;
|
||||
|
||||
void write(long offsetInRDO, ByteBuffer bytes, int offset, int length)
|
||||
throws BufferOverflowException;
|
||||
|
||||
|
||||
default R write(long offsetInRDO, BytesStore bytes)
|
||||
throws BufferOverflowException {
|
||||
try {
|
||||
return write(offsetInRDO, bytes, bytes.readPosition(), bytes.readRemaining());
|
||||
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
R write(long writeOffset, RandomDataInput bytes, long readOffset, long length)
|
||||
throws BufferOverflowException, BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Zero out the bytes between the start and the end.
|
||||
*
|
||||
* @param start index of first byte inclusive
|
||||
* @param end index of last byte exclusive
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the capacity was exceeded
|
||||
*/
|
||||
|
||||
R zeroOut(long start, long end);
|
||||
|
||||
|
||||
default R append(long offset, long value, int digits)
|
||||
throws BufferOverflowException {
|
||||
BytesInternal.append(this, offset, value, digits);
|
||||
return (R) this;
|
||||
}
|
||||
|
||||
|
||||
default R append(long offset, double value, int decimalPlaces, int digits) throws BufferOverflowException {
|
||||
if (decimalPlaces < 20) {
|
||||
double d2 = value * Maths.tens(decimalPlaces);
|
||||
if (d2 <= Long.MAX_VALUE && d2 >= Long.MIN_VALUE) {
|
||||
BytesInternal.appendDecimal(this, Math.round(d2), offset, decimalPlaces, digits);
|
||||
return (R) this;
|
||||
}
|
||||
}
|
||||
BytesInternal.append((StreamingDataOutput) this, value);
|
||||
return (R) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* expert level method to copy data from native memory into the BytesStore
|
||||
*
|
||||
* @param address in native memory to copy from
|
||||
* @param position in BytesStore to copy to
|
||||
* @param size in bytes
|
||||
*/
|
||||
void nativeWrite(long address, long position, long size) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Writes the given {@code cs} to this {@code RandomDataOutput} from the given {@code offset},
|
||||
* in Utf8 format. Returns the offset after the written char sequence.
|
||||
*
|
||||
* @param offset the offset to write char sequence from
|
||||
* @param cs the char sequence to write, could be {@code null}
|
||||
* @return the offset after the char sequence written, in this {@code RandomDataOutput}
|
||||
* @see RandomDataInput#readUtf8(long, Appendable)
|
||||
*/
|
||||
default long writeUtf8(long offset, CharSequence cs) throws BufferOverflowException {
|
||||
return BytesInternal.writeUtf8(this, offset, cs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given {@code cs} to this {@code RandomDataOutput} from the given {@code offset},
|
||||
* in Utf8 format, checking that the utf8 encoding size of the given char sequence is less or
|
||||
* equal to the given {@code maxUtf8Len}, otherwise {@code IllegalArgumentException} is thrown,
|
||||
* and no bytes of this {@code RandomDataOutput} are overwritten. Returns the offset after the
|
||||
* written char sequence.
|
||||
*
|
||||
* @param offset the offset to write char sequence from
|
||||
* @param cs the char sequence to write, could be {@code null}
|
||||
* @param maxUtf8Len the maximum allowed length (in Utf8 encoding) of the given char sequence
|
||||
* @return the offset after the char sequence written, in this {@code RandomDataOutput}
|
||||
* @throws IllegalArgumentException if the given char sequence size in Utf8 encoding exceeds
|
||||
* maxUtf8Len
|
||||
* @see RandomDataInput#readUtf8Limited(long, Appendable, int)
|
||||
* @see RandomDataInput#readUtf8Limited(long, int)
|
||||
*/
|
||||
default long writeUtf8Limited(long offset, CharSequence cs, int maxUtf8Len)
|
||||
throws BufferOverflowException {
|
||||
return BytesInternal.writeUtf8(this, offset, cs, maxUtf8Len);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.annotation.DontChain;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
|
||||
/**
|
||||
* Read data directly as Bytes.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@DontChain
|
||||
public interface ReadBytesMarshallable extends CommonMarshallable {
|
||||
/**
|
||||
* Bytes to read. This can be used as a method to implement or as a lambda.
|
||||
*
|
||||
* @param bytes to read.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
void readMarshallable(BytesIn bytes) throws IORuntimeException;
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.ReferenceOwner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* BytesStore to wrap memory mapped data.
|
||||
*/
|
||||
public class ReadOnlyMappedBytesStore extends MappedBytesStore {
|
||||
|
||||
public ReadOnlyMappedBytesStore(ReferenceOwner owner, MappedFile mappedFile, long start, long address, long capacity, long safeCapacity)
|
||||
throws IllegalStateException {
|
||||
super(owner, mappedFile, start, address, capacity, safeCapacity);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> zeroOut(long start, long end) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compareAndSwapInt(long offset, int expected, int value) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compareAndSwapLong(long offset, long expected, long value) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> writeByte(long offset, byte i8) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> writeShort(long offset, short i16) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> writeInt(long offset, int i32) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> writeLong(long offset, long i64) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> writeOrderedLong(long offset, long i) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> writeFloat(long offset, float f) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> writeDouble(long offset, double d) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> writeVolatileByte(long offset, byte i8) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> writeVolatileShort(long offset, short i16) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> writeVolatileInt(long offset, int i32) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> writeVolatileLong(long offset, long i64) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> write(long offsetInRDO, byte[] bytes, int offset, int length) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(long offsetInRDO, ByteBuffer bytes, int offset, int length) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> write(long writeOffset, RandomDataInput bytes, long readOffset, long length)
|
||||
throws BufferOverflowException, BufferUnderflowException {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write0(long offsetInRDO, RandomDataInput bytes, long offset, long length) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nativeWrite(long address, long position, long size) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
void write8bit(long position, char[] chars, int offset, int length) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long appendUTF(long pos, char[] chars, int offset, int length) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long appendUtf8(long pos, char[] chars, int offset, int length) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public VanillaBytes<Void> bytesForWrite() throws IllegalStateException {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NativeBytesStore<Void> writeOrderedInt(long offset, int i) {
|
||||
throw checkReadOnly();
|
||||
}
|
||||
|
||||
private IllegalStateException checkReadOnly() throws IllegalStateException {
|
||||
throw new IllegalStateException("Read Only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readWrite() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.ReferenceOwner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* applied after a Bytes has been released and cannot be used.
|
||||
*
|
||||
* @see NoBytesStore
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public enum ReleasedBytesStore implements BytesStore {
|
||||
RELEASED_BYTES_STORE;
|
||||
|
||||
|
||||
public static <T, B extends BytesStore<B, T>> BytesStore<B, T> releasedBytesStore() {
|
||||
return RELEASED_BYTES_STORE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reserve(ReferenceOwner id) throws IllegalStateException {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(ReferenceOwner id) throws IllegalStateException {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int refCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryReserve(ReferenceOwner id) throws IllegalStateException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reservedBy(ReferenceOwner owner) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseLast(ReferenceOwner id) throws IllegalStateException {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeByte(long offset, byte i8) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
private IllegalStateException newIllegalStateException() {
|
||||
return new IllegalStateException("released");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeShort(long offset, short i) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeInt(long offset, int i) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeOrderedInt(long offset, int i) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeLong(long offset, long i) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeOrderedLong(long offset, long i) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeFloat(long offset, float d) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeDouble(long offset, double d) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeVolatileByte(long offset, byte i8) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeVolatileShort(long offset, short i16) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeVolatileInt(long offset, int i32) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput writeVolatileLong(long offset, long i64) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput write(long offsetInRDO, byte[] bytes, int offset, int length) {
|
||||
if (length != 0)
|
||||
throw newIllegalStateException();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(long offsetInRDO, ByteBuffer bytes, int offset, int length) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RandomDataOutput write(long writeOffset, RandomDataInput bytes, long readOffset, long length) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readByte(long offset) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int peekUnsignedByte(long offset) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readShort(long offset) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readInt(long offset) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLong(long offset) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float readFloat(long offset) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readDouble(long offset) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readVolatileByte(long offset) throws BufferUnderflowException {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readVolatileShort(long offset) throws BufferUnderflowException {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readVolatileInt(long offset) throws BufferUnderflowException {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readVolatileLong(long offset) throws BufferUnderflowException {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectMemory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BytesStore copy() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long capacity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void underlyingObject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inside(long offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inside(long offset, long buffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long copyTo( BytesStore store) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nativeWrite(long address, long position, long size) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nativeRead(long position, long address, long size) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compareAndSwapInt(long offset, int expected, int value) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testAndSetInt(long offset, int expected, int value) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compareAndSwapLong(long offset, long expected, long value) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equalBytes( BytesStore bytesStore, long length) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(long from, long to, long length) {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForRead(long offset) throws BufferUnderflowException {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForWrite(long offset) throws BufferOverflowException {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForWritePosition() throws UnsupportedOperationException, BufferOverflowException {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes bytesForWrite() {
|
||||
throw newIllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sharedMemory() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.Closeable;
|
||||
|
||||
public interface RingBufferReader extends RingBufferReaderStats, Closeable {
|
||||
long UNKNOWN_INDEX = -1;
|
||||
|
||||
boolean isEmpty();
|
||||
|
||||
boolean isStopped();
|
||||
|
||||
/**
|
||||
* stop the reader. After being stopped, the reader will not block writers.
|
||||
* After being stopped the reader can be re-opened
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* the readPosition and readLimit will be adjusted so that the client can read the data
|
||||
*
|
||||
* @param bytes who's byteStore must be the ring buffer,
|
||||
* @return nextReadPosition which should be passed to {@link RingBufferReader#afterRead(long)}
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
long beforeRead(Bytes bytes);
|
||||
|
||||
void afterRead(long next);
|
||||
|
||||
void afterRead(long next, long payloadStart, long underlyingIndex);
|
||||
|
||||
long underlyingIndex();
|
||||
|
||||
/**
|
||||
* Convenience method calls both {@link #beforeRead(Bytes)} and {@link #afterRead(long)}
|
||||
*
|
||||
* @param bytes
|
||||
* @return whether read succeeded
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
boolean read(BytesOut bytes);
|
||||
|
||||
/**
|
||||
* @return the byteStore which backs the ring buffer
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
BytesStore byteStore();
|
||||
|
||||
/**
|
||||
* Take reader to just past the end of the RB
|
||||
*/
|
||||
void toEnd();
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
public interface RingBufferReaderStats {
|
||||
|
||||
long getAndClearReadCount();
|
||||
|
||||
long getAndClearMissedReadCount();
|
||||
|
||||
long behind();
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.bytes.util.EscapingStopCharTester;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface StopCharTester {
|
||||
/**
|
||||
* Detect which byte stops the string to be parsed
|
||||
* <p>
|
||||
* <p>This should be changed to support char instead.
|
||||
* <p>
|
||||
* <p>Note: for safety reasons, you should stop on a 0 byte or throw an IllegalStateException.
|
||||
*
|
||||
* @param ch to test, 0 should return true or throw an exception.
|
||||
* @return if this byte is a stop character.
|
||||
*/
|
||||
boolean isStopChar(int ch);
|
||||
|
||||
|
||||
default StopCharTester escaping() {
|
||||
return new EscapingStopCharTester(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
public enum StopCharTesters implements StopCharTester {
|
||||
COMMA_STOP {
|
||||
@Override
|
||||
public boolean isStopChar(int ch) {
|
||||
return ch < ' ' || ch == ',';
|
||||
}
|
||||
},
|
||||
CURLY_STOP {
|
||||
@Override
|
||||
public boolean isStopChar(int ch) {
|
||||
return ch < ' ' || ch == '}';
|
||||
}
|
||||
},
|
||||
COMMA_SPACE_STOP {
|
||||
@Override
|
||||
public boolean isStopChar(int ch) {
|
||||
return ch <= ' ' || ch == ',';
|
||||
}
|
||||
},
|
||||
CONTROL_STOP {
|
||||
@Override
|
||||
public boolean isStopChar(int ch) {
|
||||
return ch < ' ';
|
||||
}
|
||||
},
|
||||
SPACE_STOP {
|
||||
@Override
|
||||
public boolean isStopChar(int ch) {
|
||||
return Character.isWhitespace(ch) || ch == 0;
|
||||
}
|
||||
},
|
||||
QUOTES {
|
||||
@Override
|
||||
public boolean isStopChar(int ch) {
|
||||
return ch == '"' || ch <= 0;
|
||||
}
|
||||
},
|
||||
SINGLE_QUOTES {
|
||||
@Override
|
||||
public boolean isStopChar(int ch) {
|
||||
return ch == '\'' || ch <= 0;
|
||||
}
|
||||
},
|
||||
EQUALS {
|
||||
@Override
|
||||
public boolean isStopChar(int ch) {
|
||||
return ch == '=' || ch <= 0;
|
||||
}
|
||||
},
|
||||
NUMBER_END {
|
||||
@Override
|
||||
public boolean isStopChar(int ch) {
|
||||
switch (ch) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '+':
|
||||
case '-':
|
||||
case '.':
|
||||
case 'E':
|
||||
case 'e':
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
NON_ALPHA_DIGIT {
|
||||
@Override
|
||||
public boolean isStopChar(int ch) {
|
||||
return ch < '0' || !(Character.isAlphabetic(ch) || Character.isDigit(ch));
|
||||
}
|
||||
},
|
||||
ALL {
|
||||
@Override
|
||||
public boolean isStopChar(int ch) {
|
||||
return ch < 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.bytes.util.EscapingStopCharsTester;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface StopCharsTester {
|
||||
/**
|
||||
* Detect which byte or bytes stops the string to be parsed
|
||||
* <p>
|
||||
* <p>This should be changed to support char instead.
|
||||
* <p>
|
||||
* <p>Note: for safety reasons, you should stop on a 0 byte or throw an IllegalStateException.
|
||||
*
|
||||
* @param ch to test, 0 should return true or throw an exception.
|
||||
* @param ch2 to test, 0 should return true or throw an exception.
|
||||
* @return if this byte is a stop character.
|
||||
*/
|
||||
boolean isStopChar(int ch, int ch2);
|
||||
|
||||
|
||||
default StopCharsTester escaping() {
|
||||
return new EscapingStopCharsTester(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface StreamingCommon<S extends StreamingCommon<S>> extends RandomCommon {
|
||||
|
||||
/**
|
||||
* Set the readPosition= writePosition = start, writeLimit = capacity
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
|
||||
S clear();
|
||||
}
|
|
@ -0,0 +1,438 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import net.openhft.chronicle.core.OS;
|
||||
import net.openhft.chronicle.core.UnsafeMemory;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import net.openhft.chronicle.core.util.Histogram;
|
||||
import net.openhft.chronicle.core.util.ThrowingConsumer;
|
||||
import net.openhft.chronicle.core.util.ThrowingConsumerNonCapturing;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* This data input has a a position() and a limit()
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public interface StreamingDataInput<S extends StreamingDataInput<S>> extends StreamingCommon<S> {
|
||||
|
||||
S readPosition(long position) throws BufferUnderflowException;
|
||||
|
||||
|
||||
default S readPositionUnlimited(long position) throws BufferUnderflowException {
|
||||
return readLimitToCapacity().readPosition(position);
|
||||
}
|
||||
|
||||
|
||||
default S readPositionRemaining(long position, long remaining) throws BufferUnderflowException {
|
||||
readLimit(position + remaining);
|
||||
return readPosition(position);
|
||||
}
|
||||
|
||||
|
||||
S readLimit(long limit) throws BufferUnderflowException;
|
||||
|
||||
default S readLimitToCapacity() throws BufferUnderflowException {
|
||||
return readLimit(capacity());
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip a number of bytes by moving the readPosition. Must be less than or equal to the readLimit.
|
||||
*
|
||||
* @param bytesToSkip bytes to skip.
|
||||
* @return this
|
||||
* @throws BufferUnderflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
|
||||
S readSkip(long bytesToSkip) throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* Read skip 1 when you are sure this is safe. Use at your own risk when you find a performance problem.
|
||||
*/
|
||||
void uncheckedReadSkipOne();
|
||||
|
||||
/**
|
||||
* Read skip -1 when you are sure this is safe. Use at your own risk when you find a performance problem.
|
||||
*/
|
||||
void uncheckedReadSkipBackOne();
|
||||
|
||||
/**
|
||||
* Perform a set of actions with a temporary bounds mode.
|
||||
*/
|
||||
default void readWithLength0(long length, ThrowingConsumerNonCapturing<S, IORuntimeException, BytesOut> bytesConsumer, StringBuilder sb, BytesOut toBytes)
|
||||
throws BufferUnderflowException, IORuntimeException {
|
||||
if (length > readRemaining())
|
||||
throw new BufferUnderflowException();
|
||||
long limit0 = readLimit();
|
||||
long limit = readPosition() + length;
|
||||
try {
|
||||
readLimit(limit);
|
||||
bytesConsumer.accept((S) this, sb, toBytes);
|
||||
} finally {
|
||||
readLimit(limit0);
|
||||
readPosition(limit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a set of actions with a temporary bounds mode.
|
||||
*/
|
||||
default void readWithLength(long length, ThrowingConsumer<S, IORuntimeException> bytesConsumer)
|
||||
throws BufferUnderflowException, IORuntimeException {
|
||||
if (length > readRemaining())
|
||||
throw new BufferUnderflowException();
|
||||
long limit0 = readLimit();
|
||||
long limit = readPosition() + length;
|
||||
try {
|
||||
readLimit(limit);
|
||||
bytesConsumer.accept((S) this);
|
||||
} finally {
|
||||
readLimit(limit0);
|
||||
readPosition(limit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
default InputStream inputStream() {
|
||||
return new StreamingInputStream(this);
|
||||
}
|
||||
|
||||
default long readStopBit() throws IORuntimeException {
|
||||
return BytesInternal.readStopBit(this);
|
||||
}
|
||||
|
||||
default char readStopBitChar() throws IORuntimeException {
|
||||
return BytesInternal.readStopBitChar(this);
|
||||
}
|
||||
|
||||
default double readStopBitDouble() {
|
||||
return BytesInternal.readStopBitDouble(this);
|
||||
}
|
||||
|
||||
default double readStopBitDecimal() throws BufferOverflowException {
|
||||
long value = readStopBit();
|
||||
int scale = (int) (Math.abs(value) % 10);
|
||||
value /= 10;
|
||||
return (double) value / Maths.tens(scale);
|
||||
}
|
||||
|
||||
default boolean readBoolean() {
|
||||
byte b = readByte();
|
||||
return BytesUtil.byteToBoolean(b);
|
||||
}
|
||||
|
||||
byte readByte();
|
||||
|
||||
default byte rawReadByte() {
|
||||
return readByte();
|
||||
}
|
||||
|
||||
default char readChar() {
|
||||
return readStopBitChar();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the next unsigned 8 bit value or -1;
|
||||
*/
|
||||
int readUnsignedByte();
|
||||
|
||||
/**
|
||||
* @return the next unsigned 8 bit value or -1;
|
||||
*/
|
||||
int uncheckedReadUnsignedByte();
|
||||
|
||||
short readShort() throws BufferUnderflowException;
|
||||
|
||||
default int readUnsignedShort() throws BufferUnderflowException {
|
||||
return readShort() & 0xFFFF;
|
||||
}
|
||||
|
||||
default int readInt24() throws BufferUnderflowException {
|
||||
return readUnsignedShort() | (readUnsignedByte() << 24 >> 8);
|
||||
}
|
||||
|
||||
default int readUnsignedInt24() throws BufferUnderflowException {
|
||||
return readUnsignedShort() | (readUnsignedByte() << 16);
|
||||
}
|
||||
|
||||
int readInt() throws BufferUnderflowException;
|
||||
|
||||
default int rawReadInt() {
|
||||
return readInt();
|
||||
}
|
||||
|
||||
default long readUnsignedInt()
|
||||
throws BufferUnderflowException {
|
||||
return readInt() & 0xFFFFFFFFL;
|
||||
}
|
||||
|
||||
long readLong() throws BufferUnderflowException;
|
||||
|
||||
default long rawReadLong() {
|
||||
return readLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a long using the bytes remaining
|
||||
*/
|
||||
default long readIncompleteLong() {
|
||||
long left = readRemaining();
|
||||
try {
|
||||
if (left >= 8)
|
||||
return readLong();
|
||||
if (left == 4)
|
||||
return readInt();
|
||||
long l = 0;
|
||||
for (int i = 0, remaining = (int) left; i < remaining; i++) {
|
||||
l |= (long) readUnsignedByte() << (i * 8);
|
||||
}
|
||||
return l;
|
||||
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
float readFloat() throws BufferUnderflowException;
|
||||
|
||||
double readDouble() throws BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* The same as readUTF() except the length is stop bit encoded. This saves one byte for strings shorter than 128
|
||||
* chars. <code>null</code> values are also supported
|
||||
*
|
||||
* @return a Unicode string or <code>null</code> if <code>writeUtf8(null)</code> was called
|
||||
*/
|
||||
|
||||
default String readUtf8()
|
||||
throws BufferUnderflowException, IORuntimeException, IllegalArgumentException {
|
||||
return BytesInternal.readUtf8(this);
|
||||
}
|
||||
|
||||
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
default String readUTFΔ()
|
||||
throws IORuntimeException, BufferUnderflowException, IllegalArgumentException {
|
||||
return BytesInternal.readUtf8(this);
|
||||
}
|
||||
|
||||
|
||||
default String read8bit() throws IORuntimeException, BufferUnderflowException {
|
||||
return BytesInternal.read8bit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as readUtf8() except the chars are copied to a truncated StringBuilder.
|
||||
*
|
||||
* @param sb to copy chars to
|
||||
* @return <code>true</code> if there was a String, or <code>false</code> if it was <code>null</code>
|
||||
*/
|
||||
default <ACS extends Appendable & CharSequence> boolean readUtf8( ACS sb)
|
||||
throws IORuntimeException, IllegalArgumentException, BufferUnderflowException {
|
||||
AppendableUtil.setLength(sb, 0);
|
||||
if (readRemaining() <= 0)
|
||||
// TODO throw BufferUnderflowException here? please review
|
||||
return false;
|
||||
long len0 = readStopBit();
|
||||
if (len0 == -1)
|
||||
return false;
|
||||
int len = Maths.toUInt31(len0);
|
||||
if (len > 0)
|
||||
BytesInternal.parseUtf8(this, sb, true, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
default <ACS extends Appendable & CharSequence> boolean readUTFΔ( ACS sb)
|
||||
throws IORuntimeException, IllegalArgumentException, BufferUnderflowException {
|
||||
return readUtf8(sb);
|
||||
}
|
||||
|
||||
default boolean read8bit( Bytes b)
|
||||
throws BufferUnderflowException, IllegalStateException, BufferOverflowException {
|
||||
b.clear();
|
||||
if (readRemaining() <= 0)
|
||||
return false;
|
||||
long len0 = this.readStopBit();
|
||||
if (len0 == -1)
|
||||
return false;
|
||||
int len = Maths.toUInt31(len0);
|
||||
b.write((BytesStore) this, readPosition(), len);
|
||||
readSkip(len);
|
||||
return true;
|
||||
}
|
||||
|
||||
default <ACS extends Appendable & CharSequence> boolean read8bit( ACS sb)
|
||||
throws IORuntimeException, IllegalArgumentException, BufferUnderflowException {
|
||||
AppendableUtil.setLength(sb, 0);
|
||||
long len0 = BytesInternal.readStopBit(this);
|
||||
if (len0 == -1)
|
||||
return false;
|
||||
int len = Maths.toUInt31(len0);
|
||||
try {
|
||||
AppendableUtil.parse8bit(this, sb, len);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
default boolean read8bit( StringBuilder sb)
|
||||
throws IORuntimeException, BufferUnderflowException {
|
||||
sb.setLength(0);
|
||||
long len0 = BytesInternal.readStopBit(this);
|
||||
if (len0 == -1)
|
||||
return false;
|
||||
int len = Maths.toUInt31(len0);
|
||||
try {
|
||||
AppendableUtil.parse8bit(this, sb, len);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
default int read( byte[] bytes) {
|
||||
return read(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
default int read( byte[] bytes, int off, int len) {
|
||||
long remaining = readRemaining();
|
||||
if (remaining <= 0)
|
||||
return -1;
|
||||
int len2 = (int) Math.min(len, remaining);
|
||||
int i = 0;
|
||||
for (; i < len2 - 7; i += 8)
|
||||
UnsafeMemory.unsafePutLong(bytes, i + off, rawReadLong());
|
||||
for (; i < len2; i++)
|
||||
bytes[off + i] = rawReadByte();
|
||||
return len2;
|
||||
}
|
||||
|
||||
default int read( char[] bytes, int off, int len) {
|
||||
long remaining = readRemaining();
|
||||
if (remaining <= 0)
|
||||
return -1;
|
||||
int len2 = (int) Math.min(len, remaining);
|
||||
for (int i = 0; i < len2; i++)
|
||||
bytes[off + i] = (char) readUnsignedByte();
|
||||
return len2;
|
||||
}
|
||||
|
||||
default void read( ByteBuffer buffer) {
|
||||
for (int i = (int) Math.min(readRemaining(), buffer.remaining()); i > 0; i--)
|
||||
buffer.put(readByte());
|
||||
}
|
||||
|
||||
default void read( Bytes bytes, int length) {
|
||||
int len2 = (int) Math.min(length, readRemaining());
|
||||
int i = 0;
|
||||
for (; i < len2 - 7; i += 8)
|
||||
bytes.rawWriteLong(rawReadLong());
|
||||
for (; i < len2; i++)
|
||||
bytes.rawWriteByte(rawReadByte());
|
||||
}
|
||||
|
||||
default void unsafeReadObject(Object o, int length) {
|
||||
unsafeReadObject(o, (o.getClass().isArray() ? 4 : 0) + Jvm.objectHeaderSize(), length);
|
||||
}
|
||||
|
||||
default void unsafeReadObject(Object o, int offset, int length) {
|
||||
assert BytesUtil.isTriviallyCopyable(o.getClass(), offset, length);
|
||||
if (readRemaining() < length)
|
||||
throw new BufferUnderflowException();
|
||||
int i = 0;
|
||||
for (; i < length - 7; i += 8)
|
||||
UnsafeMemory.unsafePutLong(o, offset + i, rawReadLong());
|
||||
for (; i < length; i++)
|
||||
UnsafeMemory.unsafePutByte(o, offset + i, rawReadByte());
|
||||
}
|
||||
|
||||
int readVolatileInt() throws BufferUnderflowException;
|
||||
|
||||
long readVolatileLong() throws BufferUnderflowException;
|
||||
|
||||
int peekUnsignedByte();
|
||||
|
||||
|
||||
|
||||
default <E extends Enum<E>> E readEnum( Class<E> eClass)
|
||||
throws IORuntimeException, BufferUnderflowException {
|
||||
return BytesInternal.readEnum(this, eClass);
|
||||
}
|
||||
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
default void parseUTF(Appendable sb, int length)
|
||||
throws IllegalArgumentException, BufferUnderflowException, UTFDataFormatRuntimeException {
|
||||
parseUtf8(sb, length);
|
||||
}
|
||||
|
||||
default void parseUtf8(Appendable sb, int encodedLength)
|
||||
throws IllegalArgumentException, BufferUnderflowException, UTFDataFormatRuntimeException {
|
||||
parseUtf8(sb, true, encodedLength);
|
||||
}
|
||||
|
||||
default void parseUtf8(Appendable sb, boolean utf, int length)
|
||||
throws IllegalArgumentException, BufferUnderflowException, UTFDataFormatRuntimeException {
|
||||
AppendableUtil.setLength(sb, 0);
|
||||
BytesInternal.parseUtf8(this, sb, utf, length);
|
||||
}
|
||||
|
||||
default long parseHexLong() {
|
||||
return BytesInternal.parseHexLong(this);
|
||||
}
|
||||
|
||||
void copyTo(OutputStream out) throws IOException;
|
||||
|
||||
long copyTo(BytesStore to);
|
||||
|
||||
default void readHistogram( Histogram histogram) {
|
||||
BytesInternal.readHistogram(this, histogram);
|
||||
}
|
||||
|
||||
default void readWithLength(Bytes bytes) {
|
||||
bytes.clear();
|
||||
int length = Maths.toUInt31(readStopBit());
|
||||
int i;
|
||||
for (i = 0; i < length - 7; i++)
|
||||
bytes.writeLong(readLong());
|
||||
for (; i < length; i++)
|
||||
bytes.writeByte(readByte());
|
||||
}
|
||||
|
||||
/**
|
||||
* When there is no more data to read, return zero, false and empty string.
|
||||
*
|
||||
* @param lenient if true, return nothing rather than error.
|
||||
*/
|
||||
void lenient(boolean lenient);
|
||||
|
||||
boolean lenient();
|
||||
|
||||
}
|
|
@ -0,0 +1,562 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import net.openhft.chronicle.core.UnsafeMemory;
|
||||
import net.openhft.chronicle.core.annotation.Java9;
|
||||
import net.openhft.chronicle.core.util.Histogram;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Position based access. Once data has been read, the position() moves.
|
||||
* <p>The use of this instance is single threaded, though the use of the data
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public interface StreamingDataOutput<S extends StreamingDataOutput<S>> extends StreamingCommon<S> {
|
||||
int JAVA9_STRING_CODER_LATIN = 0;
|
||||
int JAVA9_STRING_CODER_UTF16 = 1;
|
||||
|
||||
S writePosition(long position) throws BufferOverflowException;
|
||||
|
||||
S writeLimit(long limit) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Skip a number of bytes by moving the writePosition. Must be less than or equal to the writeLimit.
|
||||
*
|
||||
* @param bytesToSkip bytes to skip.
|
||||
* @return this
|
||||
* @throws BufferOverflowException if the offset is outside the limits of the Bytes
|
||||
*/
|
||||
S writeSkip(long bytesToSkip) throws BufferOverflowException;
|
||||
|
||||
default S alignBy(int width) {
|
||||
return writeSkip((-writePosition()) & (width - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Bytes as an OutputStream
|
||||
*/
|
||||
|
||||
default OutputStream outputStream() {
|
||||
return new StreamingOutputStream(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a stop bit encoded long
|
||||
*
|
||||
* @param x long to write
|
||||
* @return this.
|
||||
*/
|
||||
|
||||
default S writeStopBit(long x) throws BufferOverflowException {
|
||||
BytesInternal.writeStopBit(this, x);
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
|
||||
default S writeStopBit(char x) throws BufferOverflowException {
|
||||
BytesInternal.writeStopBit(this, x);
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
|
||||
default S writeStopBit(double d) throws BufferOverflowException {
|
||||
BytesInternal.writeStopBit(this, d);
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
|
||||
default S writeStopBitDecimal(double d) throws BufferOverflowException {
|
||||
boolean negative = d < 0;
|
||||
double ad = Math.abs(d);
|
||||
long value;
|
||||
int scale = 0;
|
||||
if ((long) ad == ad) {
|
||||
value = (long) ad * 10;
|
||||
|
||||
} else {
|
||||
double factor = 1;
|
||||
while (scale < 9) {
|
||||
double v = ad * factor;
|
||||
if (v >= 1e14 || (long) v == v)
|
||||
break;
|
||||
factor *= 10;
|
||||
scale++;
|
||||
}
|
||||
value = Math.round(ad * factor);
|
||||
while (scale > 0 && value % 10 == 0) {
|
||||
value /= 10;
|
||||
scale--;
|
||||
}
|
||||
value = value * 10 + scale;
|
||||
}
|
||||
if (negative)
|
||||
value = -value;
|
||||
BytesInternal.writeStopBit(this, value);
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the same encoding as <code>writeUTF</code> with the following changes. 1) The length is stop bit encoded
|
||||
* i.e. one byte longer for short strings, but is not limited in length. 2) The string can be null.
|
||||
*
|
||||
* @param cs the string value to be written. Can be null.
|
||||
* @throws BufferOverflowException if there is not enough space left
|
||||
*/
|
||||
|
||||
default S writeUtf8(CharSequence cs)
|
||||
throws BufferOverflowException {
|
||||
BytesInternal.writeUtf8(this, cs);
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
|
||||
default S writeUtf8(String s)
|
||||
throws BufferOverflowException {
|
||||
BytesInternal.writeUtf8(this, s);
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
|
||||
@Deprecated(/* to be removed in x.22 */)
|
||||
default S writeUTFΔ(CharSequence cs) throws BufferOverflowException {
|
||||
return writeUtf8(cs);
|
||||
}
|
||||
|
||||
|
||||
default S write8bit(CharSequence cs)
|
||||
throws BufferOverflowException {
|
||||
if (cs == null)
|
||||
return writeStopBit(-1);
|
||||
|
||||
if (cs instanceof BytesStore)
|
||||
return write8bit((BytesStore) cs);
|
||||
|
||||
if (cs instanceof String)
|
||||
return write8bit((String) cs);
|
||||
|
||||
return write8bit(cs, 0, cs.length());
|
||||
}
|
||||
|
||||
|
||||
default S write8bit( CharSequence s, int start, int length)
|
||||
throws BufferOverflowException, IllegalArgumentException, IndexOutOfBoundsException {
|
||||
writeStopBit(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = s.charAt(i + start);
|
||||
rawWriteByte((byte) Maths.toUInt8((int) c));
|
||||
}
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
|
||||
default S write(CharSequence cs)
|
||||
throws BufferOverflowException, BufferUnderflowException, IllegalArgumentException {
|
||||
if (cs instanceof BytesStore) {
|
||||
return write((BytesStore) cs);
|
||||
}
|
||||
return write(cs, 0, cs.length());
|
||||
}
|
||||
|
||||
|
||||
default S write( CharSequence s, int start, int length)
|
||||
throws BufferOverflowException, IllegalArgumentException, IndexOutOfBoundsException {
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = s.charAt(i + start);
|
||||
appendUtf8(c);
|
||||
}
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
|
||||
default S write8bit(String s)
|
||||
throws BufferOverflowException {
|
||||
if (s == null)
|
||||
writeStopBit(-1);
|
||||
else
|
||||
write8bit(s, 0, (int) Math.min(writeRemaining(), s.length()));
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
|
||||
default S write8bit(BytesStore bs)
|
||||
throws BufferOverflowException {
|
||||
if (bs == null) {
|
||||
writeStopBit(-1);
|
||||
} else {
|
||||
long offset = bs.readPosition();
|
||||
long readRemaining = Math.min(writeRemaining(), bs.readLimit() - offset);
|
||||
writeStopBit(readRemaining);
|
||||
write(bs, offset, readRemaining);
|
||||
}
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
|
||||
S writeByte(byte i8) throws BufferOverflowException;
|
||||
|
||||
default S rawWriteByte(byte i8) throws BufferOverflowException {
|
||||
return writeByte(i8);
|
||||
}
|
||||
|
||||
|
||||
default S writeUnsignedByte(int i)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
return writeByte((byte) Maths.toUInt8(i));
|
||||
}
|
||||
|
||||
|
||||
default S writeChar(char ch) {
|
||||
return writeStopBit(ch);
|
||||
}
|
||||
|
||||
|
||||
S writeShort(short i16) throws BufferOverflowException;
|
||||
|
||||
|
||||
default S writeUnsignedShort(int u16)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
return writeShort((short) Maths.toUInt16(u16));
|
||||
}
|
||||
|
||||
|
||||
default S writeInt24(int i) throws BufferOverflowException {
|
||||
writeUnsignedShort((short) i);
|
||||
return writeUnsignedByte((i >>> 16) & 0xFF);
|
||||
}
|
||||
|
||||
|
||||
default S writeUnsignedInt24(int i) throws BufferOverflowException {
|
||||
writeUnsignedShort((short) i);
|
||||
return writeUnsignedByte(i >>> 16);
|
||||
}
|
||||
|
||||
|
||||
S writeInt(int i) throws BufferOverflowException;
|
||||
|
||||
default S rawWriteInt(int i) throws BufferOverflowException {
|
||||
return writeInt(i);
|
||||
}
|
||||
|
||||
|
||||
S writeIntAdv(int i, int advance) throws BufferOverflowException;
|
||||
|
||||
|
||||
default S writeUnsignedInt(long i)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
return writeInt((int) Maths.toUInt32(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a long
|
||||
*/
|
||||
|
||||
S writeLong(long i64) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Write a long without a bounds check
|
||||
*/
|
||||
default S rawWriteLong(long i) throws BufferOverflowException {
|
||||
return writeLong(i);
|
||||
}
|
||||
|
||||
|
||||
S writeLongAdv(long i64, int advance) throws BufferOverflowException;
|
||||
|
||||
|
||||
S writeFloat(float f) throws BufferOverflowException;
|
||||
|
||||
|
||||
S writeDouble(double d) throws BufferOverflowException;
|
||||
|
||||
|
||||
S writeDoubleAndInt(double d, int i) throws BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Write all data or fail.
|
||||
*/
|
||||
|
||||
default S write( RandomDataInput bytes) {
|
||||
assert bytes != this : "you should not write to yourself !";
|
||||
|
||||
try {
|
||||
return write(bytes, bytes.readPosition(), Math.min(writeRemaining(), bytes.readRemaining()));
|
||||
} catch (BufferOverflowException | BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the passed BytesStore
|
||||
*
|
||||
* @param bytes to write
|
||||
* @return this
|
||||
*/
|
||||
default S write( BytesStore bytes) {
|
||||
assert bytes != this : "you should not write to yourself !";
|
||||
|
||||
try {
|
||||
return write(bytes, bytes.readPosition(), Math.min(writeRemaining(), bytes.readRemaining()));
|
||||
} catch (BufferOverflowException | BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return capacity without resize
|
||||
*/
|
||||
long realCapacity();
|
||||
|
||||
/**
|
||||
* @return writeRemaining with resize
|
||||
*/
|
||||
long realWriteRemaining();
|
||||
|
||||
default boolean canWriteDirect(long count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
default S writeSome( Bytes bytes) {
|
||||
try {
|
||||
long length = Math.min(bytes.readRemaining(), writeRemaining());
|
||||
if (length + writePosition() >= 1 << 20)
|
||||
length = Math.min(bytes.readRemaining(), realCapacity() - writePosition());
|
||||
write(bytes, bytes.readPosition(), length);
|
||||
if (length == bytes.readRemaining()) {
|
||||
bytes.clear();
|
||||
} else {
|
||||
bytes.readSkip(length);
|
||||
if (bytes.writePosition() > bytes.realCapacity() / 2)
|
||||
bytes.compact();
|
||||
}
|
||||
return (S) this;
|
||||
} catch (BufferOverflowException | BufferUnderflowException | IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all data or fail.
|
||||
*/
|
||||
|
||||
default S write( RandomDataInput bytes, long offset, long length)
|
||||
throws BufferOverflowException, BufferUnderflowException {
|
||||
BytesInternal.writeFully(bytes, offset, length, this);
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all data or fail.
|
||||
*/
|
||||
|
||||
default S write( BytesStore bytes, long offset, long
|
||||
length)
|
||||
throws BufferOverflowException, BufferUnderflowException {
|
||||
if (length + writePosition() > capacity())
|
||||
throw new IllegalArgumentException("Cannot write " + length + " bytes as position is " + writePosition() + " and capacity is " + capacity());
|
||||
BytesInternal.writeFully(bytes, offset, length, this);
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
|
||||
default S write( byte[] bytes) throws BufferOverflowException {
|
||||
write(bytes, 0, bytes.length);
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all data or fail.
|
||||
*/
|
||||
|
||||
S write(byte[] bytes, int offset, int length) throws BufferOverflowException;
|
||||
|
||||
default S unsafeWriteObject(Object o, int length) {
|
||||
return unsafeWriteObject(o, (o.getClass().isArray() ? 4 : 0) + Jvm.objectHeaderSize(), length);
|
||||
}
|
||||
|
||||
default S unsafeWriteObject(Object o, int offset, int length) {
|
||||
int i = 0;
|
||||
for (; i < length - 7; i += 8)
|
||||
writeLong(UnsafeMemory.unsafeGetLong(o, offset + i));
|
||||
for (; i < length; i++)
|
||||
writeByte(UnsafeMemory.unsafeGetByte(o, offset + i));
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
|
||||
S writeSome(ByteBuffer buffer) throws BufferOverflowException;
|
||||
|
||||
|
||||
default S writeBoolean(boolean flag) throws BufferOverflowException {
|
||||
return writeByte(flag ? (byte) 'Y' : (byte) 'N');
|
||||
}
|
||||
|
||||
|
||||
S writeOrderedInt(int i) throws BufferOverflowException;
|
||||
|
||||
|
||||
S writeOrderedLong(long i) throws BufferOverflowException;
|
||||
|
||||
default <E extends Enum<E>> S writeEnum( E e)
|
||||
throws BufferOverflowException {
|
||||
return write8bit(e.name());
|
||||
}
|
||||
|
||||
|
||||
default S appendUtf8( CharSequence cs)
|
||||
throws BufferOverflowException {
|
||||
return appendUtf8(cs, 0, cs.length());
|
||||
}
|
||||
|
||||
|
||||
default S appendUtf8(int codepoint) throws BufferOverflowException {
|
||||
BytesInternal.appendUtf8Char(this, codepoint);
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
|
||||
default S appendUtf8(char[] chars, int offset, int length)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
int i;
|
||||
ascii:
|
||||
{
|
||||
for (i = 0; i < length; i++) {
|
||||
char c = chars[offset + i];
|
||||
if (c > 0x007F)
|
||||
break ascii;
|
||||
writeByte((byte) c);
|
||||
}
|
||||
return (S) this;
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
char c = chars[offset + i];
|
||||
BytesInternal.appendUtf8Char(this, c);
|
||||
}
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
|
||||
default S appendUtf8( CharSequence cs, int offset, int length)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
BytesInternal.appendUtf8(this, cs, offset, length);
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
// length is number of characters (not bytes)
|
||||
@Java9
|
||||
|
||||
default S appendUtf8(byte[] bytes, int offset, int length, byte coder)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
if (coder == JAVA9_STRING_CODER_LATIN) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
byte b = bytes[offset + i];
|
||||
int b2 = (b & 0xFF);
|
||||
BytesInternal.appendUtf8Char(this, b2);
|
||||
}
|
||||
} else {
|
||||
assert coder == JAVA9_STRING_CODER_UTF16;
|
||||
for (int i = 0; i < 2 * length; i += 2) {
|
||||
byte b1 = bytes[2 * offset + i];
|
||||
byte b2 = bytes[2 * offset + i + 1];
|
||||
|
||||
int uBE = ((b2 & 0xFF) << 8) | b1 & 0xFF;
|
||||
BytesInternal.appendUtf8Char(this, uBE);
|
||||
}
|
||||
}
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
@Java9
|
||||
|
||||
default S appendUtf8(byte[] bytes, int offset, int length)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
for (int i = 0; i < length; i++) {
|
||||
int b = bytes[offset + i] & 0xFF; // unsigned byte
|
||||
|
||||
if (b >= 0xF0) {
|
||||
int b2 = bytes[offset + i + 1] & 0xFF; // unsigned byte
|
||||
int b3 = bytes[offset + i + 2] & 0xFF; // unsigned byte
|
||||
int b4 = bytes[offset + i + 3] & 0xFF; // unsigned byte
|
||||
this.writeByte((byte) b4);
|
||||
this.writeByte((byte) b3);
|
||||
this.writeByte((byte) b2);
|
||||
this.writeByte((byte) b);
|
||||
|
||||
i += 3;
|
||||
} else if (b >= 0xE0) {
|
||||
int b2 = bytes[offset + i + 1] & 0xFF; // unsigned byte
|
||||
int b3 = bytes[offset + i + 2] & 0xFF; // unsigned byte
|
||||
this.writeByte((byte) b3);
|
||||
this.writeByte((byte) b2);
|
||||
this.writeByte((byte) b);
|
||||
|
||||
i += 2;
|
||||
} else if (b >= 0xC0) {
|
||||
int b2 = bytes[offset + i + 1] & 0xFF; // unsigned byte
|
||||
this.writeByte((byte) b2);
|
||||
this.writeByte((byte) b);
|
||||
|
||||
i += 1;
|
||||
} else {
|
||||
this.writeByte((byte) b);
|
||||
}
|
||||
}
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
default void copyFrom( InputStream input) throws IOException, BufferOverflowException, IllegalArgumentException {
|
||||
BytesInternal.copy(input, this);
|
||||
}
|
||||
|
||||
default void writePositionRemaining(long position, long length) {
|
||||
writeLimit(position + length);
|
||||
writePosition(position);
|
||||
}
|
||||
|
||||
default void writeHistogram( Histogram histogram) {
|
||||
BytesInternal.writeHistogram(this, histogram);
|
||||
}
|
||||
|
||||
default void writeBigDecimal( BigDecimal bd) {
|
||||
writeBigInteger(bd.unscaledValue());
|
||||
writeStopBit(bd.scale());
|
||||
}
|
||||
|
||||
default void writeBigInteger( BigInteger bi) {
|
||||
byte[] bytes = bi.toByteArray();
|
||||
writeStopBit(bytes.length);
|
||||
write(bytes);
|
||||
}
|
||||
|
||||
default void writeWithLength(RandomDataInput bytes) {
|
||||
writeStopBit(bytes.readRemaining());
|
||||
write(bytes);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class StreamingInputStream extends InputStream {
|
||||
|
||||
private StreamingDataInput in;
|
||||
|
||||
public StreamingInputStream() {
|
||||
this(NoBytesStore.NO_BYTES);
|
||||
}
|
||||
|
||||
public StreamingInputStream(StreamingDataInput in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
|
||||
public StreamingInputStream init(StreamingDataInput in) {
|
||||
this.in = in;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
long len = Math.min(in.readRemaining(), n);
|
||||
in.readSkip(len);
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return (int) Math.min(Integer.MAX_VALUE, in.readRemaining());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
int len2 = in.read(b, off, len);
|
||||
return len2 == 0 ? -1 : len2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return in.readRemaining() > 0 ? in.readUnsignedByte() : -1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.BufferOverflowException;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class StreamingOutputStream extends OutputStream {
|
||||
private StreamingDataOutput sdo;
|
||||
|
||||
public StreamingOutputStream() {
|
||||
this(NoBytesStore.NO_BYTES);
|
||||
}
|
||||
|
||||
public StreamingOutputStream(StreamingDataOutput sdo) {
|
||||
this.sdo = sdo;
|
||||
}
|
||||
|
||||
|
||||
public StreamingOutputStream init(StreamingDataOutput sdo) {
|
||||
this.sdo = sdo;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
try {
|
||||
sdo.write(b, off, len);
|
||||
|
||||
} catch ( BufferOverflowException | IllegalArgumentException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
try {
|
||||
sdo.writeUnsignedByte(0xff & b);
|
||||
|
||||
} catch ( BufferOverflowException | IllegalArgumentException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class SubBytes<Underlying> extends VanillaBytes<Underlying> {
|
||||
private final long start;
|
||||
private final long capacity;
|
||||
|
||||
public SubBytes( BytesStore bytesStore, long start, long capacity) throws IllegalStateException {
|
||||
super(bytesStore);
|
||||
this.start = start;
|
||||
this.capacity = capacity;
|
||||
clear();
|
||||
readLimit(writeLimit());
|
||||
}
|
||||
|
||||
public SubBytes( BytesStore bytesStore) throws IllegalStateException {
|
||||
super(bytesStore);
|
||||
this.start = 0;
|
||||
this.capacity = bytesStore.capacity();
|
||||
clear();
|
||||
readLimit(writeLimit());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long capacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long start() {
|
||||
return start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long realCapacity() {
|
||||
return capacity;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
|
||||
public class UTFDataFormatRuntimeException extends IORuntimeException {
|
||||
public UTFDataFormatRuntimeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UTFDataFormatRuntimeException(String message, Exception cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.OS;
|
||||
import net.openhft.chronicle.core.util.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static net.openhft.chronicle.core.util.StringUtils.extractBytes;
|
||||
import static net.openhft.chronicle.core.util.StringUtils.extractChars;
|
||||
|
||||
/**
|
||||
* Fast unchecked version of AbstractBytes
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class UncheckedBytes<Underlying>
|
||||
extends AbstractBytes<Underlying> {
|
||||
Bytes underlyingBytes;
|
||||
|
||||
public UncheckedBytes( Bytes underlyingBytes) throws IllegalStateException {
|
||||
super(underlyingBytes.bytesStore(), underlyingBytes.writePosition(), underlyingBytes.writeLimit());
|
||||
this.underlyingBytes = underlyingBytes;
|
||||
readPosition(underlyingBytes.readPosition());
|
||||
}
|
||||
|
||||
public void setBytes( Bytes bytes) throws IllegalStateException {
|
||||
BytesStore underlyingBytes = bytes.bytesStore();
|
||||
if (bytesStore != underlyingBytes) {
|
||||
bytesStore.release(this);
|
||||
this.bytesStore(underlyingBytes);
|
||||
bytesStore.reserve(this);
|
||||
}
|
||||
readPosition(bytes.readPosition());
|
||||
this.uncheckedWritePosition(bytes.writePosition());
|
||||
this.writeLimit = bytes.writeLimit();
|
||||
|
||||
this.underlyingBytes = bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ensureCapacity(long size) throws IllegalArgumentException {
|
||||
if (size > realCapacity()) {
|
||||
underlyingBytes.ensureCapacity(size);
|
||||
bytesStore(underlyingBytes.bytesStore());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Bytes<Underlying> unchecked(boolean unchecked) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unchecked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeCheckOffset(long offset, long adding) {
|
||||
}
|
||||
|
||||
@Override
|
||||
void readCheckOffset(long offset, long adding, boolean given) {
|
||||
}
|
||||
|
||||
@Override
|
||||
void prewriteCheckOffset(long offset, long subtracting) {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> readPosition(long position) {
|
||||
readPosition = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> readLimit(long limit) {
|
||||
uncheckedWritePosition(limit);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writePosition(long position) {
|
||||
uncheckedWritePosition(position);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> readSkip(long bytesToSkip) {
|
||||
readPosition += bytesToSkip;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeSkip(long bytesToSkip) {
|
||||
uncheckedWritePosition(writePosition() + bytesToSkip);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeLimit(long limit) {
|
||||
writeLimit = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BytesStore<Bytes<Underlying>, Underlying> copy() {
|
||||
throw new UnsupportedOperationException("todo");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isElastic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long readOffsetPositionMoved(long adding) {
|
||||
long offset = readPosition;
|
||||
readPosition += adding;
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long writeOffsetPositionMoved(long adding, long advance) {
|
||||
long oldPosition = writePosition();
|
||||
uncheckedWritePosition(writePosition() + advance);
|
||||
return oldPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long prewriteOffsetPositionMoved(long subtracting) throws BufferOverflowException {
|
||||
return readPosition -= subtracting;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> write( RandomDataInput bytes, long offset, long length)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
if (length == 8) {
|
||||
writeLong(bytes.readLong(offset));
|
||||
|
||||
} else {
|
||||
super.write(bytes, offset, length);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public Bytes<Underlying> write( BytesStore bytes, long offset, long length)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
if (length == 8) {
|
||||
writeLong(bytes.readLong(offset));
|
||||
} else if (bytes.underlyingObject() == null
|
||||
&& bytesStore
|
||||
.isDirectMemory() &&
|
||||
length >= 32) {
|
||||
rawCopy(bytes, offset, length);
|
||||
|
||||
} else {
|
||||
super.write(bytes, offset, length);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Bytes<Underlying> append8bit( CharSequence cs)
|
||||
throws BufferOverflowException, BufferUnderflowException {
|
||||
if (cs instanceof RandomDataInput) {
|
||||
return write((RandomDataInput) cs);
|
||||
}
|
||||
|
||||
int length = cs.length();
|
||||
long offset = writeOffsetPositionMoved(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = cs.charAt(i);
|
||||
if (c > 255) c = '?';
|
||||
writeByte(offset, (byte) c);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
long rawCopy( BytesStore bytes, long offset, long length)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
long len = Math.min(writeRemaining(), Math.min(bytes.capacity() - offset, length));
|
||||
if (len > 0) {
|
||||
writeCheckOffset(writePosition(), len);
|
||||
this.throwExceptionIfReleased();
|
||||
OS.memory().copyMemory(bytes.addressForRead(offset), addressForWritePosition(), len);
|
||||
writeSkip(len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeByte(byte i8) throws BufferOverflowException {
|
||||
long offset = writeOffsetPositionMoved(1, 1);
|
||||
bytesStore.writeByte(offset, i8);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeUtf8(String s) throws BufferOverflowException {
|
||||
if (s == null) {
|
||||
writeStopBit(-1);
|
||||
return this;
|
||||
}
|
||||
|
||||
try {
|
||||
if (Jvm.isJava9Plus()) {
|
||||
byte[] strBytes = extractBytes(s);
|
||||
byte coder = StringUtils.getStringCoder(s);
|
||||
long utfLength = AppendableUtil.findUtf8Length(strBytes, coder);
|
||||
writeStopBit(utfLength);
|
||||
appendUtf8(strBytes, 0, s.length(), coder);
|
||||
} else {
|
||||
char[] chars = extractChars(s);
|
||||
long utfLength = AppendableUtil.findUtf8Length(chars);
|
||||
writeStopBit(utfLength);
|
||||
if (utfLength == chars.length)
|
||||
append8bit(chars);
|
||||
else
|
||||
appendUtf8(chars, 0, chars.length);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void append8bit(char[] chars) throws BufferOverflowException, IllegalArgumentException {
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
bytesStore.writeByte(writePosition++, (byte) c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> appendUtf8(char[] chars, int offset, int length) throws BufferOverflowException, IllegalArgumentException {
|
||||
int i;
|
||||
ascii:
|
||||
{
|
||||
for (i = 0; i < length; i++) {
|
||||
char c = chars[offset + i];
|
||||
if (c > 0x007F)
|
||||
break ascii;
|
||||
bytesStore.writeByte(writePosition++, (byte) c);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
char c = chars[offset + i];
|
||||
BytesInternal.appendUtf8Char(this, c);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(long offsetInRDO, ByteBuffer bytes, int offset, int length) throws BufferOverflowException {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,930 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.bytes.algo.BytesStoreHash;
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.Memory;
|
||||
import net.openhft.chronicle.core.OS;
|
||||
import net.openhft.chronicle.core.annotation.ForceInline;
|
||||
import net.openhft.chronicle.core.io.AbstractReferenceCounted;
|
||||
import net.openhft.chronicle.core.io.BackgroundResourceReleaser;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Fast unchecked version of AbstractBytes
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class UncheckedNativeBytes<Underlying>
|
||||
extends AbstractReferenceCounted
|
||||
implements Bytes<Underlying> {
|
||||
protected final long capacity;
|
||||
|
||||
private final Bytes<Underlying> underlyingBytes;
|
||||
|
||||
protected NativeBytesStore<Underlying> bytesStore;
|
||||
protected long readPosition;
|
||||
protected long writePosition;
|
||||
protected long writeLimit;
|
||||
private int lastDecimalPlaces = 0;
|
||||
|
||||
public UncheckedNativeBytes( Bytes<Underlying> underlyingBytes)
|
||||
throws IllegalStateException {
|
||||
this.underlyingBytes = underlyingBytes;
|
||||
underlyingBytes.reserve(this);
|
||||
this.bytesStore = (NativeBytesStore<Underlying>) underlyingBytes.bytesStore();
|
||||
assert bytesStore.start() == 0;
|
||||
writePosition = underlyingBytes.writePosition();
|
||||
writeLimit = underlyingBytes.writeLimit();
|
||||
readPosition = underlyingBytes.readPosition();
|
||||
capacity = bytesStore.capacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ensureCapacity(long size) throws IllegalArgumentException {
|
||||
if (size > realCapacity()) {
|
||||
underlyingBytes.ensureCapacity(size);
|
||||
bytesStore = (NativeBytesStore<Underlying>) underlyingBytes.bytesStore();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unchecked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectMemory() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Bytes<Underlying> unchecked(boolean unchecked) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(long from, long to, long length) {
|
||||
bytesStore.move(from - start(), to - start(), length);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> compact() {
|
||||
long start = start();
|
||||
long readRemaining = readRemaining();
|
||||
if (readRemaining > 0 && start < readPosition) {
|
||||
bytesStore.move(readPosition, start, readRemaining);
|
||||
readPosition = start;
|
||||
writePosition = readPosition + readRemaining;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> readPosition(long position) {
|
||||
readPosition = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> readLimit(long limit) {
|
||||
writePosition = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writePosition(long position) {
|
||||
writePosition = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> readSkip(long bytesToSkip) {
|
||||
readPosition += bytesToSkip;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readVolatileByte(long offset) throws BufferUnderflowException {
|
||||
return bytesStore.readVolatileByte(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readVolatileShort(long offset) throws BufferUnderflowException {
|
||||
return bytesStore.readVolatileShort(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readVolatileInt(long offset) throws BufferUnderflowException {
|
||||
return bytesStore.readVolatileInt(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readVolatileLong(long offset) throws BufferUnderflowException {
|
||||
return bytesStore.readVolatileLong(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncheckedReadSkipOne() {
|
||||
readPosition++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncheckedReadSkipBackOne() {
|
||||
readPosition--;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeSkip(long bytesToSkip) {
|
||||
writePosition += bytesToSkip;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> writeLimit(long limit) {
|
||||
writeLimit = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BytesStore<Bytes<Underlying>, Underlying> copy() {
|
||||
throw new UnsupportedOperationException("todo");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isElastic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected long readOffsetPositionMoved(long adding) {
|
||||
long offset = readPosition;
|
||||
readPosition += adding;
|
||||
return offset;
|
||||
}
|
||||
|
||||
protected long writeOffsetPositionMoved(long adding) {
|
||||
return writeOffsetPositionMoved(adding, adding);
|
||||
}
|
||||
|
||||
protected long writeOffsetPositionMoved(long adding, long advance) {
|
||||
long oldPosition = writePosition;
|
||||
long writeEnd = oldPosition + adding;
|
||||
assert writeEnd <= bytesStore.safeLimit();
|
||||
writePosition += advance;
|
||||
return oldPosition;
|
||||
}
|
||||
|
||||
protected long prewriteOffsetPositionMoved(long substracting) {
|
||||
return readPosition -= substracting;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> write( RandomDataInput bytes, long offset, long length)
|
||||
throws BufferUnderflowException, BufferOverflowException {
|
||||
if (length == 8) {
|
||||
writeLong(bytes.readLong(offset));
|
||||
|
||||
} else if (length >= 16 && bytes.isDirectMemory()) {
|
||||
rawCopy(bytes, offset, length);
|
||||
|
||||
} else {
|
||||
BytesInternal.writeFully(bytes, offset, length, this);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public long rawCopy( RandomDataInput bytes, long offset, long length)
|
||||
throws BufferOverflowException, BufferUnderflowException {
|
||||
long len = Math.min(writeRemaining(), Math.min(bytes.capacity() - offset, length));
|
||||
if (len > 0) {
|
||||
writeCheckOffset(writePosition(), len);
|
||||
this.throwExceptionIfReleased();
|
||||
OS.memory().copyMemory(bytes.addressForRead(offset), addressForWritePosition(), len);
|
||||
writeSkip(len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Bytes<Underlying> clear() {
|
||||
readPosition = writePosition = start();
|
||||
writeLimit = capacity();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> clearAndPad(long length) throws BufferOverflowException {
|
||||
if (start() + length > capacity())
|
||||
throw new BufferOverflowException();
|
||||
readPosition = writePosition = start() + length;
|
||||
writeLimit = capacity();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long readLimit() {
|
||||
return writePosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long writeLimit() {
|
||||
return writeLimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long realCapacity() {
|
||||
return bytesStore.realCapacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long realWriteRemaining() {
|
||||
return writeRemaining();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long capacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Underlying underlyingObject() {
|
||||
return bytesStore.underlyingObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long readPosition() {
|
||||
return readPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long writePosition() {
|
||||
return writePosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public boolean compareAndSwapInt(long offset, int expected, int value)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 4);
|
||||
return bytesStore.compareAndSwapInt(offset, expected, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testAndSetInt(long offset, int expected, int value) {
|
||||
writeCheckOffset(offset, 4);
|
||||
bytesStore.testAndSetInt(offset, expected, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public boolean compareAndSwapLong(long offset, long expected, long value)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 8);
|
||||
return bytesStore.compareAndSwapLong(offset, expected, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performRelease() {
|
||||
this.underlyingBytes.release(this);
|
||||
// need to wait as checks rely on this completing.
|
||||
BackgroundResourceReleaser.releasePendingResources();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedByte() {
|
||||
long offset = readOffsetPositionMoved(1);
|
||||
return bytesStore.memory.readByte(bytesStore.address + offset) & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int uncheckedReadUnsignedByte() {
|
||||
return readUnsignedByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public byte readByte() {
|
||||
long offset = readOffsetPositionMoved(1);
|
||||
return bytesStore.memory.readByte(bytesStore.address + offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public int peekUnsignedByte() {
|
||||
try {
|
||||
return readRemaining() > 0 ? bytesStore.readUnsignedByte(readPosition) : -1;
|
||||
|
||||
} catch (BufferUnderflowException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public short readShort() {
|
||||
long offset = readOffsetPositionMoved(2);
|
||||
return bytesStore.readShort(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public int readInt() {
|
||||
long offset = readOffsetPositionMoved(4);
|
||||
return bytesStore.readInt(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long readLong() {
|
||||
long offset = readOffsetPositionMoved(8);
|
||||
return bytesStore.readLong(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public float readFloat() {
|
||||
long offset = readOffsetPositionMoved(4);
|
||||
return bytesStore.readFloat(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public double readDouble() {
|
||||
long offset = readOffsetPositionMoved(8);
|
||||
return bytesStore.readDouble(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public int readVolatileInt() {
|
||||
long offset = readOffsetPositionMoved(4);
|
||||
return bytesStore.readVolatileInt(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long readVolatileLong() {
|
||||
long offset = readOffsetPositionMoved(8);
|
||||
return bytesStore.readVolatileLong(offset);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeByte(long offset, byte i) throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 1);
|
||||
bytesStore.writeByte(offset, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeShort(long offset, short i) throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 2);
|
||||
bytesStore.writeShort(offset, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeInt(long offset, int i) throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 4);
|
||||
bytesStore.writeInt(offset, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeOrderedInt(long offset, int i) throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 4);
|
||||
bytesStore.writeOrderedInt(offset, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeLong(long offset, long i) throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 8);
|
||||
bytesStore.writeLong(offset, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeOrderedLong(long offset, long i) throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 8);
|
||||
bytesStore.writeOrderedLong(offset, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeFloat(long offset, float d) throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 4);
|
||||
bytesStore.writeFloat(offset, d);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeDouble(long offset, double d) throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 8);
|
||||
bytesStore.writeDouble(offset, d);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeVolatileByte(long offset, byte i8)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 1);
|
||||
bytesStore.writeVolatileByte(offset, i8);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeVolatileShort(long offset, short i16)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 2);
|
||||
bytesStore.writeVolatileShort(offset, i16);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeVolatileInt(long offset, int i32)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 4);
|
||||
bytesStore.writeVolatileInt(offset, i32);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeVolatileLong(long offset, long i64)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offset, 8);
|
||||
bytesStore.writeVolatileLong(offset, i64);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ForceInline
|
||||
public Bytes<Underlying> write(long offsetInRDO, byte[] bytes, int offset, int length)
|
||||
throws BufferOverflowException {
|
||||
writeCheckOffset(offsetInRDO, length);
|
||||
bytesStore.write(offsetInRDO, bytes, offset, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public void write(long offsetInRDO, ByteBuffer bytes, int offset, int length) throws BufferOverflowException {
|
||||
writeCheckOffset(offsetInRDO, length);
|
||||
bytesStore.write(offsetInRDO, bytes, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ForceInline
|
||||
public Bytes<Underlying> write(long writeOffset,
|
||||
RandomDataInput bytes, long readOffset, long length)
|
||||
throws BufferUnderflowException, BufferOverflowException {
|
||||
writeCheckOffset(writeOffset, length);
|
||||
bytesStore.write(writeOffset, bytes, readOffset, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
void writeCheckOffset(long offset, long adding) throws BufferOverflowException {
|
||||
// assert writeCheckOffset0(offset, adding);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public byte readByte(long offset) {
|
||||
return bytesStore.readByte(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedByte(long offset) {
|
||||
return bytesStore.memory.readByte(bytesStore.address + offset) & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int peekUnsignedByte(long offset) {
|
||||
return offset >= writePosition ? -1 : readByte(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public short readShort(long offset) {
|
||||
return bytesStore.readShort(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public int readInt(long offset) {
|
||||
return bytesStore.readInt(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public long readLong(long offset) {
|
||||
return bytesStore.readLong(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public float readFloat(long offset) {
|
||||
return bytesStore.readFloat(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public double readDouble(long offset) {
|
||||
return bytesStore.readDouble(offset);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeByte(byte i8) {
|
||||
long offset = writeOffsetPositionMoved(1);
|
||||
bytesStore.memory.writeByte(bytesStore.address + offset, i8);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> prewriteByte(byte i8) {
|
||||
long offset = prewriteOffsetPositionMoved(1);
|
||||
bytesStore.memory.writeByte(bytesStore.address + offset, i8);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeShort(short i16) {
|
||||
long offset = writeOffsetPositionMoved(2);
|
||||
bytesStore.writeShort(offset, i16);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> prewriteShort(short i16) {
|
||||
long offset = prewriteOffsetPositionMoved(2);
|
||||
bytesStore.writeShort(offset, i16);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeInt(int i) {
|
||||
long offset = writeOffsetPositionMoved(4);
|
||||
bytesStore.writeInt(offset, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeIntAdv(int i, int advance) {
|
||||
long offset = writeOffsetPositionMoved(4, advance);
|
||||
bytesStore.writeInt(offset, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> prewriteInt(int i) {
|
||||
long offset = prewriteOffsetPositionMoved(4);
|
||||
bytesStore.writeInt(offset, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeLong(long i64) {
|
||||
long offset = writeOffsetPositionMoved(8);
|
||||
bytesStore.writeLong(offset, i64);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeLongAdv(long i64, int advance) {
|
||||
long offset = writeOffsetPositionMoved(8, advance);
|
||||
bytesStore.writeLong(offset, i64);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> prewriteLong(long i64) {
|
||||
long offset = prewriteOffsetPositionMoved(8);
|
||||
bytesStore.writeLong(offset, i64);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeFloat(float f) {
|
||||
long offset = writeOffsetPositionMoved(4);
|
||||
bytesStore.writeFloat(offset, f);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeDouble(double d) {
|
||||
long offset = writeOffsetPositionMoved(8);
|
||||
bytesStore.writeDouble(offset, d);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeDoubleAndInt(double d, int i) {
|
||||
long offset = writeOffsetPositionMoved(12);
|
||||
bytesStore.writeDouble(offset, d);
|
||||
bytesStore.writeInt(offset + 8, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> write( byte[] bytes, int offset, int length) {
|
||||
if (length + offset > bytes.length)
|
||||
throw new ArrayIndexOutOfBoundsException("bytes.length=" + bytes.length + ", " +
|
||||
"length=" + length + ", offset=" + offset);
|
||||
if (length > writeRemaining())
|
||||
throw new BufferOverflowException();
|
||||
long offsetInRDO = writeOffsetPositionMoved(length);
|
||||
bytesStore.write(offsetInRDO, bytes, offset, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> prewrite( byte[] bytes) {
|
||||
long offsetInRDO = prewriteOffsetPositionMoved(bytes.length);
|
||||
bytesStore.write(offsetInRDO, bytes);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> prewrite( BytesStore bytes) {
|
||||
long offsetInRDO = prewriteOffsetPositionMoved(bytes.length());
|
||||
bytesStore.write(offsetInRDO, bytes);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeSome( ByteBuffer buffer) {
|
||||
bytesStore.write(writePosition, buffer, buffer.position(), buffer.limit());
|
||||
writePosition += buffer.remaining();
|
||||
assert writePosition <= writeLimit();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeOrderedInt(int i) {
|
||||
long offset = writeOffsetPositionMoved(4);
|
||||
bytesStore.writeOrderedInt(offset, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public Bytes<Underlying> writeOrderedLong(long i) {
|
||||
long offset = writeOffsetPositionMoved(8);
|
||||
bytesStore.writeOrderedLong(offset, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForRead(long offset) throws BufferUnderflowException {
|
||||
return bytesStore.addressForRead(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForWrite(long offset) throws BufferOverflowException {
|
||||
return bytesStore.addressForWrite(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addressForWritePosition() throws UnsupportedOperationException, BufferOverflowException {
|
||||
return bytesStore.addressForWrite(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return BytesStoreHash.hash32(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Bytes)) return false;
|
||||
Bytes b2 = (Bytes) obj;
|
||||
long remaining = readRemaining();
|
||||
return b2.readRemaining() == remaining && equalsBytes(b2, remaining);
|
||||
}
|
||||
|
||||
public boolean equalsBytes( Bytes b2, long remaining) {
|
||||
long i = 0;
|
||||
try {
|
||||
for (; i < remaining - 7; i += 8)
|
||||
if (readLong(readPosition() + i) != b2.readLong(b2.readPosition() + i))
|
||||
return false;
|
||||
for (; i < remaining; i++)
|
||||
if (readByte(readPosition() + i) != b2.readByte(b2.readPosition() + i))
|
||||
return false;
|
||||
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw Jvm.rethrow(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return BytesInternal.toString(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void lenient(boolean lenient) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lenient() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public void nativeRead(long position, long address, long size) {
|
||||
bytesStore.nativeRead(position, address, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public void nativeWrite(long address, long position, long size) {
|
||||
bytesStore.nativeWrite(address, position, size);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BytesStore bytesStore() {
|
||||
return bytesStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int byteCheckSum() throws IORuntimeException {
|
||||
NativeBytesStore bytesStore = (NativeBytesStore) bytesStore();
|
||||
return bytesStore.byteCheckSum(readPosition(), readLimit());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Bytes<Underlying> append8bit( CharSequence cs)
|
||||
throws BufferOverflowException, BufferUnderflowException {
|
||||
if (cs instanceof BytesStore) {
|
||||
return write((BytesStore) cs);
|
||||
}
|
||||
int length = cs.length();
|
||||
long offset = writeOffsetPositionMoved(length);
|
||||
long address = bytesStore.addressForWrite(offset);
|
||||
Memory memory = bytesStore.memory;
|
||||
assert memory != null;
|
||||
try {
|
||||
int i = 0;
|
||||
for (; i < length - 1; i += 2) {
|
||||
char c = cs.charAt(i);
|
||||
char c2 = cs.charAt(i + 1);
|
||||
memory.writeByte(address + i, (byte) c);
|
||||
memory.writeByte(address + i + 1, (byte) c2);
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
char c = cs.charAt(i);
|
||||
memory.writeByte(address + i, (byte) c);
|
||||
}
|
||||
|
||||
return this;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> appendUtf8(char[] chars, int offset, int length) throws BufferOverflowException, IllegalArgumentException {
|
||||
ensureCapacity(length);
|
||||
NativeBytesStore nbs = this.bytesStore;
|
||||
long position = nbs.appendUtf8(writePosition(), chars, offset, length);
|
||||
writePosition(position);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastDecimalPlaces() {
|
||||
return lastDecimalPlaces;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lastDecimalPlaces(int lastDecimalPlaces) {
|
||||
this.lastDecimalPlaces = Math.max(0, lastDecimalPlaces);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> write( RandomDataInput bytes) {
|
||||
assert bytes != this : "you should not write to yourself !";
|
||||
|
||||
try {
|
||||
return write(bytes, bytes.readPosition(), Math.min(writeRemaining(), bytes.readRemaining()));
|
||||
} catch (BufferOverflowException | BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package net.openhft.chronicle.bytes;
|
||||
|
||||
/**
|
||||
* Represents an operation that accepts a single input argument then modifies that same instance.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface UpdateInterceptor {
|
||||
|
||||
/**
|
||||
* modifies {@code t} with changed data
|
||||
*
|
||||
* @param methodName the name of the method
|
||||
* @param t the input argument - for a method call with multiple arguments, the last one is passed
|
||||
* @return whether to proceed. If false, don't write
|
||||
*/
|
||||
boolean update(String methodName, Object t);
|
||||
|
||||
}
|
|
@ -0,0 +1,597 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.Jvm;
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import net.openhft.chronicle.core.Memory;
|
||||
import net.openhft.chronicle.core.OS;
|
||||
import net.openhft.chronicle.core.annotation.Java9;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import net.openhft.chronicle.core.util.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static net.openhft.chronicle.bytes.NoBytesStore.noBytesStore;
|
||||
|
||||
/**
|
||||
* Simple Bytes implementation which is not Elastic.
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class VanillaBytes<Underlying>
|
||||
extends AbstractBytes<Underlying>
|
||||
implements Byteable<Bytes<Underlying>, Underlying>, Comparable<CharSequence> {
|
||||
|
||||
public VanillaBytes( BytesStore bytesStore) throws IllegalStateException {
|
||||
this(bytesStore, bytesStore.writePosition(), bytesStore.writeLimit());
|
||||
}
|
||||
|
||||
public VanillaBytes( BytesStore bytesStore, long writePosition, long writeLimit) throws IllegalStateException {
|
||||
super(bytesStore, writePosition, writeLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a non elastic bytes.
|
||||
*/
|
||||
|
||||
public static VanillaBytes<Void> vanillaBytes() {
|
||||
try {
|
||||
return new VanillaBytes<>(noBytesStore());
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Java9
|
||||
private static boolean isEqual0( byte[] bytes, byte coder, NativeBytesStore bs, long address) {
|
||||
|
||||
Memory memory = bs.memory;
|
||||
|
||||
if (coder == 0) {
|
||||
int i = 0;
|
||||
for (; i < bytes.length; i++) {
|
||||
byte b = memory.readByte(address + i);
|
||||
char c = (char) (bytes[i] & 0xFF);
|
||||
if (b != c) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int i = 0;
|
||||
for (; i < bytes.length; i++) {
|
||||
byte b = memory.readByte(address + i);
|
||||
char c = (char) (((bytes[i + 1] & 0xFF) << 8) | (bytes[i] & 0xFF));
|
||||
|
||||
if (b != c) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isEqual0( char[] chars, NativeBytesStore bs, long address) {
|
||||
|
||||
Memory memory = bs.memory;
|
||||
int i = 0;
|
||||
for (; i < chars.length - 3; i += 4) {
|
||||
int b = memory.readInt(address + i);
|
||||
int b0 = b & 0xFF;
|
||||
int b1 = (b >> 8) & 0xFF;
|
||||
int b2 = (b >> 16) & 0xFF;
|
||||
int b3 = (b >> 24) & 0xFF;
|
||||
if (b0 != chars[i] || b1 != chars[i + 1] || b2 != chars[i + 2] || b3 != chars[i + 3])
|
||||
return false;
|
||||
}
|
||||
for (; i < chars.length; i++) {
|
||||
int b = memory.readByte(address + i) & 0xFF;
|
||||
if (b != chars[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isEqual1( char[] chars, BytesStore bytesStore, long readPosition) throws BufferUnderflowException {
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
int b = bytesStore.readByte(readPosition + i) & 0xFF;
|
||||
if (b != chars[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Java9
|
||||
private static boolean isEqual1( byte[] bytes, byte coder, BytesStore bytesStore, long readPosition) throws BufferUnderflowException {
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
int b = bytesStore.readByte(readPosition + i) & 0xFF;
|
||||
char c;
|
||||
|
||||
if (coder == 0) {
|
||||
c = (char) (bytes[i] & 0xFF);
|
||||
} else {
|
||||
c = (char) (((bytes[i + 1] & 0xFF) << 8) | (bytes[i] & 0xFF));
|
||||
i++;
|
||||
}
|
||||
|
||||
if (b != c)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readVolatileLong(long offset) throws BufferUnderflowException {
|
||||
readCheckOffset(offset, 8, true);
|
||||
return bytesStore.readVolatileLong(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bytesStore( BytesStore<Bytes<Underlying>, Underlying> byteStore, long offset, long length)
|
||||
throws IllegalStateException, BufferOverflowException, BufferUnderflowException {
|
||||
setBytesStore(byteStore);
|
||||
// assume its read-only
|
||||
readLimit(offset + length);
|
||||
writeLimit(offset + length);
|
||||
readPosition(offset);
|
||||
}
|
||||
|
||||
private void setBytesStore( BytesStore<Bytes<Underlying>, Underlying> bytesStore)
|
||||
throws IllegalStateException {
|
||||
if (this.bytesStore != bytesStore) {
|
||||
BytesStore oldBS = this.bytesStore;
|
||||
this.bytesStore(bytesStore);
|
||||
bytesStore.reserve(this);
|
||||
oldBS.release(this);
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long offset() {
|
||||
return readPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long maxSize() {
|
||||
return readRemaining();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isElastic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> bytesForRead() throws IllegalStateException {
|
||||
return isClear()
|
||||
? new VanillaBytes<>(bytesStore, writePosition(), bytesStore.writeLimit())
|
||||
: new SubBytes<>(bytesStore, readPosition(), readLimit());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEqual( String s) {
|
||||
if (s == null || s.length() != readRemaining()) return false;
|
||||
|
||||
try {
|
||||
if (Jvm.isJava9Plus()) {
|
||||
byte[] bytes = StringUtils.extractBytes(s);
|
||||
byte coder = StringUtils.getStringCoder(s);
|
||||
if (bytesStore instanceof NativeBytesStore) {
|
||||
NativeBytesStore bs = (NativeBytesStore) this.bytesStore;
|
||||
long address = bs.addressForRead(readPosition);
|
||||
return isEqual0(bytes, coder, bs, address);
|
||||
|
||||
} else {
|
||||
return isEqual1(bytes, coder, bytesStore, readPosition);
|
||||
}
|
||||
} else {
|
||||
char[] chars = StringUtils.extractChars(s);
|
||||
if (bytesStore instanceof NativeBytesStore) {
|
||||
NativeBytesStore bs = (NativeBytesStore) this.bytesStore;
|
||||
long address = bs.addressForRead(readPosition);
|
||||
return isEqual0(chars, bs, address);
|
||||
|
||||
} else {
|
||||
return isEqual1(chars, bytesStore, readPosition);
|
||||
}
|
||||
}
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long realCapacity() {
|
||||
return bytesStore.realCapacity();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BytesStore<Bytes<Underlying>, Underlying> copy() {
|
||||
if (bytesStore.underlyingObject() instanceof ByteBuffer) {
|
||||
try {
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(Maths.toInt32(readRemaining()));
|
||||
ByteBuffer bbu = (ByteBuffer) bytesStore.underlyingObject();
|
||||
ByteBuffer slice = bbu.slice();
|
||||
slice.position((int) readPosition());
|
||||
slice.limit((int) readLimit());
|
||||
bb.put(slice);
|
||||
bb.clear();
|
||||
return (BytesStore) BytesStore.wrap(bb);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
} else {
|
||||
return (BytesStore) NativeBytes.copyOf(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> write( RandomDataInput bytes, long offset, long length)
|
||||
throws BufferOverflowException, BufferUnderflowException, IllegalArgumentException {
|
||||
optimisedWrite(bytes, offset, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void optimisedWrite( RandomDataInput bytes, long offset, long length) {
|
||||
if (length <= safeCopySize() && isDirectMemory() && bytes.isDirectMemory()) {
|
||||
long len = Math.min(writeRemaining(), Math.min(bytes.capacity() - offset, length));
|
||||
if (len > 0) {
|
||||
writeCheckOffset(writePosition(), len);
|
||||
long address = bytes.addressForRead(offset);
|
||||
long address2 = addressForWritePosition();
|
||||
assert address != 0;
|
||||
assert address2 != 0;
|
||||
OS.memory().copyMemory(address, address2, len);
|
||||
writeSkip(len);
|
||||
}
|
||||
} else {
|
||||
super.write(bytes, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(long position, CharSequence str, int offset, int length)
|
||||
throws BufferOverflowException, IllegalArgumentException {
|
||||
|
||||
ensureCapacity(length);
|
||||
if (offset + length > str.length())
|
||||
throw new IllegalArgumentException("offset=" + offset + " + length=" + length + " > str.length =" + str.length());
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
bytesStore.writeByte(position + i, str.charAt(offset + i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public VanillaBytes append( CharSequence str, int start, int end) throws IndexOutOfBoundsException {
|
||||
assert end > start : "end=" + end + ",start=" + start;
|
||||
try {
|
||||
if (isDirectMemory()) {
|
||||
if (str instanceof BytesStore) {
|
||||
|
||||
write((BytesStore) str, (long) start, end - start);
|
||||
return this;
|
||||
}
|
||||
if (str instanceof String) {
|
||||
if (Jvm.isJava9Plus()) {
|
||||
byte coder = StringUtils.getStringCoder((String) str);
|
||||
appendUtf8(StringUtils.extractBytes((String) str), start, end - start, coder);
|
||||
} else {
|
||||
appendUtf8(StringUtils.extractChars((String) str), start, end - start);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
super.append(str, start, end);
|
||||
return this;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new IndexOutOfBoundsException(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public VanillaBytes appendUtf8( CharSequence str) throws BufferOverflowException {
|
||||
try {
|
||||
if (isDirectMemory()) {
|
||||
if (str instanceof BytesStore) {
|
||||
write((BytesStore) str, 0L, str.length());
|
||||
return this;
|
||||
}
|
||||
if (str instanceof String) {
|
||||
if (Jvm.isJava9Plus()) {
|
||||
String str1 = (String) str;
|
||||
byte coder = StringUtils.getStringCoder(str1);
|
||||
appendUtf8(StringUtils.extractBytes(str1), 0, str.length(), coder);
|
||||
} else {
|
||||
appendUtf8(StringUtils.extractChars((String) str), 0, str.length());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
super.append(str, 0, str.length());
|
||||
return this;
|
||||
|
||||
} catch (Exception e) {
|
||||
BufferOverflowException e2 = new BufferOverflowException();
|
||||
e2.initCause(e);
|
||||
throw e2;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Bytes<Underlying> append8bit( CharSequence cs)
|
||||
throws BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException {
|
||||
if (cs instanceof RandomDataInput)
|
||||
return write((RandomDataInput) cs);
|
||||
|
||||
if (isDirectMemory() && cs instanceof String)
|
||||
return append8bitNBS_S((String) cs);
|
||||
return append8bit0(cs);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Bytes<Underlying> append8bit( BytesStore bs)
|
||||
throws BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException {
|
||||
long remaining = bs.readLimit() - bs.readPosition();
|
||||
return write(bs, 0L, remaining);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> write( BytesStore bytes, long offset, long length) throws BufferOverflowException, BufferUnderflowException {
|
||||
if (bytes.canReadDirect(length) && canWriteDirect(length) && length == (int) length) {
|
||||
long wAddr = addressForWritePosition();
|
||||
writeSkip(length);
|
||||
long rAddr = bytes.addressForRead(offset);
|
||||
BytesInternal.copyMemory(rAddr, wAddr, (int) length);
|
||||
|
||||
} else {
|
||||
BytesInternal.writeFully(bytes, offset, length, this);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Bytes<Underlying> append8bit( String cs)
|
||||
throws BufferOverflowException, BufferUnderflowException, IndexOutOfBoundsException {
|
||||
if (isDirectMemory())
|
||||
return append8bitNBS_S(cs);
|
||||
return append8bit0(cs);
|
||||
}
|
||||
|
||||
|
||||
private Bytes<Underlying> append8bitNBS_S( String s) throws BufferOverflowException {
|
||||
int length = s.length();
|
||||
long offset = writeOffsetPositionMoved(length); // can re-assign the byteStore if not large enough.
|
||||
NativeBytesStore bytesStore = (NativeBytesStore) this.bytesStore;
|
||||
final long address = bytesStore.address + bytesStore.translate(offset);
|
||||
final Memory memory = bytesStore.memory;
|
||||
|
||||
if (memory == null)
|
||||
bytesStore.throwExceptionIfReleased();
|
||||
|
||||
if (Jvm.isJava9Plus()) {
|
||||
final byte[] chars = StringUtils.extractBytes(s);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < length; i++) {
|
||||
memory.writeByte(address + i, chars[i]);
|
||||
}
|
||||
} else {
|
||||
final char[] chars = StringUtils.extractChars(s);
|
||||
int i;
|
||||
for (i = 0; i < length - 3; i += 4) {
|
||||
int c0 = chars[i] & 0xFF;
|
||||
int c1 = chars[i + 1] & 0xFF;
|
||||
int c2 = chars[i + 2] & 0xFF;
|
||||
int c3 = chars[i + 3] & 0xFF;
|
||||
memory.writeInt(address + i, c0 | (c1 << 8) | (c2 << 16) | (c3 << 24));
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
int c0 = chars[i];
|
||||
memory.writeByte(address + i, (byte) c0);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return bytesStore instanceof NativeBytesStore
|
||||
? toString2((NativeBytesStore) bytesStore)
|
||||
: toString0();
|
||||
}
|
||||
|
||||
private String toString2( NativeBytesStore bytesStore) {
|
||||
int length = (int)
|
||||
Math.min(Bytes.MAX_HEAP_CAPACITY, readRemaining());
|
||||
char[] chars = new char[length];
|
||||
final Memory memory = bytesStore.memory;
|
||||
final long address = bytesStore.address + bytesStore.translate(readPosition());
|
||||
for (int i = 0; i < length && i < realCapacity(); i++)
|
||||
chars[i] = (char) (memory.readByte(address + i) & 0xFF);
|
||||
|
||||
return StringUtils.newString(chars);
|
||||
}
|
||||
|
||||
|
||||
protected String toString0() {
|
||||
int length = (int) Math.min(Bytes.MAX_HEAP_CAPACITY, readRemaining());
|
||||
char[] chars = new char[length];
|
||||
try {
|
||||
for (int i = 0; i < length; i++) {
|
||||
chars[i] = (char) (bytesStore.readByte(readPosition() + i) & 0xFF);
|
||||
}
|
||||
} catch (BufferUnderflowException e) {
|
||||
// ignored
|
||||
}
|
||||
return StringUtils.newString(chars);
|
||||
}
|
||||
|
||||
|
||||
protected Bytes<Underlying> append8bit0( CharSequence cs) throws BufferOverflowException, IndexOutOfBoundsException {
|
||||
int length = cs.length();
|
||||
long offset = writeOffsetPositionMoved(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = cs.charAt(i);
|
||||
if (c > 255) c = '?';
|
||||
bytesStore.writeByte(offset + i, (byte) c);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equalBytes( BytesStore bytesStore, long length) throws BufferUnderflowException {
|
||||
if (isDirectMemory() &&
|
||||
bytesStore instanceof VanillaBytes &&
|
||||
bytesStore.isDirectMemory()) {
|
||||
VanillaBytes b2 = (VanillaBytes) bytesStore;
|
||||
NativeBytesStore nbs0 = (NativeBytesStore) this.bytesStore;
|
||||
NativeBytesStore nbs2 = (NativeBytesStore) b2.bytesStore();
|
||||
long i = 0;
|
||||
for (; i < length - 7; i += 8) {
|
||||
long addr0 = nbs0.address + readPosition() - nbs0.start() + i;
|
||||
long addr2 = nbs2.address + b2.readPosition() - nbs2.start() + i;
|
||||
long l0 = nbs0.memory.readLong(addr0);
|
||||
long l2 = nbs2.memory.readLong(addr2);
|
||||
if (l0 != l2)
|
||||
return false;
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
long offset2 = readPosition() + i - nbs0.start();
|
||||
long offset21 = b2.readPosition() + i - nbs2.start();
|
||||
byte b0 = nbs0.memory.readByte(nbs0.address + offset2);
|
||||
byte b1 = nbs2.memory.readByte(nbs2.address + offset21);
|
||||
if (b0 != b1)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return super.equalBytes(bytesStore, length);
|
||||
}
|
||||
}
|
||||
|
||||
public void read8Bit(char[] chars, int length) {
|
||||
if (isDirectMemory()) {
|
||||
long position = readPosition();
|
||||
NativeBytesStore nbs = (NativeBytesStore) bytesStore();
|
||||
nbs.read8bit(position, chars, length);
|
||||
} else {
|
||||
long pos = this.readPosition();
|
||||
for (int i = 0; i < length; i++)
|
||||
chars[i] = (char) this.readUnsignedByte(pos + i);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: protected?
|
||||
@Override
|
||||
public int byteCheckSum(int start, int end) throws IORuntimeException {
|
||||
byte b = 0;
|
||||
// the below cast is safe as should only be called from net.openhft.chronicle.bytes.AbstractBytes.byteCheckSum(long, long)
|
||||
NativeBytesStore bytesStore = (NativeBytesStore) bytesStore();
|
||||
Memory memory = bytesStore.memory;
|
||||
assert memory != null;
|
||||
long addr = bytesStore.addressForRead(start);
|
||||
int i = 0, len = end - start;
|
||||
for (; i < len - 3; i += 4) {
|
||||
b += memory.readByte(addr + i)
|
||||
+ memory.readByte(addr + i + 1)
|
||||
+ memory.readByte(addr + i + 2)
|
||||
+ memory.readByte(addr + i + 3);
|
||||
}
|
||||
for (; i < len; i++) {
|
||||
b += memory.readByte(addr + i);
|
||||
}
|
||||
return b & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Bytes<Underlying> appendUtf8(char[] chars, int offset, int length) throws BufferOverflowException, IllegalArgumentException {
|
||||
ensureCapacity(length);
|
||||
if (bytesStore instanceof NativeBytesStore) {
|
||||
NativeBytesStore nbs = (NativeBytesStore) this.bytesStore;
|
||||
long position = nbs.appendUtf8(writePosition(), chars, offset, length);
|
||||
writePosition(position);
|
||||
} else {
|
||||
super.appendUtf8(chars, offset, length);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer toTemporaryDirectByteBuffer() throws IllegalArgumentException {
|
||||
if (isClear())
|
||||
return bytesStore.toTemporaryDirectByteBuffer();
|
||||
return super.toTemporaryDirectByteBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read( byte[] bytes) {
|
||||
int len = (int) Math.min(bytes.length, readRemaining());
|
||||
if (bytesStore instanceof NativeBytesStore) {
|
||||
NativeBytesStore nbs = (NativeBytesStore) this.bytesStore;
|
||||
long len2 = nbs.read(readPosition(), bytes, 0, len);
|
||||
try {
|
||||
readSkip(len2);
|
||||
} catch (BufferUnderflowException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return (int) (len2);
|
||||
}
|
||||
return super.read(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo( CharSequence cs) {
|
||||
long len1 = readRemaining();
|
||||
int len2 = cs.length();
|
||||
long lim = Math.min(len1, len2);
|
||||
|
||||
int k = 0;
|
||||
while (k < lim) {
|
||||
char c1 = bytesStore.charAt(k);
|
||||
char c2 = cs.charAt(k);
|
||||
if (c1 != c2) {
|
||||
return c1 - c2;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
return (int) (len1 - len2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes;
|
||||
|
||||
import net.openhft.chronicle.core.annotation.DontChain;
|
||||
|
||||
/**
|
||||
* Write data directly as Bytes.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@FunctionalInterface
|
||||
@DontChain
|
||||
public interface WriteBytesMarshallable extends CommonMarshallable {
|
||||
/**
|
||||
* Write to Bytes. This can be used as an interface to extend or a lambda
|
||||
*
|
||||
* @param bytes to write to.
|
||||
*/
|
||||
void writeMarshallable(BytesOut bytes);
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes.algo;
|
||||
|
||||
import net.openhft.chronicle.bytes.BytesStore;
|
||||
import net.openhft.chronicle.bytes.NativeBytesStore;
|
||||
|
||||
import java.util.function.ToLongFunction;
|
||||
|
||||
/**
|
||||
* Simple function to derive a long hash from a BytesStore
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public interface BytesStoreHash<B extends BytesStore> extends ToLongFunction<B> {
|
||||
static long hash( BytesStore b) {
|
||||
return b.isDirectMemory() && b.bytesStore() instanceof NativeBytesStore
|
||||
? OptimisedBytesStoreHash.INSTANCE.applyAsLong(b)
|
||||
: VanillaBytesStoreHash.INSTANCE.applyAsLong(b);
|
||||
}
|
||||
|
||||
static long hash( BytesStore b, long length) {
|
||||
return b.isDirectMemory() && b.bytesStore() instanceof NativeBytesStore
|
||||
? OptimisedBytesStoreHash.INSTANCE.applyAsLong(b, length)
|
||||
: VanillaBytesStoreHash.INSTANCE.applyAsLong(b, length);
|
||||
}
|
||||
|
||||
static int hash32(BytesStore b) {
|
||||
long hash = hash(b);
|
||||
return (int) (hash ^ (hash >>> 32));
|
||||
}
|
||||
|
||||
static int hash32( BytesStore b, int length) {
|
||||
long hash = hash(b, length);
|
||||
return (int) (hash ^ (hash >>> 32));
|
||||
}
|
||||
|
||||
long applyAsLong(BytesStore bytes, long length);
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes.algo;
|
||||
|
||||
import net.openhft.chronicle.bytes.BytesStore;
|
||||
import net.openhft.chronicle.bytes.NativeBytesStore;
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import net.openhft.chronicle.core.Memory;
|
||||
import net.openhft.chronicle.core.OS;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import static net.openhft.chronicle.bytes.algo.VanillaBytesStoreHash.*;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public enum OptimisedBytesStoreHash implements BytesStoreHash<BytesStore> {
|
||||
INSTANCE;
|
||||
|
||||
|
||||
public static final Memory MEMORY = OS.memory();
|
||||
public static final boolean IS_LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
|
||||
private static final int TOP_BYTES = IS_LITTLE_ENDIAN ? 4 : 0;
|
||||
|
||||
static long applyAsLong1to7( BytesStore store, int remaining) {
|
||||
final long address = store.addressForRead(store.readPosition());
|
||||
|
||||
return hash(readIncompleteLong(address, remaining));
|
||||
}
|
||||
|
||||
static long applyAsLong8( BytesStore store) {
|
||||
final long address = store.addressForRead(store.readPosition());
|
||||
|
||||
return hash0(MEMORY.readLong(address), MEMORY.readInt(address + TOP_BYTES));
|
||||
}
|
||||
|
||||
public static long hash(long l) {
|
||||
return hash0(l, l >> 32);
|
||||
}
|
||||
|
||||
static long hash0(long l, long hi) {
|
||||
return agitate(l * K0 + hi * K1);
|
||||
}
|
||||
|
||||
static long applyAsLong9to16( BytesStore store, int remaining) {
|
||||
final NativeBytesStore bytesStore = (NativeBytesStore) store.bytesStore();
|
||||
final long address = bytesStore.addressForRead(store.readPosition());
|
||||
long h0 = (long) remaining * K0;
|
||||
|
||||
int left = remaining;
|
||||
long addrI = address;
|
||||
|
||||
long l0 = readIncompleteLong(addrI, left);
|
||||
int l0a = (int) (l0 >> 32);
|
||||
long l1 = readIncompleteLong(addrI + 8, left - 8);
|
||||
int l1a = (int) (l1 >> 32);
|
||||
final long l2 = 0;
|
||||
final int l2a = 0;
|
||||
final long l3 = 0;
|
||||
final int l3a = 0;
|
||||
|
||||
h0 += (l0 + l1a - l2a) * M0;
|
||||
long h1 = (l1 + l2a - l3a) * M1;
|
||||
long h2 = (l2 + l3a - l0a) * M2;
|
||||
long h3 = (l3 + l0a - l1a) * M3;
|
||||
|
||||
return agitate(h0) ^ agitate(h1)
|
||||
^ agitate(h2) ^ agitate(h3);
|
||||
}
|
||||
|
||||
static long applyAsLong17to32( BytesStore store, int remaining) {
|
||||
final NativeBytesStore bytesStore = (NativeBytesStore) store.bytesStore();
|
||||
final long address = bytesStore.addressForRead(store.readPosition());
|
||||
long h0 = (long) remaining * K0;
|
||||
|
||||
int left = remaining;
|
||||
long addrI = address;
|
||||
|
||||
long l0 = MEMORY.readLong(addrI);
|
||||
int l0a = MEMORY.readInt(addrI + TOP_BYTES);
|
||||
long l1 = MEMORY.readLong(addrI + 8);
|
||||
int l1a = MEMORY.readInt(addrI + 8 + TOP_BYTES);
|
||||
long l2 = readIncompleteLong(addrI + 16, left - 16);
|
||||
int l2a = (int) (l2 >> 32);
|
||||
long l3 = readIncompleteLong(addrI + 24, left - 24);
|
||||
int l3a = (int) (l3 >> 32);
|
||||
|
||||
h0 += (l0 + l1a - l2a) * M0;
|
||||
long h1 = (l1 + l2a - l3a) * M1;
|
||||
long h2 = (l2 + l3a - l0a) * M2;
|
||||
long h3 = (l3 + l0a - l1a) * M3;
|
||||
|
||||
return agitate(h0) ^ agitate(h1)
|
||||
^ agitate(h2) ^ agitate(h3);
|
||||
}
|
||||
|
||||
public static long applyAsLong32bytesMultiple( BytesStore store, int remaining) {
|
||||
final NativeBytesStore bytesStore = (NativeBytesStore) store.bytesStore();
|
||||
final long address = bytesStore.addressForRead(store.readPosition());
|
||||
long h0 = remaining * K0, h1 = 0, h2 = 0, h3 = 0;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < remaining - 31; i += 32) {
|
||||
if (i > 0) {
|
||||
h0 *= K0;
|
||||
h1 *= K1;
|
||||
h2 *= K2;
|
||||
h3 *= K3;
|
||||
}
|
||||
long addrI = address + i;
|
||||
long l0 = MEMORY.readLong(addrI);
|
||||
int l0a = MEMORY.readInt(addrI + TOP_BYTES);
|
||||
long l1 = MEMORY.readLong(addrI + 8);
|
||||
int l1a = MEMORY.readInt(addrI + 8 + TOP_BYTES);
|
||||
long l2 = MEMORY.readLong(addrI + 16);
|
||||
int l2a = MEMORY.readInt(addrI + 16 + TOP_BYTES);
|
||||
long l3 = MEMORY.readLong(addrI + 24);
|
||||
int l3a = MEMORY.readInt(addrI + 24 + TOP_BYTES);
|
||||
|
||||
h0 += (l0 + l1a - l2a) * M0;
|
||||
h1 += (l1 + l2a - l3a) * M1;
|
||||
h2 += (l2 + l3a - l0a) * M2;
|
||||
h3 += (l3 + l0a - l1a) * M3;
|
||||
}
|
||||
|
||||
return agitate(h0) ^ agitate(h1)
|
||||
^ agitate(h2) ^ agitate(h3);
|
||||
}
|
||||
|
||||
public static long applyAsLongAny( BytesStore store, long remaining) {
|
||||
final NativeBytesStore bytesStore = (NativeBytesStore) store.bytesStore();
|
||||
final long address = bytesStore.addressForRead(store.readPosition());
|
||||
long h0 = remaining * K0, h1 = 0, h2 = 0, h3 = 0;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < remaining - 31; i += 32) {
|
||||
if (i > 0) {
|
||||
h0 *= K0;
|
||||
h1 *= K1;
|
||||
h2 *= K2;
|
||||
h3 *= K3;
|
||||
}
|
||||
long addrI = address + i;
|
||||
long l0 = MEMORY.readLong(addrI);
|
||||
int l0a = MEMORY.readInt(addrI + TOP_BYTES);
|
||||
long l1 = MEMORY.readLong(addrI + 8);
|
||||
int l1a = MEMORY.readInt(addrI + 8 + TOP_BYTES);
|
||||
long l2 = MEMORY.readLong(addrI + 16);
|
||||
int l2a = MEMORY.readInt(addrI + 16 + TOP_BYTES);
|
||||
long l3 = MEMORY.readLong(addrI + 24);
|
||||
int l3a = MEMORY.readInt(addrI + 24 + TOP_BYTES);
|
||||
|
||||
h0 += (l0 + l1a - l2a) * M0;
|
||||
h1 += (l1 + l2a - l3a) * M1;
|
||||
h2 += (l2 + l3a - l0a) * M2;
|
||||
h3 += (l3 + l0a - l1a) * M3;
|
||||
}
|
||||
long left = remaining - i;
|
||||
if (left > 0) {
|
||||
if (i > 0) {
|
||||
h0 *= K0;
|
||||
h1 *= K1;
|
||||
h2 *= K2;
|
||||
h3 *= K3;
|
||||
}
|
||||
long addrI = address + i;
|
||||
if (left <= 16) {
|
||||
|
||||
long l0 = readIncompleteLong(addrI, (int) left);
|
||||
int l0a = (int) (l0 >> 32);
|
||||
long l1 = readIncompleteLong(addrI + 8, (int) (left - 8));
|
||||
int l1a = (int) (l1 >> 32);
|
||||
final long l2 = 0;
|
||||
final int l2a = 0;
|
||||
final long l3 = 0;
|
||||
final int l3a = 0;
|
||||
|
||||
h0 += (l0 + l1a - l2a) * M0;
|
||||
h1 += (l1 + l2a - l3a) * M1;
|
||||
h2 += (l2 + l3a - l0a) * M2;
|
||||
h3 += (l3 + l0a - l1a) * M3;
|
||||
|
||||
} else {
|
||||
long l0 = MEMORY.readLong(addrI);
|
||||
int l0a = MEMORY.readInt(addrI + TOP_BYTES);
|
||||
long l1 = MEMORY.readLong(addrI + 8);
|
||||
int l1a = MEMORY.readInt(addrI + 8 + TOP_BYTES);
|
||||
long l2 = readIncompleteLong(addrI + 16, (int) (left - 16));
|
||||
int l2a = (int) (l2 >> 32);
|
||||
long l3 = readIncompleteLong(addrI + 24, (int) (left - 24));
|
||||
int l3a = (int) (l3 >> 32);
|
||||
|
||||
h0 += (l0 + l1a - l2a) * M0;
|
||||
h1 += (l1 + l2a - l3a) * M1;
|
||||
h2 += (l2 + l3a - l0a) * M2;
|
||||
h3 += (l3 + l0a - l1a) * M3;
|
||||
}
|
||||
}
|
||||
|
||||
return agitate(h0) ^ agitate(h1)
|
||||
^ agitate(h2) ^ agitate(h3);
|
||||
}
|
||||
|
||||
static long readIncompleteLong(long address, int len) {
|
||||
switch (len) {
|
||||
case 1:
|
||||
return MEMORY.readByte(address);
|
||||
case 2:
|
||||
return MEMORY.readShort(address);
|
||||
case 3:
|
||||
return IS_LITTLE_ENDIAN
|
||||
? (MEMORY.readShort(address) & 0xFFFF) + ((MEMORY.readByte(address + 2) & 0xFF) << 16)
|
||||
: ((MEMORY.readShort(address) & 0xFFFF) << 8) + (MEMORY.readByte(address + 2) & 0xFF);
|
||||
case 4:
|
||||
return MEMORY.readInt(address);
|
||||
case 5:
|
||||
return IS_LITTLE_ENDIAN
|
||||
? (MEMORY.readInt(address) & 0xFFFFFFFFL) + ((long) (MEMORY.readByte(address + 4) & 0xFF) << 32)
|
||||
: ((MEMORY.readInt(address) & 0xFFFFFFFFL) << 8) + (MEMORY.readByte(address + 4) & 0xFF);
|
||||
case 6:
|
||||
return IS_LITTLE_ENDIAN
|
||||
? (MEMORY.readInt(address) & 0xFFFFFFFFL) + ((long) (MEMORY.readShort(address + 4) & 0xFFFF) << 32)
|
||||
: ((MEMORY.readInt(address) & 0xFFFFFFFFL) << 16) + (MEMORY.readShort(address + 4) & 0xFFFF);
|
||||
case 7:
|
||||
return IS_LITTLE_ENDIAN
|
||||
? (MEMORY.readInt(address) & 0xFFFFFFFFL) + ((long) (MEMORY.readShort(address + 4) & 0xFFFF) << 32) + ((long) (MEMORY.readByte(address + 6) & 0xFF) << 48)
|
||||
: ((MEMORY.readInt(address) & 0xFFFFFFFFL) << 24) + ((MEMORY.readShort(address + 4) & 0xFFFF) << 8) + (MEMORY.readByte(address + 6) & 0xFF);
|
||||
default:
|
||||
return len >= 8 ? MEMORY.readLong(address) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long applyAsLong( BytesStore store) {
|
||||
final int remaining = Maths.toInt32(store.readRemaining());
|
||||
return applyAsLong(store, remaining);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long applyAsLong( BytesStore store, long remaining) {
|
||||
if (remaining <= 16) {
|
||||
if (remaining == 0) {
|
||||
return 0;
|
||||
} else if (remaining < 8) {
|
||||
return applyAsLong1to7(store, (int) remaining);
|
||||
} else if (remaining == 8) {
|
||||
return applyAsLong8(store);
|
||||
} else {
|
||||
return applyAsLong9to16(store, (int) remaining);
|
||||
}
|
||||
} else if (remaining <= 32) {
|
||||
return applyAsLong17to32(store, (int) remaining);
|
||||
} else if ((remaining & 31) == 0) {
|
||||
return applyAsLong32bytesMultiple(store, (int) remaining);
|
||||
} else {
|
||||
return applyAsLongAny(store, remaining);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes.algo;
|
||||
|
||||
import net.openhft.chronicle.bytes.BytesStore;
|
||||
import net.openhft.chronicle.core.Maths;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public enum VanillaBytesStoreHash implements BytesStoreHash<BytesStore> {
|
||||
INSTANCE;
|
||||
|
||||
public static final int K0 = 0x6d0f27bd;
|
||||
public static final int K1 = 0xc1f3bfc9;
|
||||
public static final int K2 = 0x6b192397;
|
||||
public static final int K3 = 0x6b915657;
|
||||
public static final int M0 = 0x5bc80bad;
|
||||
public static final int M1 = 0xea7585d7;
|
||||
public static final int M2 = 0x7a646e19;
|
||||
public static final int M3 = 0x855dd4db;
|
||||
private static final int HI_BYTES = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? 4 : 0;
|
||||
|
||||
public static long agitate(long l) {
|
||||
l ^= Long.rotateLeft(l, 26);
|
||||
l ^= Long.rotateRight(l, 17);
|
||||
return l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long applyAsLong( BytesStore store) {
|
||||
int remaining = Maths.toInt32(store.readRemaining());
|
||||
return applyAsLong(store, remaining);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long applyAsLong(BytesStore bytes, long length) {
|
||||
long start = bytes.readPosition();
|
||||
if (length <= 8) {
|
||||
long l = bytes.readIncompleteLong(start);
|
||||
return agitate(l * K0 + (l >> 32) * K1);
|
||||
}
|
||||
// use two hashes so that when they are combined the 64-bit hash is more random.
|
||||
long h0 = length * K0;
|
||||
long h1 = 0, h2 = 0, h3 = 0;
|
||||
int i;
|
||||
// optimise chunks of 32 bytes but this is the same as the next loop.
|
||||
for (i = 0; i < length - 31; i += 32) {
|
||||
if (i > 0) {
|
||||
h0 *= K0;
|
||||
h1 *= K1;
|
||||
h2 *= K2;
|
||||
h3 *= K3;
|
||||
}
|
||||
long addrI = start + i;
|
||||
long l0 = bytes.readLong(addrI);
|
||||
int l0a = bytes.readInt(addrI + HI_BYTES);
|
||||
long l1 = bytes.readLong(addrI + 8);
|
||||
int l1a = bytes.readInt(addrI + 8 + HI_BYTES);
|
||||
long l2 = bytes.readLong(addrI + 16);
|
||||
int l2a = bytes.readInt(addrI + 16 + HI_BYTES);
|
||||
long l3 = bytes.readLong(addrI + 24);
|
||||
int l3a = bytes.readInt(addrI + 24 + HI_BYTES);
|
||||
|
||||
h0 += (l0 + l1a - l2a) * M0;
|
||||
h1 += (l1 + l2a - l3a) * M1;
|
||||
h2 += (l2 + l3a - l0a) * M2;
|
||||
h3 += (l3 + l0a - l1a) * M3;
|
||||
}
|
||||
|
||||
// perform a hash of the end.
|
||||
long left = length - i;
|
||||
if (left > 0) {
|
||||
if (i > 0) {
|
||||
h0 *= K0;
|
||||
h1 *= K1;
|
||||
h2 *= K2;
|
||||
h3 *= K3;
|
||||
}
|
||||
|
||||
long addrI = start + i;
|
||||
long l0 = bytes.readIncompleteLong(addrI);
|
||||
int l0a = (int) (l0 >> 32);
|
||||
long l1 = bytes.readIncompleteLong(addrI + 8);
|
||||
int l1a = (int) (l1 >> 32);
|
||||
long l2 = bytes.readIncompleteLong(addrI + 16);
|
||||
int l2a = (int) (l2 >> 32);
|
||||
long l3 = bytes.readIncompleteLong(addrI + 24);
|
||||
int l3a = (int) (l3 >> 32);
|
||||
|
||||
h0 += (l0 + l1a - l2a) * M0;
|
||||
h1 += (l1 + l2a - l3a) * M1;
|
||||
h2 += (l2 + l3a - l0a) * M2;
|
||||
h3 += (l3 + l0a - l1a) * M3;
|
||||
}
|
||||
return agitate(h0) ^ agitate(h1)
|
||||
^ agitate(h2) ^ agitate(h3);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes.algo;
|
||||
|
||||
import net.openhft.chronicle.bytes.BytesStore;
|
||||
|
||||
// Migration of XxHash from Zero-Allocation-Hashing
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class XxHash implements BytesStoreHash<BytesStore> {
|
||||
// Primes if treated as unsigned
|
||||
private static final long P1 = -7046029288634856825L;
|
||||
private static final long P2 = -4417276706812531889L;
|
||||
private static final long P3 = 1609587929392839161L;
|
||||
private static final long P4 = -8796714831421723037L;
|
||||
public static final XxHash INSTANCE = new XxHash(P4);
|
||||
private static final long P5 = 2870177450012600261L;
|
||||
private final long seed;
|
||||
|
||||
public XxHash(long seed) {
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
private static long finalize(long hash) {
|
||||
hash ^= hash >>> 33;
|
||||
hash *= P2;
|
||||
hash ^= hash >>> 29;
|
||||
hash *= P3;
|
||||
hash ^= hash >>> 32;
|
||||
return hash;
|
||||
}
|
||||
|
||||
long fetch64(BytesStore bytes, long off) {
|
||||
return bytes.readLong(off);
|
||||
}
|
||||
|
||||
// long because of unsigned nature of original algorithm
|
||||
long fetch32(BytesStore bytes, long off) {
|
||||
return bytes.readUnsignedInt(off);
|
||||
}
|
||||
|
||||
// int because of unsigned nature of original algorithm
|
||||
long fetch8(BytesStore bytes, long off) {
|
||||
return bytes.readUnsignedByte(off);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long applyAsLong(BytesStore bytes) {
|
||||
return applyAsLong(bytes, bytes.readRemaining());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long applyAsLong(BytesStore bytes, long length) {
|
||||
long hash;
|
||||
long remaining = length;
|
||||
long off = bytes.readPosition();
|
||||
|
||||
if (remaining >= 32) {
|
||||
long v1 = seed + P1 + P2;
|
||||
long v2 = seed + P2;
|
||||
long v3 = seed;
|
||||
long v4 = seed - P1;
|
||||
|
||||
do {
|
||||
v1 += fetch64(bytes, off) * P2;
|
||||
v1 = Long.rotateLeft(v1, 31);
|
||||
v1 *= P1;
|
||||
|
||||
v2 += fetch64(bytes, off + 8) * P2;
|
||||
v2 = Long.rotateLeft(v2, 31);
|
||||
v2 *= P1;
|
||||
|
||||
v3 += fetch64(bytes, off + 16) * P2;
|
||||
v3 = Long.rotateLeft(v3, 31);
|
||||
v3 *= P1;
|
||||
|
||||
v4 += fetch64(bytes, off + 24) * P2;
|
||||
v4 = Long.rotateLeft(v4, 31);
|
||||
v4 *= P1;
|
||||
|
||||
off += 32;
|
||||
remaining -= 32;
|
||||
} while (remaining >= 32);
|
||||
|
||||
hash = Long.rotateLeft(v1, 1)
|
||||
+ Long.rotateLeft(v2, 7)
|
||||
+ Long.rotateLeft(v3, 12)
|
||||
+ Long.rotateLeft(v4, 18);
|
||||
|
||||
v1 *= P2;
|
||||
v1 = Long.rotateLeft(v1, 31);
|
||||
v1 *= P1;
|
||||
hash ^= v1;
|
||||
hash = hash * P1 + P4;
|
||||
|
||||
v2 *= P2;
|
||||
v2 = Long.rotateLeft(v2, 31);
|
||||
v2 *= P1;
|
||||
hash ^= v2;
|
||||
hash = hash * P1 + P4;
|
||||
|
||||
v3 *= P2;
|
||||
v3 = Long.rotateLeft(v3, 31);
|
||||
v3 *= P1;
|
||||
hash ^= v3;
|
||||
hash = hash * P1 + P4;
|
||||
|
||||
v4 *= P2;
|
||||
v4 = Long.rotateLeft(v4, 31);
|
||||
v4 *= P1;
|
||||
hash ^= v4;
|
||||
hash = hash * P1 + P4;
|
||||
} else {
|
||||
hash = seed + P5;
|
||||
}
|
||||
|
||||
hash += length;
|
||||
|
||||
while (remaining >= 8) {
|
||||
long k1 = fetch64(bytes, off);
|
||||
k1 *= P2;
|
||||
k1 = Long.rotateLeft(k1, 31);
|
||||
k1 *= P1;
|
||||
hash ^= k1;
|
||||
hash = Long.rotateLeft(hash, 27) * P1 + P4;
|
||||
off += 8;
|
||||
remaining -= 8;
|
||||
}
|
||||
|
||||
if (remaining >= 4) {
|
||||
hash ^= fetch32(bytes, off) * P1;
|
||||
hash = Long.rotateLeft(hash, 23) * P2 + P3;
|
||||
off += 4;
|
||||
remaining -= 4;
|
||||
}
|
||||
|
||||
while (remaining != 0) {
|
||||
hash ^= fetch8(bytes, off) * P5;
|
||||
hash = Long.rotateLeft(hash, 11) * P1;
|
||||
--remaining;
|
||||
++off;
|
||||
}
|
||||
|
||||
return finalize(hash);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* This package and any and all sub-packages contains strictly internal classes for this Chronicle library.
|
||||
* Internal classes shall <em>never</em> be used directly.
|
||||
* <p>
|
||||
* Specifically, the following actions (including, but not limited to) are not allowed
|
||||
* on internal classes and packages:
|
||||
* <ul>
|
||||
* <li>Casting to</li>
|
||||
* <li>Reflection of any kind</li>
|
||||
* <li>Explicit Serialize/deserialize</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The classes in this package and any sub-package are subject to
|
||||
* changes at any time for any reason.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes.internal;
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.bytes.pool;
|
||||
|
||||
import net.openhft.chronicle.bytes.Bytes;
|
||||
import net.openhft.chronicle.core.io.IOTools;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class BytesPool {
|
||||
final ThreadLocal<Bytes> bytesTL = new ThreadLocal<>();
|
||||
|
||||
public Bytes acquireBytes() {
|
||||
Bytes bytes = bytesTL.get();
|
||||
if (bytes == null) {
|
||||
bytesTL.set(bytes = createBytes());
|
||||
} else {
|
||||
bytes.clear();
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
protected Bytes createBytes() {
|
||||
// use heap buffer as we never know when a thread will die and not release this resource.
|
||||
Bytes<ByteBuffer> bbb = Bytes.elasticHeapByteBuffer(256);
|
||||
IOTools.unmonitor(bbb);
|
||||
return bbb;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes.ref;
|
||||
|
||||
import net.openhft.chronicle.bytes.Byteable;
|
||||
import net.openhft.chronicle.bytes.BytesStore;
|
||||
import net.openhft.chronicle.core.io.AbstractCloseable;
|
||||
import net.openhft.chronicle.core.io.Closeable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public abstract class AbstractReference extends AbstractCloseable implements Byteable, Closeable {
|
||||
|
||||
|
||||
protected BytesStore<?, ?> bytes;
|
||||
protected long offset;
|
||||
|
||||
@Override
|
||||
public void bytesStore( final BytesStore bytes, final long offset, final long length) throws IllegalStateException, IllegalArgumentException, BufferOverflowException, BufferUnderflowException {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
acceptNewBytesStore(bytes);
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BytesStore bytesStore() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long offset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract long maxSize();
|
||||
|
||||
protected void acceptNewBytesStore( final BytesStore bytes) {
|
||||
if (this.bytes != null) {
|
||||
this.bytes.release(this);
|
||||
}
|
||||
this.bytes = bytes.bytesStore();
|
||||
this.bytes.reserve(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performClose() {
|
||||
if (this.bytes != null) {
|
||||
this.bytes.release(this);
|
||||
this.bytes = null;
|
||||
}
|
||||
}
|
||||
|
||||
public long address() {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return bytesStore().addressForRead(offset);
|
||||
}
|
||||
|
||||
/* TODO FIX
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
warnIfNotClosed();
|
||||
super.finalize();
|
||||
}*/
|
||||
|
||||
@Override
|
||||
protected boolean threadSafetyCheck(boolean isUsed) {
|
||||
// References are thread safe
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package net.openhft.chronicle.bytes.ref;
|
||||
|
||||
import net.openhft.chronicle.bytes.BytesStore;
|
||||
import net.openhft.chronicle.core.values.BooleanValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
|
||||
public class BinaryBooleanReference extends AbstractReference implements BooleanValue {
|
||||
|
||||
private static final byte FALSE = (byte) 0xB0;
|
||||
private static final byte TRUE = (byte) 0xB1;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public void bytesStore( final BytesStore bytes, final long offset, final long length) throws IllegalStateException, IllegalArgumentException, BufferOverflowException, BufferUnderflowException {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
if (length != maxSize())
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
super.bytesStore(bytes, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long maxSize() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getValue() {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
byte b = bytes.readByte(offset);
|
||||
if (b == FALSE)
|
||||
return false;
|
||||
if (b == TRUE)
|
||||
return true;
|
||||
|
||||
throw new IllegalStateException("unexpected code=" + b);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(final boolean flag) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
bytes.writeByte(offset, flag ? TRUE : FALSE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes.ref;
|
||||
|
||||
import net.openhft.chronicle.bytes.*;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import net.openhft.chronicle.core.values.IntValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import static net.openhft.chronicle.bytes.ref.BinaryIntReference.INT_NOT_COMPLETE;
|
||||
|
||||
/**
|
||||
* This class acts a Binary array of 64-bit values. c.f. TextLongArrayReference
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class BinaryIntArrayReference extends AbstractReference implements ByteableIntArrayValues, BytesMarshallable {
|
||||
public static final int SHIFT = 2;
|
||||
private static final long CAPACITY = 0;
|
||||
private static final long USED = CAPACITY + Long.BYTES;
|
||||
private static final long VALUES = USED + Long.BYTES;
|
||||
private static final int MAX_TO_STRING = 1024;
|
||||
|
||||
private static Set<WeakReference<BinaryIntArrayReference>> binaryIntArrayReferences = null;
|
||||
private long length;
|
||||
|
||||
public BinaryIntArrayReference() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
public BinaryIntArrayReference(long defaultCapacity) {
|
||||
this.length = (defaultCapacity << SHIFT) + VALUES;
|
||||
}
|
||||
|
||||
public static void startCollecting() {
|
||||
binaryIntArrayReferences = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
}
|
||||
|
||||
public static void forceAllToNotCompleteState() {
|
||||
binaryIntArrayReferences.forEach(x -> {
|
||||
BinaryIntArrayReference binaryLongReference = x.get();
|
||||
if (binaryLongReference != null) {
|
||||
binaryLongReference.setValueAt(0, INT_NOT_COMPLETE);
|
||||
}
|
||||
});
|
||||
binaryIntArrayReferences = null;
|
||||
}
|
||||
|
||||
public static void write( Bytes bytes, long capacity) throws BufferOverflowException, IllegalArgumentException {
|
||||
assert (bytes.writePosition() & 0x7) == 0;
|
||||
|
||||
bytes.writeLong(capacity);
|
||||
bytes.writeLong(0L); // used
|
||||
long start = bytes.writePosition();
|
||||
bytes.zeroOut(start, start + (capacity << SHIFT));
|
||||
bytes.writeSkip(capacity << SHIFT);
|
||||
}
|
||||
|
||||
public static void lazyWrite( Bytes bytes, long capacity) throws BufferOverflowException {
|
||||
assert (bytes.writePosition() & 0x7) == 0;
|
||||
|
||||
bytes.writeLong(capacity);
|
||||
bytes.writeLong(0L); // used
|
||||
bytes.writeSkip(capacity << SHIFT);
|
||||
}
|
||||
|
||||
public static long peakLength( BytesStore bytes, long offset) throws BufferUnderflowException {
|
||||
final long capacity = bytes.readLong(offset + CAPACITY);
|
||||
assert capacity > 0 : "capacity too small " + capacity;
|
||||
return (capacity << SHIFT) + VALUES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCapacity() {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return (length - VALUES) >>> SHIFT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUsed() {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return bytes.readVolatileInt(offset + USED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxUsed(long usedAtLeast) {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
bytes.writeMaxLong(offset + USED, usedAtLeast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getValueAt(long index) throws BufferUnderflowException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return bytes.readInt(VALUES + offset + (index << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAt(long index, int value) throws IllegalArgumentException, BufferOverflowException {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
bytes.writeInt(VALUES + offset + (index << SHIFT), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVolatileValueAt(long index) throws BufferUnderflowException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return bytes.readVolatileInt(VALUES + offset + (index << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindValueAt(long index, IntValue value) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
((BinaryIntReference) value).bytesStore(bytes, VALUES + offset + (index << SHIFT), 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrderedValueAt(long index, int value) throws IllegalArgumentException, BufferOverflowException {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
bytes.writeOrderedInt(VALUES + offset + (index << SHIFT), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bytesStore( BytesStore bytes, long offset, long length) throws BufferUnderflowException, IllegalArgumentException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
if (length != peakLength(bytes, offset))
|
||||
throw new IllegalArgumentException(length + " != " + peakLength(bytes, offset));
|
||||
|
||||
assert (offset & 7) == 0 : "offset=" + offset;
|
||||
super.bytesStore(bytes, (offset + 7) & ~7, length);
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readMarshallable(BytesIn bytes) throws IORuntimeException {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
long position = bytes.readPosition();
|
||||
long capacity = bytes.readLong();
|
||||
long used = bytes.readLong();
|
||||
if (capacity < 0 || capacity > bytes.readRemaining() >> SHIFT)
|
||||
throw new IORuntimeException("Corrupt used capacity");
|
||||
|
||||
if (used < 0 || used > capacity)
|
||||
throw new IORuntimeException("Corrupt used value");
|
||||
|
||||
bytes.readSkip(capacity << SHIFT);
|
||||
long length = bytes.readPosition() - position;
|
||||
bytesStore(((Bytes) bytes).bytesStore(), position, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMarshallable(BytesOut bytes) {
|
||||
BytesStore bytesStore = bytesStore();
|
||||
if (bytesStore == null) {
|
||||
long capacity = getCapacity();
|
||||
bytes.writeLong(capacity);
|
||||
bytes.writeLong(0);
|
||||
bytes.writeSkip(capacity << SHIFT);
|
||||
} else {
|
||||
bytes.write(bytesStore, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNull() {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return bytes == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
bytes = null;
|
||||
offset = 0;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BytesStore bytesStore() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long offset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long maxSize() {
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
if (bytes == null)
|
||||
return "not set";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("used: ");
|
||||
long used = getUsed();
|
||||
sb.append(used);
|
||||
sb.append(", value: ");
|
||||
String sep = "";
|
||||
try {
|
||||
int i, max = (int) Math.min(used, Math.min(getCapacity(), MAX_TO_STRING));
|
||||
for (i = 0; i < max; i++) {
|
||||
long valueAt = getValueAt(i);
|
||||
sb.append(sep).append(valueAt);
|
||||
sep = ", ";
|
||||
}
|
||||
if (i < getCapacity())
|
||||
sb.append(" ...");
|
||||
|
||||
} catch (BufferUnderflowException e) {
|
||||
sb.append(" ").append(e);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long sizeInBytes(long capacity) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return (capacity << SHIFT) + VALUES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteableIntArrayValues capacity(long arrayLength) {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
BytesStore bytesStore = bytesStore();
|
||||
long length = sizeInBytes(arrayLength);
|
||||
if (bytesStore == null) {
|
||||
this.length = length;
|
||||
} else {
|
||||
assert this.length == length;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compareAndSet(long index, int expected, int value) throws IllegalArgumentException, BufferOverflowException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
if (value == INT_NOT_COMPLETE && binaryIntArrayReferences != null)
|
||||
binaryIntArrayReferences.add(new WeakReference<>(this));
|
||||
return bytes.compareAndSwapInt(VALUES + offset + (index << SHIFT), expected, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes.ref;
|
||||
|
||||
import net.openhft.chronicle.bytes.BytesStore;
|
||||
import net.openhft.chronicle.core.values.IntValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
|
||||
/**
|
||||
* This class acts as a Binary 32-bit in values. c.f. TextIntReference
|
||||
*/
|
||||
public class BinaryIntReference extends AbstractReference implements IntValue {
|
||||
public static final int INT_NOT_COMPLETE = Integer.MIN_VALUE;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public void bytesStore( final BytesStore bytes, final long offset, final long length) throws IllegalStateException, IllegalArgumentException, BufferOverflowException, BufferUnderflowException {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
if (length != maxSize())
|
||||
throw new IllegalArgumentException();
|
||||
super.bytesStore(bytes, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long maxSize() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return bytes == null ? "bytes is null" : "value: " + getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getValue() {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return bytes == null ? 0 : bytes.readInt(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(int value) {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
bytes.writeInt(offset, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVolatileValue() {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return bytes.readVolatileInt(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrderedValue(int value) {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
bytes.writeOrderedInt(offset, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addValue(int delta) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return bytes.addAndGetInt(offset, delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addAtomicValue(int delta) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return addValue(delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compareAndSwapValue(int expected, int value) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return bytes.compareAndSwapInt(offset, expected, value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes.ref;
|
||||
|
||||
import net.openhft.chronicle.bytes.*;
|
||||
import net.openhft.chronicle.core.io.IORuntimeException;
|
||||
import net.openhft.chronicle.core.values.LongValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import static net.openhft.chronicle.bytes.ref.BinaryLongReference.LONG_NOT_COMPLETE;
|
||||
|
||||
/**
|
||||
* This class acts a Binary array of 64-bit values. c.f. TextLongArrayReference
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class BinaryLongArrayReference extends AbstractReference implements ByteableLongArrayValues, BytesMarshallable {
|
||||
public static final int SHIFT = 3;
|
||||
private static final long CAPACITY = 0;
|
||||
private static final long USED = CAPACITY + Long.BYTES;
|
||||
private static final long VALUES = USED + Long.BYTES;
|
||||
private static final int MAX_TO_STRING = 1024;
|
||||
|
||||
private static Set<WeakReference<BinaryLongArrayReference>> binaryLongArrayReferences = null;
|
||||
private long length;
|
||||
|
||||
public BinaryLongArrayReference() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
public BinaryLongArrayReference(long defaultCapacity) {
|
||||
this.length = (defaultCapacity << SHIFT) + VALUES;
|
||||
}
|
||||
|
||||
public static void startCollecting() {
|
||||
binaryLongArrayReferences = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
}
|
||||
|
||||
public static void forceAllToNotCompleteState() {
|
||||
binaryLongArrayReferences.forEach(x -> {
|
||||
BinaryLongArrayReference binaryLongReference = x.get();
|
||||
if (binaryLongReference != null) {
|
||||
binaryLongReference.setValueAt(0, LONG_NOT_COMPLETE);
|
||||
}
|
||||
});
|
||||
binaryLongArrayReferences = null;
|
||||
}
|
||||
|
||||
public static void write( Bytes bytes, long capacity) throws BufferOverflowException, IllegalArgumentException {
|
||||
assert (bytes.writePosition() & 0x7) == 0;
|
||||
|
||||
bytes.writeLong(capacity);
|
||||
bytes.writeLong(0L); // used
|
||||
long start = bytes.writePosition();
|
||||
bytes.zeroOut(start, start + (capacity << SHIFT));
|
||||
bytes.writeSkip(capacity << SHIFT);
|
||||
}
|
||||
|
||||
public static void lazyWrite( Bytes bytes, long capacity) throws BufferOverflowException {
|
||||
assert (bytes.writePosition() & 0x7) == 0;
|
||||
|
||||
bytes.writeLong(capacity);
|
||||
bytes.writeLong(0L); // used
|
||||
bytes.writeSkip(capacity << SHIFT);
|
||||
}
|
||||
|
||||
public static long peakLength( BytesStore bytes, long offset) throws BufferUnderflowException {
|
||||
final long capacity = bytes.readLong(offset + CAPACITY);
|
||||
assert capacity > 0 : "capacity too small " + capacity;
|
||||
return (capacity << SHIFT) + VALUES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCapacity() {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return (length - VALUES) >>> SHIFT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUsed() {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return bytes.readVolatileLong(offset + USED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxUsed(long usedAtLeast) {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
bytes.writeMaxLong(offset + USED, usedAtLeast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getValueAt(long index) throws BufferUnderflowException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return bytes.readLong(VALUES + offset + (index << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAt(long index, long value) throws IllegalArgumentException, BufferOverflowException {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
bytes.writeLong(VALUES + offset + (index << SHIFT), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getVolatileValueAt(long index) throws BufferUnderflowException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return bytes.readVolatileLong(VALUES + offset + (index << SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindValueAt(long index, LongValue value) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
((BinaryLongReference) value).bytesStore(bytes, VALUES + offset + (index << SHIFT), 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrderedValueAt(long index, long value) throws IllegalArgumentException, BufferOverflowException {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
bytes.writeOrderedLong(VALUES + offset + (index << SHIFT), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bytesStore( BytesStore bytes, long offset, long length) throws BufferUnderflowException, IllegalArgumentException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
if (length != peakLength(bytes, offset))
|
||||
throw new IllegalArgumentException(length + " != " + peakLength(bytes, offset));
|
||||
|
||||
assert (offset & 7) == 0 : "offset=" + offset;
|
||||
super.bytesStore(bytes, (offset + 7) & ~7, length);
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readMarshallable(BytesIn bytes) throws IORuntimeException {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
long position = bytes.readPosition();
|
||||
long capacity = bytes.readLong();
|
||||
long used = bytes.readLong();
|
||||
if (capacity < 0 || capacity > bytes.readRemaining() >> SHIFT)
|
||||
throw new IORuntimeException("Corrupt used capacity");
|
||||
|
||||
if (used < 0 || used > capacity)
|
||||
throw new IORuntimeException("Corrupt used value");
|
||||
|
||||
bytes.readSkip(capacity << SHIFT);
|
||||
long length = bytes.readPosition() - position;
|
||||
bytesStore(((Bytes) bytes).bytesStore(), position, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMarshallable(BytesOut bytes) {
|
||||
BytesStore bytesStore = bytesStore();
|
||||
if (bytesStore == null) {
|
||||
long capacity = getCapacity();
|
||||
bytes.writeLong(capacity);
|
||||
bytes.writeLong(0);
|
||||
bytes.writeSkip(capacity << SHIFT);
|
||||
} else {
|
||||
bytes.write(bytesStore, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNull() {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return bytes == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
bytes = null;
|
||||
offset = 0;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BytesStore bytesStore() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long offset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long maxSize() {
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
if (bytes == null)
|
||||
return "not set";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("used: ");
|
||||
long used = getUsed();
|
||||
sb.append(used);
|
||||
sb.append(", value: ");
|
||||
String sep = "";
|
||||
try {
|
||||
int i, max = (int) Math.min(used, Math.min(getCapacity(), MAX_TO_STRING));
|
||||
for (i = 0; i < max; i++) {
|
||||
long valueAt = getValueAt(i);
|
||||
sb.append(sep).append(valueAt);
|
||||
sep = ", ";
|
||||
}
|
||||
if (i < getCapacity())
|
||||
sb.append(" ...");
|
||||
|
||||
} catch (BufferUnderflowException e) {
|
||||
sb.append(" ").append(e);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long sizeInBytes(long capacity) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
return (capacity << SHIFT) + VALUES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteableLongArrayValues capacity(long arrayLength) {
|
||||
throwExceptionIfClosedInSetter();
|
||||
|
||||
BytesStore bytesStore = bytesStore();
|
||||
long length = sizeInBytes(arrayLength);
|
||||
if (bytesStore == null) {
|
||||
this.length = length;
|
||||
} else {
|
||||
assert this.length == length;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compareAndSet(long index, long expected, long value) throws IllegalArgumentException, BufferOverflowException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
if (value == LONG_NOT_COMPLETE && binaryLongArrayReferences != null)
|
||||
binaryLongArrayReferences.add(new WeakReference<>(this));
|
||||
return bytes.compareAndSwapLong(VALUES + offset + (index << SHIFT), expected, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright 2016-2020 chronicle.software
|
||||
*
|
||||
* https://chronicle.software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package net.openhft.chronicle.bytes.ref;
|
||||
|
||||
import net.openhft.chronicle.bytes.BytesStore;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.BufferUnderflowException;
|
||||
|
||||
public class BinaryLongReference extends AbstractReference implements LongReference {
|
||||
public static final long LONG_NOT_COMPLETE = -1;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public void bytesStore( final BytesStore bytes, final long offset, final long length) throws IllegalStateException, IllegalArgumentException, BufferOverflowException, BufferUnderflowException {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
if (length != maxSize())
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
super.bytesStore(bytes, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long maxSize() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return bytes == null ? "bytes is null" : "value: " + getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getValue() {
|
||||
return bytes == null ? 0L : bytes.readLong(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(long value) {
|
||||
try {
|
||||
bytes.writeLong(offset, value);
|
||||
} catch (NullPointerException e) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getVolatileValue() {
|
||||
try {
|
||||
return bytes.readVolatileLong(offset);
|
||||
} catch (NullPointerException e) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVolatileValue(long value) {
|
||||
try {
|
||||
bytes.writeVolatileLong(offset, value);
|
||||
} catch (NullPointerException e) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getVolatileValue(long closedValue) {
|
||||
if (isClosed())
|
||||
return closedValue;
|
||||
try {
|
||||
return getVolatileValue();
|
||||
} catch (Exception e) {
|
||||
return closedValue;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrderedValue(long value) {
|
||||
try {
|
||||
bytes.writeOrderedLong(offset, value);
|
||||
} catch (NullPointerException e) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addValue(long delta) {
|
||||
try {
|
||||
return bytes.addAndGetLong(offset, delta);
|
||||
} catch (NullPointerException e) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addAtomicValue(long delta) {
|
||||
return addValue(delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compareAndSwapValue(long expected, long value) {
|
||||
try {
|
||||
return bytes.compareAndSwapLong(offset, expected, value);
|
||||
} catch (NullPointerException e) {
|
||||
throwExceptionIfClosed();
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue