[Xcb] [PATCH libxcb 1/1] calculate lengthless list

Christian Linhart chris at demorecorder.com
Tue Nov 10 16:02:09 PST 2015


From: Jaya Tiwari <tiwari.jaya18 at gmail.com>

Some rework done by Christian Linhart

Signed-off-by: Jaya Tiwari <tiwari.jaya18 at gmail.com>
Signed-off-by: Christian Linhart <chris at demorecorder.com>
---
 src/c_client.py | 84 ++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 62 insertions(+), 22 deletions(-)

diff --git a/src/c_client.py b/src/c_client.py
index 5d01289..797c85b 100644
--- a/src/c_client.py
+++ b/src/c_client.py
@@ -467,15 +467,16 @@ def _c_type_setup(self, name, postfix):
             field.prev_varsized_offset = prev_varsized_offset
 
             if prev_varsized_offset == 0:
                 first_field_after_varsized = field
             field.first_field_after_varsized = first_field_after_varsized
 
             if field.type.fixed_size():
-                prev_varsized_offset += field.type.size
+                if field.wire:
+                    prev_varsized_offset += field.type.size
                 # special case: intermixed fixed and variable size fields
                 if prev_varsized_field is not None and not field.type.is_pad and field.wire:
                     if not self.is_union:
                         self.c_need_serialize = True
                         self.c_var_followed_by_fixed_fields = True
             else:
                 self.last_varsized_field = field
@@ -645,15 +646,15 @@ def _c_helper_resolve_field_names (prefix):
     return all_fields
 
 def get_expr_fields(self):
     """
     get the Fields referenced by switch or list expression
     """
     def get_expr_field_names(expr):
-        if expr.op is None:
+        if expr.op is None or expr.op == 'calculate_len':
             if expr.lenfield_name is not None:
                 return [expr.lenfield_name]
             else:
                 # constant value expr
                 return []
         else:
             if expr.op == '~':
