Exemplo n.º 1
0
def _PythonToCtype(data, c_type):
    """Populate a ctypes data type with a Python structure."""
    if c_type is actuator_util.Vec3:
        # Handle Vec3.
        assert len(data) == 3
        c_data = c_type()
        c_data.x = data[0]
        c_data.y = data[1]
        c_data.z = data[2]
        return c_data
    elif hasattr(c_type, '_length_'):
        # Handle arrays.
        length = getattr(c_type, '_length_')
        assert len(data) == length

        c_data = c_type()
        for i in range(length):
            c_data[i] = _PythonToCtype(data[i], getattr(c_type, '_type_'))

    elif hasattr(c_type, '_fields_'):
        # Handle structures.
        fields = autogen_util.GetCFields(c_type)
        assert set(data.keys()) == {field for field, _ in fields}

        c_data = c_type()
        for field, field_type in fields:
            setattr(c_data, field, _PythonToCtype(data[field], field_type))

    else:
        c_data = c_type(data)

    return c_data
Exemplo n.º 2
0
def FindChildTypes(parent):
  """Return name of all the substructures on which a parent struct depends."""
  struct_lst = []
  ctype_lst = []
  for _, field_type in autogen_util.GetCFields(parent):
    if isinstance(field_type, type(ctypes.Array)):
      t = field_type()._type_
    else:
      t = field_type
    if isinstance(t, type(ctypes.Structure)):
      struct_lst.append(t.__name__)
      slst, clst = FindChildTypes(t)
      struct_lst += slst
      ctype_lst += clst
    # Matches any of the fundamental c types
    elif isinstance(t, type(ctypes.c_double)):
      ctype_lst.append(t.__name__)
  return struct_lst, ctype_lst
Exemplo n.º 3
0
def WritePackFunc(f, s, is_static, name=None):
  """Writes a pack function."""
  if not name:
    name = ConvTypeToStr(s)[0]
  f.write('\n'
          '\n%ssize_t %s(const %s *in, size_t num, uint8_t *out) {'
          '\n  size_t byte_ind = 0U, elmt_ind;'
          '\n  for (elmt_ind = 0U; elmt_ind < num; ++elmt_ind) {'
          % (GetStaticStr(is_static), GenPackFuncName(name),
             name))
  for field_name, field_type in autogen_util.GetCFields(s):
    type_str, num, dim = ConvTypeToStr(field_type)
    if field_name in s._enums_:
      type_str = s._enums_[field_name]
    f.write('\n    byte_ind += %s(&in[elmt_ind].%s%s, %d, &out[byte_ind]);'
            % (GenPackFuncName(type_str), field_name, '[0]'*dim, num))
  f.write('\n  }'
          '\n  return byte_ind;'
          '\n}')
Exemplo n.º 4
0
def GetTypePackedSize(t):
  if isinstance(t, type(ctypes.c_double)):
    if t == ctypes.c_double:
      return 8
    elif t == ctypes.c_float:
      return 4
    elif t == ctypes.c_int8:
      return 1
    elif t == ctypes.c_int16:
      return 2
    elif t == ctypes.c_int32:
      return 4
    elif t == ctypes.c_int64:
      return 8
    elif t == ctypes.c_int:
      return 4
    elif t == ctypes.c_uint8:
      return 1
    elif t == ctypes.c_uint16:
      return 2
    elif t == ctypes.c_uint32:
      return 4
    elif t == ctypes.c_uint64:
      return 8
    elif t == ctypes.c_uint:
      return 4
    elif t == ctypes.c_char:
      return 1
    elif t == ctypes.c_bool:
      return 1
    else:
      raise ValueError('Unrecognized type: %s' % t)
  elif isinstance(t, type(ctypes.Structure)):
    num_bytes = 0
    for (_, field_type) in autogen_util.GetCFields(t):
      num_bytes += GetTypePackedSize(field_type)
    return num_bytes
  elif isinstance(t, type(ctypes.Array)):
    return GetTypePackedSize(t()._type_) * len(t())
  else:
    raise ValueError('Unrecognized type: %s' % t)
Exemplo n.º 5
0
def GetRequiredTypes(t):
    """Get types whose loading functions are required to load a given type.

  Args:
    t: A type.

  Returns:
    A set of types whose loading functions are required to implement
    the loading function for t.
  """
    types = set()
    if _IsArrayType(t):
        scalar_type = _ArrayCTypeScalarType(t)
        types = {scalar_type}
        types = types.union(GetRequiredTypes(scalar_type))
    elif _IsStructType(t):
        fields = autogen_util.GetCFields(t)
        types = {f_type for (_, f_type) in fields}
        types = types.union(
            *[GetRequiredTypes(f_type) for (_, f_type) in fields])

    return types
