-
Notifications
You must be signed in to change notification settings - Fork 227
Expand file tree
/
Copy pathSimpleStringBuffer.java
More file actions
220 lines (199 loc) · 7.21 KB
/
SimpleStringBuffer.java
File metadata and controls
220 lines (199 loc) · 7.21 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
218
219
220
package org.python.core.buffer;
import java.nio.ByteBuffer;
import org.python.core.BufferProtocol;
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 {@link java.nio.ByteBuffer} or
* {@link org.python.core.PyBuffer.Pointer} 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 flags consumer requirements
* @param obj exporting object (or <code>null</code>)
* @param bufString storing the implementation of the object
*/
public SimpleStringBuffer(int flags, BufferProtocol obj, String bufString) {
/*
* Leaving storage=null is ok because we carefully override every method that uses it,
* deferring creation of the storage byte array until we absolutely must have one.
*/
super(obj, null, 0, bufString.length());
// Save the backing string
this.bufString = bufString;
// 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 final byte byteAtImpl(int index) {
return (byte)bufString.charAt(index);
}
/**
* {@inheritDoc}
* <p>
* In <code>SimpleStringBuffer</code> we can simply return the argument.
*/
@Override
public final int byteIndex(int index) {
// We do not check the index because String will do it for us.
return 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 count)
throws IndexOutOfBoundsException {
// Avoid creating buf by using String.charAt
int endIndex = srcIndex + count, 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 count) {
if (count > 0) {
// The new string content is just a sub-string.
return new SimpleStringView(getRoot(), flags, bufString.substring(start, start + count));
} else {
// Special case for count==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 count, int stride) {
if (stride == 1) {
// Unstrided slice of a SimpleStringBuffer is itself a SimpleStringBuffer.
return getBufferSlice(flags, start, count);
} 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, count, stride);
}
}
@Override
protected ByteBuffer getNIOByteBufferImpl() {
// Force creation of the actual byte array from the String.
ensureHaveBytes();
// The buffer spans the whole storage, which may include data not in the view
ByteBuffer b = ByteBuffer.wrap(storage);
// Return as read-only.
return b.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.
*/
@SuppressWarnings("deprecation")
@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.
*/
@SuppressWarnings("deprecation")
@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.
*/
@SuppressWarnings("deprecation")
@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, root.getObj(), bufString);
// Get a lease on the root PyBuffer
this.root = root.getBuffer(FULL_RO);
}
@Override
protected PyBuffer getRoot() {
return root;
}
}
}