File: formatiterator.py

package info (click to toggle)
pypy 5.6.0%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 97,040 kB
  • ctags: 185,069
  • sloc: python: 1,147,862; ansic: 49,642; cpp: 5,245; asm: 5,169; makefile: 529; sh: 481; xml: 232; lisp: 45
file content (124 lines) | stat: -rw-r--r-- 4,363 bytes parent folder | download | duplicates (6)
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
from rpython.rlib import jit
from rpython.rlib.rarithmetic import ovfcheck
from rpython.rlib.rstruct.error import StructError
from rpython.rlib.rstruct.nativefmttable import native_is_bigendian, native_fmttable
from rpython.rlib.rstruct.standardfmttable import standard_fmttable
from rpython.rlib.unroll import unrolling_iterable


class FormatIterator(object):
    """
    An iterator-like object that follows format strings step by step.
    It provides input to the packer/unpacker and accumulates their output.
    The subclasses are specialized for either packing, unpacking, or
    just computing the size.
    """
    _mixin_ = True
    _operate_is_specialized_ = False

    @jit.look_inside_iff(lambda self, fmt: jit.isconstant(fmt))
    def interpret(self, fmt):
        # decode the byte order, size and alignment based on the 1st char
        table = unroll_native_fmtdescs
        self.bigendian = native_is_bigendian
        index = 0
        if len(fmt) > 0:
            c = fmt[0]
            index = 1
            if c == '@':
                pass
            elif c == '=':
                table = unroll_standard_fmtdescs
            elif c == '<':
                table = unroll_standard_fmtdescs
                self.bigendian = False
            elif c == '>' or c == '!':
                table = unroll_standard_fmtdescs
                self.bigendian = True
            else:
                index = 0

        # interpret the format string,
        # calling self.operate() for each format unit
        while index < len(fmt):
            c = fmt[index]
            index += 1
            if c.isspace():
                continue
            if c.isdigit():
                repetitions = ord(c) - ord('0')
                while True:
                    if index == len(fmt):
                        raise StructError("incomplete struct format")
                    c = fmt[index]
                    index += 1
                    if not c.isdigit():
                        break
                    try:
                        repetitions = ovfcheck(repetitions * 10)
                        repetitions = ovfcheck(repetitions + (ord(c) -
                                                              ord('0')))
                    except OverflowError:
                        raise StructError("overflow in item count")
                assert repetitions >= 0
            else:
                repetitions = 1

            for fmtdesc in table:
                if c == fmtdesc.fmtchar:
                    if self._operate_is_specialized_:
                        if fmtdesc.alignment > 1:
                            self.align(fmtdesc.mask)
                        self.operate(fmtdesc, repetitions)
                    break
            else:
                raise StructError("bad char in struct format")
            if not self._operate_is_specialized_:
                if fmtdesc.alignment > 1:
                    self.align(fmtdesc.mask)
                self.operate(fmtdesc, repetitions)
        self.finished()

    def finished(self):
        pass


class CalcSizeFormatIterator(FormatIterator):
    totalsize = 0

    def operate(self, fmtdesc, repetitions):
        try:
            size = ovfcheck(fmtdesc.size * repetitions)
            self.totalsize = ovfcheck(self.totalsize + size)
        except OverflowError:
            raise StructError("total struct size too long")

    def align(self, mask):
        pad = (-self.totalsize) & mask
        try:
            self.totalsize = ovfcheck(self.totalsize + pad)
        except OverflowError:
            raise StructError("total struct size too long")


class FmtDesc(object):
    def __init__(self, fmtchar, attrs):
        self.fmtchar = fmtchar
        self.alignment = 1      # by default
        self.needcount = False  # by default
        self.__dict__.update(attrs)
        self.mask = self.alignment - 1
        assert self.alignment & self.mask == 0, (
            "this module assumes that all alignments are powers of two")
    def _freeze_(self):
        return True

def table2desclist(table):
    items = table.items()
    items.sort()
    lst = [FmtDesc(key, attrs) for key, attrs in items]
    return unrolling_iterable(lst)


unroll_standard_fmtdescs = table2desclist(standard_fmttable)
unroll_native_fmtdescs   = table2desclist(native_fmttable)