Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions capnpy/compiler/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ def _emit(self, m, ns, name):
#
if self.slot.type.is_void():
self._emit_void(m, ns, name)
elif self.slot.type.is_float32() or self.slot.type.is_float64():
self._emit_float(m, ns, name)
elif self.slot.type.is_primitive():
self._emit_primitive(m, ns, name)
elif self.slot.type.is_bool():
Expand Down Expand Up @@ -78,6 +80,19 @@ def _emit_primitive(self, m, ns, name):
return value
""")

def _emit_float(self, m, ns, name):
ns.typename = '_Types.%s' % self.slot.type.which()
ns.default_ = self.slot.defaultValue.as_pyobj()
ns.ifmt = "ord(%r)" % self.slot.get_fmt()
m.def_property(ns, name, """
{ensure_union}
value = self._read_primitive({offset}, {ifmt})

if {default_} != 0:
value = _fxor(value, {default_}, {ifmt})
return value
""")

def _emit_bool(self, m, ns, name):
byteoffset, bitoffset = divmod(self.slot.offset, 8)
ns.offset = byteoffset
Expand Down
1 change: 1 addition & 0 deletions capnpy/compiler/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def emit(self, m):
m.w("from capnpy.util import extend_module_maybe as _extend_module_maybe")
m.w("from capnpy.util import check_version as _check_version")
m.w("from capnpy.util import encode_maybe as _encode_maybe")
m.w("from capnpy.util import fxor as _fxor")
#
if m.pyx:
m.w("from capnpy cimport _hash")
Expand Down
24 changes: 1 addition & 23 deletions capnpy/segment/base.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,5 @@
import struct
from six import int2byte
from pypytools import IS_PYPY


if IS_PYPY:
# workaround for a limitation of the PyPy JIT: struct.unpack is optimized
# only if the format string is a tracing-time constant; this is because of
# this line in rlib/rstruct/formatiterator.py:
# @jit.look_inside_iff(lambda self, fmt: jit.isconstant(fmt))
# def interpret(self, fmt):
# ...
#
# The problem is that if you use struct.unpack(chr(113), '...'), chr(113)
# is not a tracing-time constant (it becomes constant later, during
# optimizeopt). The work around is to use mychr, which pyjitpl.py is smart
# enough to detect as a tracing-time constant.
_CHR = tuple(map(int2byte, range(256)))
def mychr(i):
return _CHR[i]

else:
mychr = int2byte

from capnpy.util import mychr

def unpack_uint32(buf, offset):
if offset < 0 or offset + 4 > len(buf):
Expand Down
23 changes: 23 additions & 0 deletions capnpy/testing/compiler/test_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,29 @@ def test_primitive_default(self):
assert p.x == 0
assert p.y is False

def test_float_default(self):
schema = """
@0xbf5147cbbecf40c1;
struct Foo {
x @0 :Float32 = 0.5;
y @1 :Float64 = 8.0;
}
"""
mod = self.compile(schema)
#
buf = b('\x00\x00\x00\x00\x00\x00\x00\x00'
'\x00\x00\x00\x00\x00\x00\x00\x00')
p = mod.Foo.from_buffer(buf, 0, 2, 0)
assert p.x == 0.5
assert p.y == 8.0
#
buf = b('\x00\x00\x80\x00\x00\x00\x00\x00'
'\x00\x00\x00\x00\x00\x00\x10\x00')
p = mod.Foo.from_buffer(buf, 0, 2, 0)
assert p.x == 1.0
assert p.y == 16.0


def test_void(self):
schema = """
@0xbf5147cbbecf40c1;
Expand Down
25 changes: 25 additions & 0 deletions capnpy/util.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import sys
import py
from pypytools import IS_PYPY
import six
import struct

import capnpy
try:
Expand All @@ -11,6 +13,25 @@

Py_TPFLAGS_HEAPTYPE = (1<<9) # from object.h

if IS_PYPY:
# workaround for a limitation of the PyPy JIT: struct.unpack is optimized
# only if the format string is a tracing-time constant; this is because of
# this line in rlib/rstruct/formatiterator.py:
# @jit.look_inside_iff(lambda self, fmt: jit.isconstant(fmt))
# def interpret(self, fmt):
# ...
#
# The problem is that if you use struct.unpack(chr(113), '...'), chr(113)
# is not a tracing-time constant (it becomes constant later, during
# optimizeopt). The work around is to use mychr, which pyjitpl.py is smart
# enough to detect as a tracing-time constant.
_CHR = tuple(map(six.int2byte, range(256)))
def mychr(i):
return _CHR[i]

else:
mychr = six.int2byte

def magic_setattr(cls, attr, value):
if cls.__flags__ & Py_TPFLAGS_HEAPTYPE:
# normal case
Expand Down Expand Up @@ -111,3 +132,7 @@ def data_repr(s):
except ImportError:
float32_repr = float64_repr = repr

# https://stackoverflow.com/a/51939549
def fxor(a, b, fmt):
raw = [x ^ y for (x, y) in zip(struct.pack(mychr(fmt), a), struct.pack(mychr(fmt), b))]
return struct.unpack(mychr(fmt), bytes(raw))[0]