-
Notifications
You must be signed in to change notification settings - Fork 60
Expand file tree
/
Copy pathSimpleStringBuffer.java
More file actions
217 lines (194 loc) · 6.9 KB
/
Copy pathSimpleStringBuffer.java
File metadata and controls
217 lines (194 loc) · 6.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
package org.python.core.buffer;
import java.nio.ByteBuffer;
import org.python.core.PyBuffer;
import org.python.core.util.StringUtil;
/**
* Buffer API that appears to be a one-dimensional array of one-byte items providing read-only API,
* but which is actually backed by a Java String. Some of the buffer API absolutely needs access to
* the data as a byte array (those parts that involve a <code>PyBuffer.Pointer</code> result), and
* therefore this class must create a byte array from the String for them. However, it defers
* creation of a byte array until that part of the API is actually used. Where possible, this class
* overrides those methods in SimpleBuffer that would otherwise access the byte array attribute to
* use the String instead.
*/
public class SimpleStringBuffer extends SimpleBuffer {
/**
* The string backing this PyBuffer. A substitute for {@link #buf} until we can no longer avoid
* creating it.
*/
private String bufString;
/**
* Provide an instance of SimpleStringBuffer meeting the consumer's expectations as expressed in
* the flags argument.
*
* @param bufString storing the implementation of the object
* @param flags consumer requirements
*/
public SimpleStringBuffer(int flags, String bufString) {
// Save the backing string
this.bufString = bufString;
shape[0] = bufString.length();
// Check request is compatible with type
checkRequestFlags(flags);
}
/**
* {@inheritDoc}
* <p>
* This method uses {@link String#length()} rather than create an actual byte buffer.
*/
@Override
public int getLen() {
// Avoid creating buf by using String.length
return bufString.length();
}
/**
* {@inheritDoc}
* <p>
* This method uses {@link String#charAt(int)} rather than create an actual byte buffer.
*/
@Override
public byte byteAt(int index) throws IndexOutOfBoundsException {
// Avoid creating buf by using String.charAt
return (byte)bufString.charAt(index);
}
/**
* {@inheritDoc}
* <p>
* This method uses {@link String#charAt(int)} rather than create an actual byte buffer.
*/
@Override
public int intAt(int index) throws IndexOutOfBoundsException {
// Avoid creating buf by using String.charAt
return bufString.charAt(index);
}
/**
* {@inheritDoc}
* <p>
* This method uses {@link String#charAt(int)} rather than create an actual byte buffer.
*/
@Override
public void copyTo(int srcIndex, byte[] dest, int destPos, int length)
throws IndexOutOfBoundsException {
// Avoid creating buf by using String.charAt
int endIndex = srcIndex + length, p = destPos;
for (int i = srcIndex; i < endIndex; i++) {
dest[p++] = (byte)bufString.charAt(i);
}
}
/**
* {@inheritDoc}
* <p>
* The <code>SimpleStringBuffer</code> implementation avoids creation of a byte buffer.
*/
@Override
public PyBuffer getBufferSlice(int flags, int start, int length) {
if (length > 0) {
// The new string content is just a sub-string. (Non-copy operation in Java.)
return new SimpleStringView(getRoot(), flags,
bufString.substring(start, start + length));
} else {
// Special case for length==0 where start out of bounds sometimes raises exception.
return new ZeroByteBuffer.View(getRoot(), flags);
}
}
/**
* {@inheritDoc}
* <p>
* The <code>SimpleStringBuffer</code> implementation creates an actual byte buffer.
*/
@Override
public PyBuffer getBufferSlice(int flags, int start, int length, int stride) {
if (stride == 1) {
// Unstrided slice of a SimpleStringBuffer is itself a SimpleStringBuffer.
return getBufferSlice(flags, start, length);
} else {
// Force creation of the actual byte array from the String.
ensureHaveBytes();
// Now we are effectively a SimpleBuffer, return the strided view.
return super.getBufferSlice(flags, start, length, stride);
}
}
@Override
public ByteBuffer getNIOByteBuffer() {
// Force creation of the actual byte array from the String.
ensureHaveBytes();
return super.getNIOByteBuffer().asReadOnlyBuffer();
}
/**
* This method creates an actual byte array from the underlying String if none yet exists.
*/
private void ensureHaveBytes() {
if (storage == null) {
// We can't avoid creating the byte array any longer (index0 already correct)
storage = StringUtil.toBytes(bufString);
}
}
/**
* {@inheritDoc}
* <p>
* This method creates an actual byte array from the underlying String if none yet exists.
*/
@Override
public Pointer getBuf() {
ensureHaveBytes();
return super.getBuf();
}
/**
* {@inheritDoc}
* <p>
* This method creates an actual byte array from the underlying String if none yet exists.
*/
@Override
public Pointer getPointer(int index) {
ensureHaveBytes();
return super.getPointer(index);
}
/**
* {@inheritDoc}
* <p>
* This method creates an actual byte array from the underlying String if none yet exists.
*/
@Override
public Pointer getPointer(int... indices) {
ensureHaveBytes();
return super.getPointer(indices);
}
/**
* The <code>toString()</code> method of a <code>SimpleStringBuffer</code> simply produces the
* underlying <code>String</code>.
*/
@Override
public String toString() {
return bufString;
}
/**
* A <code>SimpleStringBuffer.SimpleStringView</code> represents a contiguous subsequence of
* another <code>SimpleStringBuffer</code>.
*/
static class SimpleStringView extends SimpleStringBuffer {
/** The buffer on which this is a slice view */
PyBuffer root;
/**
* Construct a slice of a SimpleStringBuffer.
*
* @param root buffer which will be acquired and must be released ultimately
* @param flags the request flags of the consumer that requested the slice
* @param buf becomes the buffer of bytes for this object
*/
public SimpleStringView(PyBuffer root, int flags, String bufString) {
// Create a new SimpleStringBuffer on the string passed in
super(flags, bufString);
// Get a lease on the root PyBuffer
this.root = root.getBuffer(FULL_RO);
}
@Override
protected PyBuffer getRoot() {
return root;
}
@Override
public void releaseAction() {
// We have to release the root too if ours was final.
root.release();
}
}
}