Exemplo n.º 6
0
  def _MessageStructToDtype(ctype):
    """Construct a numpy dtype from a ctypes type.

    This function exists because numpy's dtype constructor squeezes
    multidimensional arrays and converts ctypes.c_char to length one
    strings (see see b/26933384).

    This function does not respect the underlying ctype's alignment.
    In the context of _MessageStructToH5T this is fine, as we later
    pack the structure.

    Args:
      ctype: Type to convert.

    Returns:
      A numpy.dtype.  This type may not have the correct offsets.

    Raises:
      InvalidCtypeException: if a type is encountered that isn't a
          Structure, Array, c_char, or a member of the _ALLOWED_BASIC_CTYPES.
    """
    if isinstance(ctype, type(ctypes.Structure)):
      names, fields = zip(*autogen_util.GetCFields(ctype))
      field_dtypes = [_MessageStructToDtype(f) for f in fields]
      return numpy.dtype(zip(names, field_dtypes))
    elif type(ctype) is type(ctypes.Array):
      return numpy.dtype((_MessageStructToDtype(getattr(ctype, '_type_')),
                          (getattr(ctype, '_length_'),)))
    elif ctype == ctypes.c_char:
      # Numpy converts ctypes.c_char to 'S1', i.e. a string of length
      # one.  This is generally not desired, and in particular, causes
      # MATLAB to expect scalar characters to be null-terminated strings
      # (see b/26933384).  This branch is added to force character
      # arrays to be regarded as byte arrays.
      return 'u1'
    elif ctype in _ALLOWED_BASIC_CTYPES:
      return numpy.dtype(ctype)
    else:
      raise InvalidCtypeException('Invalid ctypes type.', ctype)
Exemplo n.º 7
0
def _NativeStructToH5T(ctype):
  """Creates an HDF5 Type object from a ctypes type.

  This function exists as h5t.py_create does not respect field
  alignment, and the conversion of ctypes.c_char to length one strings
  is undesired.

  Args:
    ctype: Type to convert.

  Returns:
    HDF5 type object with correct size and offsets.

  Raises:
    InvalidCtypeException: if a type is encountered that isn't a
        Structure, Array, c_char, or a member of the _ALLOWED_BASIC_CTYPES.
  """
  if isinstance(ctype, type(ctypes.Structure)):
    t = h5py.h5t.create(h5py.h5t.COMPOUND, ctypes.sizeof(ctype))
    for (field_name, field_type) in autogen_util.GetCFields(ctype):
      t.insert(field_name, getattr(ctype, field_name).offset,
               _NativeStructToH5T(field_type))
    return t
  elif type(ctype) is type(ctypes.Array):
    return h5py.h5t.array_create(
        _NativeStructToH5T(getattr(ctype, '_type_')),
        (getattr(ctype, '_length_'),))
  elif ctype == ctypes.c_char:
    # The py_create function, like numpy's dtype constructor, converts
    # characters into strings. This branch is added to force
    # character arrays to be regarded as byte arrays.
    return h5py.h5t.py_create(ctypes.c_uint8)
  elif ctype in _ALLOWED_BASIC_CTYPES:
    return h5py.h5t.py_create(ctype)
  else:
    raise InvalidCtypeException('Invalid ctypes type.', ctype)
