Skip to content

Commit 54d7431

Browse files
committed
Implement 'PyUnicode_GET_SIZE' (and required member accesses).
1 parent ae11214 commit 54d7431

File tree

5 files changed

+209
-14
lines changed

5 files changed

+209
-14
lines changed

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_unicode.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -306,13 +306,13 @@ def compile_module(self, name):
306306
)
307307

308308
# TODO enable once supported
309-
# test_PyUnicode_GET_SIZE = CPyExtFunction(
310-
# lambda args: len(args[0]),
311-
# lambda: (
312-
# ("hello",),
313-
# ),
314-
# resultspec="n",
315-
# argspec='O',
316-
# arguments=["PyObject* o"],
317-
# cmpfunc=unhandled_error_compare
318-
# )
309+
test_PyUnicode_GET_SIZE = CPyExtFunction(
310+
lambda args: len(args[0]),
311+
lambda: (
312+
("hello",),
313+
),
314+
resultspec="n",
315+
argspec='O',
316+
arguments=["PyObject* o"],
317+
cmpfunc=unhandled_error_compare
318+
)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cpyobject/NativeMemberNames.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,13 @@ public abstract class NativeMemberNames {
5151
public static final String OB_ITEM = "ob_item";
5252
public static final String MA_USED = "ma_used";
5353
public static final String UNICODE_WSTR = "wstr";
54+
public static final String UNICODE_WSTR_LENGTH = "wstr_length";
5455
public static final String UNICODE_STATE = "state";
56+
public static final String UNICODE_STATE_INTERNED = "interned";
57+
public static final String UNICODE_STATE_KIND = "kind";
58+
public static final String UNICODE_STATE_COMPACT = "compact";
59+
public static final String UNICODE_STATE_ASCII = "ascii";
60+
public static final String UNICODE_STATE_READY = "ready";
5561

5662
public static boolean isValid(String key) {
5763
switch (key) {
@@ -67,7 +73,13 @@ public static boolean isValid(String key) {
6773
case OB_ITEM:
6874
case MA_USED:
6975
case UNICODE_WSTR:
76+
case UNICODE_WSTR_LENGTH:
7077
case UNICODE_STATE:
78+
case UNICODE_STATE_INTERNED:
79+
case UNICODE_STATE_KIND:
80+
case UNICODE_STATE_COMPACT:
81+
case UNICODE_STATE_ASCII:
82+
case UNICODE_STATE_READY:
7183
return true;
7284
}
7385
return false;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (c) 2018, Oracle and/or its affiliates.
3+
*
4+
* The Universal Permissive License (UPL), Version 1.0
5+
*
6+
* Subject to the condition set forth below, permission is hereby granted to any
7+
* person obtaining a copy of this software, associated documentation and/or data
8+
* (collectively the "Software"), free of charge and under any and all copyright
9+
* rights in the Software, and any and all patent rights owned or freely
10+
* licensable by each licensor hereunder covering either (i) the unmodified
11+
* Software as contributed to or provided by such licensor, or (ii) the Larger
12+
* Works (as defined below), to deal in both
13+
*
14+
* (a) the Software, and
15+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
16+
* one is included with the Software (each a "Larger Work" to which the
17+
* Software is contributed by such licensors),
18+
*
19+
* without restriction, including without limitation the rights to copy, create
20+
* derivative works of, display, perform, and distribute the Software and make,
21+
* use, sell, offer for sale, import, export, have made, and have sold the
22+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
23+
* either these or other terms.
24+
*
25+
* This license is subject to the following condition:
26+
*
27+
* The above copyright notice and either this complete permission notice or at a
28+
* minimum a reference to the UPL must be included in all copies or substantial
29+
* portions of the Software.
30+
*
31+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37+
* SOFTWARE.
38+
*/
39+
package com.oracle.graal.python.builtins.objects.cpyobject;
40+
41+
import com.oracle.graal.python.builtins.objects.str.PString;
42+
import com.oracle.truffle.api.interop.ForeignAccess;
43+
import com.oracle.truffle.api.interop.TruffleObject;
44+
45+
/**
46+
* Wraps a sequence object (like a list) such that it behaves like a bare C array.
47+
*/
48+
public class PyUnicodeState implements TruffleObject {
49+
50+
private final PString delegate;
51+
52+
public PyUnicodeState(PString delegate) {
53+
this.delegate = delegate;
54+
}
55+
56+
public PString getDelegate() {
57+
return delegate;
58+
}
59+
60+
static boolean isInstance(TruffleObject o) {
61+
return o instanceof PyUnicodeState;
62+
}
63+
64+
public ForeignAccess getForeignAccess() {
65+
return PyUnicodeStateMRForeign.ACCESS;
66+
}
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright (c) 2018, Oracle and/or its affiliates.
3+
*
4+
* The Universal Permissive License (UPL), Version 1.0
5+
*
6+
* Subject to the condition set forth below, permission is hereby granted to any
7+
* person obtaining a copy of this software, associated documentation and/or data
8+
* (collectively the "Software"), free of charge and under any and all copyright
9+
* rights in the Software, and any and all patent rights owned or freely
10+
* licensable by each licensor hereunder covering either (i) the unmodified
11+
* Software as contributed to or provided by such licensor, or (ii) the Larger
12+
* Works (as defined below), to deal in both
13+
*
14+
* (a) the Software, and
15+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
16+
* one is included with the Software (each a "Larger Work" to which the
17+
* Software is contributed by such licensors),
18+
*
19+
* without restriction, including without limitation the rights to copy, create
20+
* derivative works of, display, perform, and distribute the Software and make,
21+
* use, sell, offer for sale, import, export, have made, and have sold the
22+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
23+
* either these or other terms.
24+
*
25+
* This license is subject to the following condition:
26+
*
27+
* The above copyright notice and either this complete permission notice or at a
28+
* minimum a reference to the UPL must be included in all copies or substantial
29+
* portions of the Software.
30+
*
31+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37+
* SOFTWARE.
38+
*/
39+
package com.oracle.graal.python.builtins.objects.cpyobject;
40+
41+
import java.nio.charset.Charset;
42+
import java.nio.charset.CharsetEncoder;
43+
44+
import com.oracle.graal.python.builtins.modules.TruffleCextBuiltins.ToSulongNode;
45+
import com.oracle.truffle.api.CompilerDirectives;
46+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
47+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
48+
import com.oracle.truffle.api.interop.MessageResolution;
49+
import com.oracle.truffle.api.interop.Resolve;
50+
import com.oracle.truffle.api.interop.UnknownIdentifierException;
51+
import com.oracle.truffle.api.nodes.Node;
52+
53+
@MessageResolution(receiverType = PyUnicodeState.class)
54+
public class PyUnicodeStateMR {
55+
56+
@Resolve(message = "READ")
57+
abstract static class ReadNode extends Node {
58+
@Child private ToSulongNode toSulongNode;
59+
60+
public Object access(PyUnicodeState object, String key) {
61+
switch (key) {
62+
case NativeMemberNames.UNICODE_STATE_INTERNED:
63+
return getToSulongNode().execute(false);
64+
case NativeMemberNames.UNICODE_STATE_KIND:
65+
return getToSulongNode().execute(0);
66+
case NativeMemberNames.UNICODE_STATE_COMPACT:
67+
return getToSulongNode().execute(false);
68+
case NativeMemberNames.UNICODE_STATE_ASCII:
69+
return getToSulongNode().execute(onlyAscii(object.getDelegate().getValue()));
70+
case NativeMemberNames.UNICODE_STATE_READY:
71+
return getToSulongNode().execute(true);
72+
}
73+
throw UnknownIdentifierException.raise(key);
74+
}
75+
76+
@CompilationFinal private CharsetEncoder asciiEncoder;
77+
78+
public boolean isPureAscii(String v) {
79+
return asciiEncoder.canEncode(v);
80+
}
81+
82+
private boolean onlyAscii(String value) {
83+
if (asciiEncoder == null) {
84+
CompilerDirectives.transferToInterpreterAndInvalidate();
85+
asciiEncoder = Charset.forName("US-ASCII").newEncoder();
86+
}
87+
return doCheck(value, asciiEncoder);
88+
}
89+
90+
@TruffleBoundary
91+
private static boolean doCheck(String value, CharsetEncoder asciiEncoder) {
92+
return asciiEncoder.canEncode(value);
93+
}
94+
95+
private ToSulongNode getToSulongNode() {
96+
if (toSulongNode == null) {
97+
CompilerDirectives.transferToInterpreterAndInvalidate();
98+
toSulongNode = insert(ToSulongNode.create());
99+
}
100+
return toSulongNode;
101+
}
102+
}
103+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cpyobject/PythonObjectNativeWrapperMR.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,12 +193,25 @@ Object doObItem(PSequence object, @SuppressWarnings("unused") String key) {
193193
@Specialization(guards = "eq(UNICODE_WSTR, key)")
194194
Object doWstr(String object, @SuppressWarnings("unused") String key,
195195
@Cached("create()") PyTruffle_Unicode_AsWideChar asWideCharNode) {
196-
return new PySequenceArrayWrapper(asWideCharNode.execute(object, getWcharSize(), object.length(), null));
196+
return new PySequenceArrayWrapper(asWideCharNode.execute(object, sizeofWchar(), object.length(), null));
197+
}
198+
199+
@Specialization(guards = "eq(UNICODE_WSTR_LENGTH, key)")
200+
long doWstrLength(String object, @SuppressWarnings("unused") String key,
201+
@Cached("create()") PyTruffle_Unicode_AsWideChar asWideCharNode) {
202+
// TODO refactor 'PyTruffle_Unicode_AsWideChar'
203+
long sizeofWchar = sizeofWchar();
204+
Object result = asWideCharNode.execute(object, sizeofWchar, object.length(), null);
205+
if (result instanceof PBytes) {
206+
return ((PBytes) result).len() / sizeofWchar;
207+
}
208+
return -1;
197209
}
198210

199211
@Specialization(guards = "eq(UNICODE_STATE, key)")
200-
Object doState(String object, @SuppressWarnings("unused") String key) {
201-
return factory().createBytes(new byte[]{(byte) 0xDE, (byte) 0xAD, (byte) 0xBE, (byte) 0xEF});
212+
Object doState(PString object, @SuppressWarnings("unused") String key) {
213+
// TODO also support bare 'String' ?
214+
return new PyUnicodeState(object);
202215
}
203216

204217
@Fallback
@@ -222,7 +235,7 @@ private ToSulongNode getToSulongNode() {
222235
return toSulongNode;
223236
}
224237

225-
private long getWcharSize() {
238+
private long sizeofWchar() {
226239
if (wcharSize < 0) {
227240
CompilerDirectives.transferToInterpreterAndInvalidate();
228241
TruffleObject boxed = (TruffleObject) getContext().getEnv().importSymbol(NativeCAPISymbols.FUN_WHCAR_SIZE);

0 commit comments

Comments
 (0)