Skip to content

Commit 0e7f3db

Browse files
committed
Implement buffer decorator (similar to memoryview).
1 parent 3016860 commit 0e7f3db

File tree

11 files changed

+227
-2
lines changed

11 files changed

+227
-2
lines changed

graalpython/com.oracle.graal.python.cext/src/capi.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ static void initialize_globals() {
8282
static void initialize_bufferprocs() {
8383
polyglot_invoke(PY_TRUFFLE_CEXT, "PyTruffle_SetBufferProcs", to_java((PyObject*)&PyBytes_Type), (getbufferproc)bytes_buffer_getbuffer, (releasebufferproc)NULL);
8484
polyglot_invoke(PY_TRUFFLE_CEXT, "PyTruffle_SetBufferProcs", to_java((PyObject*)&PyByteArray_Type), (getbufferproc)NULL, (releasebufferproc)NULL);
85+
polyglot_invoke(PY_TRUFFLE_CEXT, "PyTruffle_SetBufferProcs", to_java((PyObject*)&PyBuffer_Type), (getbufferproc)bufferdecorator_getbuffer, (releasebufferproc)NULL);
8586
}
8687

8788
__attribute__((constructor))
@@ -111,6 +112,7 @@ static void initialize_capi() {
111112
initialize_type_structure(&PyFrozenSet_Type, "frozenset");
112113
initialize_type_structure(&PySet_Type, "set");
113114
initialize_type_structure(&PyEllipsis_Type, "ellipsis");
115+
initialize_type_structure(&PyBuffer_Type, "buffer");
114116

115117
// initialize global variables like '_Py_NoneStruct', etc.
116118
initialize_globals();

graalpython/com.oracle.graal.python.cext/src/capi.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ typedef struct {
6262
PyCapsule_Destructor destructor;
6363
} PyCapsule;
6464

65+
typedef struct {
66+
PyObject_VAR_HEAD
67+
void *buf_delegate;
68+
} PyBufferDecorator;
69+
70+
PyAPI_DATA(PyTypeObject) PyBuffer_Type;
71+
6572
/* Declare Python structs/types for explicit polyglot typecasts. */
6673
/* NOTE: Also add an appropriate case in 'PyTruffle_Explicit_Cast' ! */
6774
POLYGLOT_DECLARE_STRUCT(_object);
@@ -78,6 +85,7 @@ POLYGLOT_DECLARE_STRUCT(_longobject);
7885
POLYGLOT_DECLARE_TYPE(PyCapsule);
7986
POLYGLOT_DECLARE_TYPE(PyMemoryViewObject);
8087
POLYGLOT_DECLARE_TYPE(PySetObject);
88+
POLYGLOT_DECLARE_TYPE(PyBufferDecorator);
8189

8290

8391
extern void* to_java(PyObject* obj);
@@ -248,4 +256,7 @@ void* PyTruffle_Tuple_GetItem(void* jtuple, Py_ssize_t position);
248256
/* BYTES */
249257
int bytes_buffer_getbuffer(PyBytesObject *self, Py_buffer *view, int flags);
250258

259+
/* MEMORYVIEW, BUFFERDECORATOR */
260+
int bufferdecorator_getbuffer(PyBufferDecorator *self, Py_buffer *view, int flags);
261+
251262
#endif

graalpython/com.oracle.graal.python.cext/src/memoryobject.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "capi.h"
4040

4141
PyTypeObject PyMemoryView_Type = PY_TRUFFLE_TYPE("memoryview", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, offsetof(PyMemoryViewObject, ob_array));
42+
PyTypeObject PyBuffer_Type = PY_TRUFFLE_TYPE("buffer", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, sizeof(PyBufferDecorator));
4243

4344
PyObject* PyMemoryView_FromObject(PyObject *v) {
4445

@@ -47,3 +48,7 @@ PyObject* PyMemoryView_FromObject(PyObject *v) {
4748
PyErr_Format(PyExc_TypeError, "memoryview: a bytes-like object is required, not '%.200s'", Py_TYPE(v)->tp_name);
4849
return NULL;
4950
}
51+
52+
int bufferdecorator_getbuffer(PyBufferDecorator *self, Py_buffer *view, int flags) {
53+
return PyBuffer_FillInfo(view, (PyObject*)self, polyglot_get_member(self, "buf_delegate"), PyObject_Size((PyObject *)self), 1, flags);
54+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
import com.oracle.graal.python.builtins.objects.list.ListBuiltins;
108108
import com.oracle.graal.python.builtins.objects.list.PList;
109109
import com.oracle.graal.python.builtins.objects.mappingproxy.MappingproxyBuiltins;
110+
import com.oracle.graal.python.builtins.objects.memoryview.BufferBuiltins;
110111
import com.oracle.graal.python.builtins.objects.method.MethodBuiltins;
111112
import com.oracle.graal.python.builtins.objects.module.PythonModule;
112113
import com.oracle.graal.python.builtins.objects.object.ObjectBuiltins;
@@ -261,6 +262,7 @@ public final class Python3Core implements PythonCore {
261262
new AtexitModuleBuiltins(),
262263
new FaulthandlerModuleBuiltins(),
263264
new SysModuleBuiltins(),
265+
new BufferBuiltins(),
264266
};
265267

266268
// not using EnumMap, HashMap, etc. to allow this to fold away during partial evaluation

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ public enum PythonBuiltinClassType {
9494
PythonModule(com.oracle.graal.python.builtins.objects.module.PythonModule.class, "module"),
9595
PythonObject(com.oracle.graal.python.builtins.objects.object.PythonObject.class, "object"),
9696
PythonParseResult(com.oracle.graal.python.runtime.PythonParseResult.class, "code"),
97-
PZip(com.oracle.graal.python.builtins.objects.iterator.PZip.class, "zip");
97+
PZip(com.oracle.graal.python.builtins.objects.iterator.PZip.class, "zip"),
98+
PBuffer(com.oracle.graal.python.builtins.objects.memoryview.PBuffer.class, "buffer");
9899

99100
private final Class<?> clazz;
100101
private final String shortName;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinConstructors.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
import com.oracle.graal.python.builtins.objects.iterator.PZip;
102102
import com.oracle.graal.python.builtins.objects.list.PList;
103103
import com.oracle.graal.python.builtins.objects.mappingproxy.PMappingproxy;
104+
import com.oracle.graal.python.builtins.objects.memoryview.PBuffer;
104105
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
105106
import com.oracle.graal.python.builtins.objects.method.PMethod;
106107
import com.oracle.graal.python.builtins.objects.module.PythonModule;
@@ -1466,4 +1467,22 @@ Object slice(PythonClass cls, int first, int second, int third) {
14661467
return factory().createSlice(first, second, third);
14671468
}
14681469
}
1470+
1471+
// buffer([iterable])
1472+
@Builtin(name = "buffer", fixedNumOfArguments = 2, constructsClass = PBuffer.class)
1473+
@GenerateNodeFactory
1474+
public abstract static class BufferNode extends PythonBuiltinNode {
1475+
1476+
@Specialization
1477+
protected PBuffer construct(PythonClass cls, Object value) {
1478+
return factory().createBuffer(cls, value);
1479+
}
1480+
1481+
@Fallback
1482+
public PBuffer listObject(@SuppressWarnings("unused") Object cls, Object arg) {
1483+
CompilerAsserts.neverPartOfCompilation();
1484+
throw new RuntimeException("buffer does not support iterable object " + arg);
1485+
}
1486+
}
1487+
14691488
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public abstract class NativeMemberNames {
6666
public static final String UNICODE_STATE_ASCII = "ascii";
6767
public static final String UNICODE_STATE_READY = "ready";
6868
public static final String MD_DICT = "md_dict";
69+
public static final String BUF_DELEGATE = "buf_delegate";
6970

7071
public static boolean isValid(String key) {
7172
switch (key) {

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import com.oracle.graal.python.builtins.objects.cext.PythonObjectNativeWrapperMRFactory.WriteNativeMemberNodeGen;
4949
import com.oracle.graal.python.builtins.objects.cext.UnicodeObjectNodes.UnicodeAsWideCharNode;
5050
import com.oracle.graal.python.builtins.objects.dict.PDict;
51+
import com.oracle.graal.python.builtins.objects.memoryview.PBuffer;
5152
import com.oracle.graal.python.builtins.objects.object.PythonObject;
5253
import com.oracle.graal.python.builtins.objects.str.PString;
5354
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
@@ -199,7 +200,7 @@ Object doTpAsNumber(PythonClass object, @SuppressWarnings("unused") String key)
199200

200201
@Specialization(guards = "eq(TP_AS_BUFFER, key)")
201202
Object doTpAsBuffer(PythonClass object, @SuppressWarnings("unused") String key) {
202-
if (object == getCore().lookupType(PBytes.class) || object == getCore().lookupType(PByteArray.class)) {
203+
if (object == getCore().lookupType(PBytes.class) || object == getCore().lookupType(PByteArray.class) || object == getCore().lookupType(PBuffer.class)) {
203204
return new PyBufferProcsWrapper(object);
204205
}
205206

@@ -262,6 +263,11 @@ Object doMdDict(PythonObject object, @SuppressWarnings("unused") String key,
262263
return getToSulongNode().execute(getDictNode.execute(object, SpecialAttributeNames.__DICT__));
263264
}
264265

266+
@Specialization(guards = "eq(BUF_DELEGATE, key)")
267+
Object doObSval(PBuffer object, @SuppressWarnings("unused") String key) {
268+
return new PySequenceArrayWrapper(object.getDelegate());
269+
}
270+
265271
@Fallback
266272
Object doGeneric(@SuppressWarnings("unused") Object receiver, Object key) {
267273
throw UnknownIdentifierException.raise(key.toString());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* Copyright (c) 2017, 2018, Oracle and/or its affiliates.
3+
* Copyright (c) 2013, Regents of the University of California
4+
*
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without modification, are
8+
* permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice, this list of
11+
* conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
13+
* conditions and the following disclaimer in the documentation and/or other materials provided
14+
* with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
17+
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19+
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21+
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
24+
* OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
package com.oracle.graal.python.builtins.objects.memoryview;
27+
28+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETITEM__;
29+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__HASH__;
30+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__ITER__;
31+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__LEN__;
32+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__REPR__;
33+
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
34+
35+
import java.util.List;
36+
37+
import com.oracle.graal.python.builtins.Builtin;
38+
import com.oracle.graal.python.builtins.CoreFunctions;
39+
import com.oracle.graal.python.builtins.PythonBuiltins;
40+
import com.oracle.graal.python.builtins.objects.PNone;
41+
import com.oracle.graal.python.builtins.objects.ints.PInt;
42+
import com.oracle.graal.python.nodes.PGuards;
43+
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
44+
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
45+
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
46+
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
47+
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
48+
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
49+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
50+
import com.oracle.truffle.api.dsl.Cached;
51+
import com.oracle.truffle.api.dsl.Fallback;
52+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
53+
import com.oracle.truffle.api.dsl.Specialization;
54+
import com.oracle.truffle.api.dsl.TypeSystemReference;
55+
56+
@CoreFunctions(extendClasses = PBuffer.class)
57+
public class BufferBuiltins extends PythonBuiltins {
58+
59+
@Override
60+
protected List<com.oracle.truffle.api.dsl.NodeFactory<? extends PythonBuiltinNode>> getNodeFactories() {
61+
return BufferBuiltinsFactory.getFactories();
62+
}
63+
64+
@Builtin(name = __REPR__, fixedNumOfArguments = 1)
65+
@GenerateNodeFactory
66+
public abstract static class ReprNode extends PythonUnaryBuiltinNode {
67+
68+
@Specialization
69+
@TruffleBoundary
70+
public Object repr(PBuffer self,
71+
@Cached("create(__REPR__)") LookupAndCallUnaryNode repr) {
72+
return "buffer(" + repr.executeObject(self.getDelegate()) + ")";
73+
}
74+
75+
}
76+
77+
@Builtin(name = __GETITEM__, fixedNumOfArguments = 2)
78+
@TypeSystemReference(PythonArithmeticTypes.class)
79+
@GenerateNodeFactory
80+
public abstract static class GetItemNode extends PythonBinaryBuiltinNode {
81+
82+
@Specialization
83+
public Object iter(PBuffer self, boolean key,
84+
@Cached("create(__GETITEM__)") LookupAndCallBinaryNode callGetItemNode) {
85+
return callGetItemNode.executeObject(self.getDelegate(), key);
86+
}
87+
88+
@Specialization
89+
public Object iter(PBuffer self, int key,
90+
@Cached("create(__GETITEM__)") LookupAndCallBinaryNode callGetItemNode) {
91+
return callGetItemNode.executeObject(self.getDelegate(), key);
92+
}
93+
94+
@Specialization
95+
public Object iter(PBuffer self, long key,
96+
@Cached("create(__GETITEM__)") LookupAndCallBinaryNode callGetItemNode) {
97+
return callGetItemNode.executeObject(self.getDelegate(), key);
98+
}
99+
100+
@Specialization
101+
public Object iter(PBuffer self, PInt key,
102+
@Cached("create(__GETITEM__)") LookupAndCallBinaryNode callGetItemNode) {
103+
return callGetItemNode.executeObject(self.getDelegate(), key);
104+
}
105+
106+
@Fallback
107+
protected Object doGeneric(Object self, Object idx) {
108+
if (!PGuards.isInteger(idx)) {
109+
throw raise(TypeError, "buffer indices must be integers, not %p", idx);
110+
}
111+
throw raise(TypeError, "descriptor '__getitem__' requires a 'buffer' object but received a '%p'", self);
112+
}
113+
}
114+
115+
@Builtin(name = __LEN__, fixedNumOfArguments = 1)
116+
@GenerateNodeFactory
117+
public abstract static class LenNode extends PythonUnaryBuiltinNode {
118+
119+
@Specialization
120+
public Object iter(PBuffer self,
121+
@Cached("create(__LEN__)") LookupAndCallUnaryNode callLenNode) {
122+
return callLenNode.executeObject(self.getDelegate());
123+
}
124+
}
125+
126+
@Builtin(name = __ITER__, fixedNumOfArguments = 1)
127+
@GenerateNodeFactory
128+
public abstract static class IterNode extends PythonBuiltinNode {
129+
130+
@Specialization
131+
public Object iter(PBuffer self,
132+
@Cached("create(__ITER__)") LookupAndCallUnaryNode callIterNode) {
133+
return callIterNode.executeObject(self.getDelegate());
134+
}
135+
136+
@Fallback
137+
Object doGeneric(@SuppressWarnings("unused") Object self) {
138+
return PNone.NONE;
139+
}
140+
}
141+
142+
@Builtin(name = __HASH__, fixedNumOfArguments = 1)
143+
@GenerateNodeFactory
144+
public abstract static class HashNode extends PythonBuiltinNode {
145+
@Specialization
146+
Object doGeneric(Object self) {
147+
throw raise(TypeError, "unhashable type: '%p'", self);
148+
}
149+
}
150+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.oracle.graal.python.builtins.objects.memoryview;
2+
3+
import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
4+
import com.oracle.graal.python.builtins.objects.type.PythonClass;
5+
6+
public class PBuffer extends PythonBuiltinObject {
7+
8+
private final Object delegate;
9+
10+
public PBuffer(PythonClass cls, Object iterable) {
11+
super(cls);
12+
this.delegate = iterable;
13+
}
14+
15+
public Object getDelegate() {
16+
return delegate;
17+
}
18+
19+
}

0 commit comments

Comments
 (0)