@@ -722,23 +723,25 @@ def resolve_expr_fields_list(self, parents):
     that cannot be resolved within the parents of the list.
     These are normally fields that need to be given as function parameters
     for length and iterator functions.
     """
     all_fields = []
     expr_fields = get_expr_fields(self)
     unresolved = []
-
+    dont_resolve_this = ''
     for complex_obj in parents:
         for field in complex_obj.fields:
+            if field.type.is_list and field.type.expr.op == 'calculate_len':
+                dont_resolve_this = field.type.expr.lenfield_name
             if field.wire:
                 all_fields.append(field)
 
     # try to resolve expr fields
     for e in expr_fields:
-        if e not in all_fields and e not in unresolved:
+        if e not in all_fields and e not in unresolved and e.field_name != dont_resolve_this:
             unresolved.append(e)
 
     return unresolved
 # resolve_expr_fields_list()
 
 
 def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
@@ -771,15 +774,17 @@ def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
     # fixed and variable size fields
     if self.is_switch:
         param_fields = get_expr_fields(self)
 
     # _serialize()/_unserialize()/_unpack() function parameters
     # note: don't use set() for params, it is unsorted
     params = []
-
+    parameter = ''
+    if self.is_list:
+       parameter = self.type.expr.lenfield_name
     # 1. the parameter for the void * buffer
     if  'serialize' == context:
         params.append(('void', '**', buffer_var))
     elif context in ('unserialize', 'unpack', 'sizeof'):
         params.append(('const void', '*', buffer_var))
 
     # 2. any expr fields that cannot be resolved within self and descendants
@@ -791,15 +796,15 @@ def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
     #    that do not appear in the data type struct
     for p in param_fields:
         if self.is_switch:
             typespec = p.c_field_const_type
             pointerspec = p.c_pointer
             add_param(params, (typespec, pointerspec, p.c_field_name))
         else:
-            if p.visible and not p.wire and not p.auto:
+            if p.visible and not p.wire and not p.auto and p.field_name != parameter:
                 typespec = p.c_field_type
                 pointerspec = ''
                 add_param(params, (typespec, pointerspec, p.c_field_name))
 
     # 4. aux argument
     if 'serialize' == context:
         add_param(params, ('const %s' % self.c_type, '*', aux_var))
@@ -980,16 +985,18 @@ def _c_serialize_helper_list_field(context, self, field,
                             field.c_field_name)
 
         field_mapping.update(_c_helper_resolve_field_names(prefix))
         resolved += [x for x in unresolved if x in field_mapping]
         unresolved = [x for x in unresolved if x not in field_mapping]
         if len(unresolved)>0:
             raise Exception('could not resolve the length fields required for list %s' % field.c_field_name)
-
-    list_length = _c_accessor_get_expr(expr, field_mapping)
+    if expr.op == 'calculate_len':
+        list_length = field.type.expr.lenfield_name
+    else:
+        list_length = _c_accessor_get_expr(expr, field_mapping)
 
     # default: list with fixed size elements
     length = '%s * sizeof(%s)' % (list_length, field.type.member.c_wiretype)
 
     # list with variable-sized elements
     if not field.type.member.fixed_size():
         # compute string for argumentlist for member-type functions
@@ -1717,15 +1724,15 @@ def _c_accessor_get_expr(expr, field_mapping):
         _c_pre.pop_indent()
         _c_pre.code("}")
         _c_pre.code("/* sumof end. Result is in %s */", sumvar)
         _c_pre.end()
         return sumvar
     elif expr.op == 'listelement-ref':
         return '(*xcb_listelement)'
-    elif expr.op != None:
+    elif expr.op != None and expr.op != 'calculate_len':
         return ('(' + _c_accessor_get_expr(expr.lhs, field_mapping) +
                 ' ' + expr.op + ' ' +
                 _c_accessor_get_expr(expr.rhs, field_mapping) + ')')
     elif expr.bitfield:
         return 'xcb_popcount(' + lenexp + ')'
     else:
         return lenexp
@@ -1907,16 +1914,42 @@ def _c_accessors_list(self, field):
         _hc('%s (const %s *R,', field.c_length_name, R_obj.c_type)
         _h('%sconst %s *S%s);', spacing, S_obj.c_type, add_param_str)
         _c('%sconst %s *S%s)', spacing, S_obj.c_type, add_param_str)
     else:
         _h('%s (const %s *R%s);', field.c_length_name, c_type, add_param_str)
         _c('%s (const %s *R%s)', field.c_length_name, c_type, add_param_str)
     _c('{')
-    length = _c_accessor_get_expr(field.type.expr, fields)
-    _c('    return %s;', length)
+
+    def get_length():
+        if field.type.expr.op == 'calculate_len':
+            if field.type.member.fixed_size():
+                if field.prev_varsized_field is None:
+                    # the list is directly after the fixed size part of the
+                    # request: simply subtract the size of the fixed-size part
+                    # from the request size and divide that by the member size
+                    return '(((R->length * 4) - sizeof('+ self.c_type + '))/'+'sizeof('+field.type.member.c_wiretype+'))'
+                else:
+		    # use the accessor to get the start of the list, then
+		    # compute the length of it by subtracting it from
+                    # the adress of the first byte after the end of the
+                    # request
+		    after_end_of_request = '(((char*)R) + R->length * 4)'
+		    start_of_list = '%s(R)' % (field.c_accessor_name)
+                    bytesize_of_list = '%s - (char*)(%s)' % (after_end_of_request, start_of_list)
+		    return '(%s) / sizeof(%s)' % (bytesize_of_list, field.type.member.c_wiretype)
+            else:
+                raise Exception(
+                    "lengthless lists with varsized members are not supported. Fieldname '%s'"
+                    %
+                    (field.c_field_name)
+                );
+        else:
+            return _c_accessor_get_expr(field.type.expr, fields)
+
+    _c('    return %s;', get_length())
     _c('}')
 
     if field.type.member.is_simple:
         _hc('')
         _hc('xcb_generic_iterator_t')
         spacing = ' '*(len(field.c_end_name)+2)
         add_param_str = additional_params_to_str(spacing)
@@ -1929,53 +1962,52 @@ def _c_accessors_list(self, field):
             _c('%s (const %s *R%s)', field.c_end_name, c_type, add_param_str)
         _c('{')
         _c('    xcb_generic_iterator_t i;')
 
         param = 'R' if switch_obj is None else 'S'
         if switch_obj is not None:
             _c('    i.data = %s + %s;', fields[field.c_field_name][0],
-               _c_accessor_get_expr(field.type.expr, fields))
+               get_length())
         elif field.prev_varsized_field == None:
             _c('    i.data = ((%s *) (R + 1)) + (%s);', field.type.c_wiretype,
-               _c_accessor_get_expr(field.type.expr, fields))
+               get_length())
         else:
             (prev_varsized_field, align_pad) = get_align_pad(field)
 
             if align_pad is None:
                 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
                     type_pad_type(field.first_field_after_varsized.type.c_type))
 
             _c('    xcb_generic_iterator_t prev = %s;',
                 _c_iterator_get_end(prev_varsized_field, 'R'))
             _c('    i.data = ((%s *) ((char*) prev.data + %s)) + (%s);',
                 field.type.c_wiretype, align_pad,
-                _c_accessor_get_expr(field.type.expr, fields))
+                get_length())
 
         _c('    i.rem = 0;')
         _c('    i.index = (char *) i.data - (char *) %s;', param)
         _c('    return i;')
         _c('}')
 
     else:
         _hc('')
         _hc('%s', field.c_iterator_type)
         spacing = ' '*(len(field.c_iterator_name)+2)
-        add_param_str = additional_params_to_str(spacing)
         if switch_obj is not None:
             _hc('%s (const %s *R,', field.c_iterator_name, R_obj.c_type)
             _h('%sconst %s *S%s);', spacing, S_obj.c_type, add_param_str)
             _c('%sconst %s *S%s)', spacing, S_obj.c_type, add_param_str)
         else:
             _h('%s (const %s *R%s);', field.c_iterator_name, c_type, add_param_str)
             _c('%s (const %s *R%s)', field.c_iterator_name, c_type, add_param_str)
         _c('{')
         _c('    %s i;', field.c_iterator_type)
 
         _c_pre.start()
-        length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
+        length_expr_str = get_length()
 
         if switch_obj is not None:
             _c_pre.end()
             _c('    i.data = %s;', fields[field.c_field_name][0])
             _c('    i.rem = %s;', length_expr_str)
         elif field.prev_varsized_field == None:
             _c_pre.end()
@@ -2350,19 +2382,24 @@ def _c_request_helper(self, name, void, regular, aux=False, reply_fds=False):
             if not field.type.fixed_size():
                 _c('    /* %s %s */', field.type.c_type, field.c_field_name)
                 # default: simple cast to char *
                 if not field.type.c_need_serialize and not field.type.c_need_sizeof:
                     _c('    xcb_parts[%d].iov_base = (char *) %s;', count, field.c_field_name)
                     if field.type.is_list:
                         if field.type.member.fixed_size():
-                            _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count,
-                               _c_accessor_get_expr(field.type.expr, None),
-                               field.type.member.c_wiretype)
+                            if field.type.expr.op == 'calculate_len':
+                                lenfield = field.type.expr.lenfield_name
+                            else:
+                                lenfield = _c_accessor_get_expr(field.type.expr, None)
+
+                            _c('    xcb_parts[%d].iov_len = %s * sizeof(%s);', count, lenfield,
+                                        field.type.member.c_wiretype)
                         else:
                             list_length = _c_accessor_get_expr(field.type.expr, None)
+                            length = ''
 
                             _c("    xcb_parts[%d].iov_len = 0;" % count)
                             _c("    xcb_tmp = (char *)%s;", field.c_field_name)
                             _c("    for(i=0; i<%s; i++) {" % list_length)
                             _c("        xcb_tmp_len = %s(xcb_tmp);" %
                                               (field.type.c_sizeof_name))
                             _c("        xcb_parts[%d].iov_len += xcb_tmp_len;" % count)
@@ -3109,17 +3146,20 @@ def c_request(self, name):
     else:
         # Request prototypes
         _c_request_helper(self, name, void=True, regular=False)
         _c_request_helper(self, name, void=True, regular=True)
         if self.c_need_aux:
             _c_request_helper(self, name, void=True, regular=False, aux=True)
             _c_request_helper(self, name, void=True, regular=True, aux=True)
-        if config_server_side:
-            _c_accessors(self, name, name)
-
+        for field in self.fields:
+            if not field.type.is_pad and field.wire:
+                if _c_field_needs_list_accessor(field):
+                    _c_accessors_list(self, field)
+                elif _c_field_needs_field_accessor(field):
+                    _c_accessors_field(self, field)
     # We generate the manpage afterwards because _c_type_setup has been called.
     # TODO: what about aux helpers?
     _man_request(self, name, void=not self.reply, aux=False)
 
 def c_event(self, name):
     '''
     Exported function that handles event declarations.
-- 
2.1.4



More information about the Xcb mailing list