Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / mojo / public / tools / bindings / pylib / mojom / generate / pack.py
1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import module as mojom
6
7 # This module provides a mechanism for determining the packed order and offsets
8 # of a mojom.Struct.
9 #
10 # ps = pack.PackedStruct(struct)
11 # ps.packed_fields will access a list of PackedField objects, each of which
12 # will have an offset, a size and a bit (for mojom.BOOLs).
13
14 class PackedField(object):
15   kind_to_size = {
16     mojom.BOOL:         1,
17     mojom.INT8:         1,
18     mojom.UINT8:        1,
19     mojom.INT16:        2,
20     mojom.UINT16:       2,
21     mojom.INT32:        4,
22     mojom.UINT32:       4,
23     mojom.FLOAT:        4,
24     mojom.HANDLE:       4,
25     mojom.MSGPIPE:      4,
26     mojom.SHAREDBUFFER: 4,
27     mojom.DCPIPE:       4,
28     mojom.DPPIPE:       4,
29     mojom.INT64:        8,
30     mojom.UINT64:       8,
31     mojom.DOUBLE:       8,
32     mojom.STRING:       8
33   }
34
35   @classmethod
36   def GetSizeForKind(cls, kind):
37     if isinstance(kind, mojom.Array) or isinstance(kind, mojom.Struct):
38       return 8
39     if isinstance(kind, mojom.Interface):
40       kind = mojom.MSGPIPE
41     if isinstance(kind, mojom.Enum):
42       # TODO(mpcomplete): what about big enums?
43       return cls.kind_to_size[mojom.INT32]
44     if not kind in cls.kind_to_size:
45       raise Exception("Invalid kind: %s" % kind.spec)
46     return cls.kind_to_size[kind]
47
48   def __init__(self, field, ordinal):
49     self.field = field
50     self.ordinal = ordinal
51     self.size = self.GetSizeForKind(field.kind)
52     self.offset = None
53     self.bit = None
54
55
56 # Returns the pad necessary to reserve space for alignment of |size|.
57 def GetPad(offset, size):
58   return (size - (offset % size)) % size
59
60
61 # Returns a 2-tuple of the field offset and bit (for BOOLs)
62 def GetFieldOffset(field, last_field):
63   if field.field.kind == mojom.BOOL and \
64       last_field.field.kind == mojom.BOOL and \
65       last_field.bit < 7:
66     return (last_field.offset, last_field.bit + 1)
67
68   offset = last_field.offset + last_field.size
69   pad = GetPad(offset, field.size)
70   return (offset + pad, 0)
71
72
73 class PackedStruct(object):
74   def __init__(self, struct):
75     self.struct = struct
76     self.packed_fields = []
77
78     # No fields.
79     if (len(struct.fields) == 0):
80       return
81
82     # Start by sorting by ordinal.
83     src_fields = []
84     ordinal = 0
85     for field in struct.fields:
86       if field.ordinal is not None:
87         ordinal = field.ordinal
88       src_fields.append(PackedField(field, ordinal))
89       ordinal += 1
90     src_fields.sort(key=lambda field: field.ordinal)
91
92     src_field = src_fields[0]
93     src_field.offset = 0
94     src_field.bit = 0
95     # dst_fields will contain each of the fields, in increasing offset order.
96     dst_fields = self.packed_fields
97     dst_fields.append(src_field)
98
99     # Then find first slot that each field will fit.
100     for src_field in src_fields[1:]:
101       last_field = dst_fields[0]
102       for i in xrange(1, len(dst_fields)):
103         next_field = dst_fields[i]
104         offset, bit = GetFieldOffset(src_field, last_field)
105         if offset + src_field.size <= next_field.offset:
106           # Found hole.
107           src_field.offset = offset
108           src_field.bit = bit
109           dst_fields.insert(i, src_field)
110           break
111         last_field = next_field
112       if src_field.offset is None:
113         # Add to end
114         src_field.offset, src_field.bit = GetFieldOffset(src_field, last_field)
115         dst_fields.append(src_field)
116
117   def GetTotalSize(self):
118     if not self.packed_fields:
119       return 0
120     last_field = self.packed_fields[-1]
121     offset = last_field.offset + last_field.size
122     pad = GetPad(offset, 8)
123     return offset + pad
124
125
126 class ByteInfo(object):
127   def __init__(self):
128     self.is_padding = False
129     self.packed_fields = []
130
131
132 def GetByteLayout(packed_struct):
133   bytes = [ByteInfo() for i in xrange(packed_struct.GetTotalSize())]
134
135   limit_of_previous_field = 0
136   for packed_field in packed_struct.packed_fields:
137     for i in xrange(limit_of_previous_field, packed_field.offset):
138       bytes[i].is_padding = True
139     bytes[packed_field.offset].packed_fields.append(packed_field)
140     limit_of_previous_field = packed_field.offset + packed_field.size
141
142   for i in xrange(limit_of_previous_field, len(bytes)):
143     bytes[i].is_padding = True
144
145   for byte in bytes:
146     # A given byte cannot both be padding and have a fields packed into it.
147     assert not (byte.is_padding and byte.packed_fields)
148
149   return bytes