Exemplo n.º 8
0
def MatchesCStruct(pytype, pyclass, parent=''):
    """Checks if the Python type matches an equivalent C type.

  This will display in bold any fields that are in one of pytype and
  pyclass but not the other.

  Args:
    pytype: Python dictionary to be compared to a C struct.
    pyclass: ctypes Python class equivalent to a C struct.
    parent: A string used in recursive calls to the function to keep
        track of the parent fields so they may be displayed.

  Returns:
    True if the dictionary and ctypes Python class match,
    otherwise False.
  """
    def Bold(s):
        return '\033[1m' + s + '\033[0m'

    if hasattr(pyclass, '_fields_'):
        fields = autogen_util.GetCFields(pyclass)
        # If we are at a leaf struct (like Vec3 or Quat), the pytype can
        # use an array rather than a dictionary.
        if (isinstance(pytype, list) and len(pytype) == len(fields)
                and all([c == ctypes.c_double for (_, c) in fields])):
            all_floats = True
            for i in range(len(pytype)):
                if not isinstance(pytype[i], float):
                    print Bold('%s[%d] must be a float.' % (parent, i))
                    all_floats = False
            return all_floats

        diff = set(pytype) ^ {k for (k, _) in fields}
        if diff:
            print Bold(parent + '.{' + ', '.join(diff) +
                       '}') + ' are different.'
            return False
        for k, c in fields:
            if not MatchesCStruct(pytype[k], c, parent + '.' + k):
                return False
        return True

    elif hasattr(pyclass, '_length_'):
        if isinstance(pytype, str):
            if getattr(pyclass, '_type_') is not ctypes.c_char:
                print Bold(parent) + ' should not be a string.\n'
                return False
            elif len(pytype) + 1 > getattr(pyclass, '_length_'):
                # Strings can be shorter than the allotted array (but require
                # room for null termination).
                print Bold(parent) + ' has the wrong length.\n'
                return False
            else:
                return True
        else:
            expected_length = getattr(pyclass, '_length_')
            try:
                actual_length = len(pytype)
            except TypeError:
                print(
                    Bold(parent) +
                    ' is expected to be an array of length %d.' %
                    expected_length)
                return False
            if actual_length != expected_length:
                print(
                    Bold(parent) +
                    ' has the wrong length (expected %d, actual %d).\n' %
                    (expected_length, actual_length))
                return False
            else:
                expected_type = getattr(pyclass, '_type_')
                return all([
                    MatchesCStruct(pytype[i], expected_type,
                                   '%s[%d]' % (parent, i))
                    for i in xrange(len(pytype))
                ])

    else:
        # Check that scalar types are properly specified.
        if pyclass == ctypes.c_double and not isinstance(pytype, float):
            print Bold(parent + ' must be a float.')
            return False
        elif pyclass == ctypes.c_int and not isinstance(pytype, int):
            print Bold(parent + ' must be an int.')
            return False
        elif pyclass == ctypes.c_bool and not isinstance(pytype, bool):
            print Bold(parent + ' must be a bool.')
            return False
        return True
Exemplo n.º 9
0
def _GetStruct(type_id, path):
  """Recursively parse a ctypes structure to build a (path, type) list."""
  out = []
  for field_name, field_type in autogen_util.GetCFields(type_id):
    out.extend(_GetType(field_type, path + '.' + field_name))
  return out
Exemplo n.º 10
0
def GetLoadFunc(t):
    """Generate the JSON loading implementation for a given type.

  Args:
    t: A type.

  Returns:
    A pair containing C code.  The first element is a string with the prototype
    of the function and the second element is a list of strings giving the lines
    of C code.

  Raises:
    TypeError: The given type is a string type, a fundamental type, or unknown.
  """
    prototype = _GetLoadFunctionPrototype(t)
    body = []  # This will be an array strings corresponding to lines of code.

    if _IsArrayType(t):
        (_, _, args) = _GetTypeInfo(t)
        body = [
            'if (JSONLoadArrayCheck(obj, len0) < 0) return -1;',
            'int32_t status;'
        ]

        sub_dim = ['len%d' % d for d in range(1, len(args))]
        if sub_dim:
            # TODO: Check for overflow?
            body += ['uint32_t stride = %s;' % ' * '.join(sub_dim)]
            dst = '&s[i*stride]'
        else:
            dst = 's[i]'

        scalar_type = _ArrayCTypeScalarType(t)
        body += [
            'for (uint32_t i = 0U; i < len0; ++i) {', '  ' + _GetLoadFuncCall(
                scalar_type, 'json_array_get(obj, i)', dst, 'status', sub_dim),
            '  if (status == -1) {', '    JSONLoadPrintIndexError(i);',
            '    return -1;', '  }', '}', 'return 0;'
        ]

    elif _IsStructType(t):
        fields = autogen_util.GetCFields(t)
        body = [
            'if (s == NULL) return -1;',
            'if (JSONLoadStructCheck(obj, %uU) < 0) return -1;' % len(fields),
            'json_t *value;', 'int32_t status;', ''
        ]
        for (f_name, f_type) in fields:
            body += [
                'value = JSONLoadStructGet(obj, "%s");' % f_name,
                'if (value == NULL) return -1;',
                _GetLoadFuncCall(f_type, 'value', 's->%s' % f_name,
                                 'status'), 'if (status == -1) {',
                '  JSONLoadPrintKeyError("%s");' % f_name, '  return -1;', '}',
                ''
            ]
        body += ['return 0;']

    # These functions are hand written in the files json_load_basic.{c,h}.
    elif _IsFundamentalType(t) or _IsStringType(t):
        raise TypeError('Cannot generate load function for type %s.' % str(t))

    else:
        raise TypeError('Unknown type: %s.' % str(t))

    return (prototype, ['' if not line else '  ' + line for line in body])