array.py :  » Windows » Python-File-Format-Interface » PyFFI-2.1.4 » pyffi » object_models » xml » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Windows » Python File Format Interface 
Python File Format Interface » PyFFI 2.1.4 » pyffi » object_models » xml » array.py
"""Implements class for arrays."""

# --------------------------------------------------------------------------
# ***** BEGIN LICENSE BLOCK *****
#
# Copyright (c) 2007-2009, Python File Format Interface
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#
#    * Redistributions in binary form must reproduce the above
#      copyright notice, this list of conditions and the following
#      disclaimer in the documentation and/or other materials provided
#      with the distribution.
#
#    * Neither the name of the Python File Format Interface
#      project nor the names of its contributors may be used to endorse
#      or promote products derived from this software without specific
#      prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# ***** END LICENSE BLOCK *****
# --------------------------------------------------------------------------

# note: some imports are defined at the end to avoid problems with circularity

import weakref

from pyffi.utils.graph import DetailNode,EdgeFilter

class _ListWrap(list, DetailNode):
    """A wrapper for list, which uses get_value and set_value for
    getting and setting items of the basic type."""

    def __init__(self, element_type, parent = None):
        self._parent = weakref.ref(parent) if parent else None
        self._elementType = element_type
        # we link to the unbound methods (that is, self.__class__.xxx
        # instead of self.xxx) to avoid circular references!!
        if issubclass(element_type, BasicBase):
            self._get_item_hook = self.__class__.get_basic_item
            self._set_item_hook = self.__class__.set_basic_item
            self._iter_item_hook = self.__class__.iter_basic_item
        else:
            self._get_item_hook = self.__class__.get_item
            self._set_item_hook = self.__class__._not_implemented_hook
            self._iter_item_hook = self.__class__.iter_item

    def __getitem__(self, index):
        return self._get_item_hook(self, index)

    def __setitem__(self, index, value):
        return self._set_item_hook(self, index, value)

    def __iter__(self):
        return self._iter_item_hook(self)

    def __contains__(self, value):
        # ensure that the "in" operator uses self.__iter__() rather than
        # list.__iter__()
        for elem in self.__iter__():
            if elem == value:
                return True
        return False

    def _not_implemented_hook(self, *args):
        """A hook for members that are not implemented."""
        raise NotImplementedError

    def iter_basic_item(self):
        """Iterator which calls C{get_value()} on all items. Applies when
        the list has BasicBase elements."""
        for elem in list.__iter__(self):
            yield elem.get_value()

    def iter_item(self):
        """Iterator over all items. Applies when the list does not have
        BasicBase elements."""
        for elem in list.__iter__(self):
            yield elem

    def get_basic_item(self, index):
        """Item getter which calls C{get_value()} on the C{index}'d item."""
        return list.__getitem__(self, index).get_value()

    def set_basic_item(self, index, value):
        """Item setter which calls C{set_value()} on the C{index}'d item."""
        return list.__getitem__(self, index).set_value(value)

    def get_item(self, index):
        """Regular item getter, used when the list does not have BasicBase
        elements."""
        return list.__getitem__(self, index)

    # DetailNode

    def get_detail_child_nodes(self, edge_filter=EdgeFilter()):
        """Yield children."""
        return (item for item in list.__iter__(self))

    def get_detail_child_names(self, edge_filter=EdgeFilter()):
        """Yield child names."""
        return ("[%i]" % row for row in xrange(list.__len__(self)))

class Array(_ListWrap):
    """A general purpose class for 1 or 2 dimensional arrays consisting of
    either BasicBase or StructBase elements."""

    def __init__(
        self,
        element_type = None,
        element_type_template = None,
        element_type_argument = None,
        count1 = None, count2 = None,
        parent = None):
        """Initialize the array type.

        :param element_type: The class describing the type of each element.
        :param element_type_template: If the class takes a template type
            argument, then this argument describes the template type.
        :param element_type_argument: If the class takes a type argument, then
            it is described here.
        :param count1: An C{Expression} describing the count (first dimension).
        :param count2: Either ``None``, or an C{Expression} describing the
            second dimension count.
        :param parent: The parent of this instance, that is, the instance this
            array is an attribute of."""
        if count2 is None:
            _ListWrap.__init__(self,
                               element_type = element_type, parent = parent)
        else:
            _ListWrap.__init__(self,
                               element_type = _ListWrap, parent = parent)
        self._elementType = element_type
        self._parent = weakref.ref(parent) if parent else None
        self._elementTypeTemplate = element_type_template
        self._elementTypeArgument = element_type_argument
        self._count1 = count1
        self._count2 = count2

        if self._count2 == None:
            for i in xrange(self._len1()):
                elem_instance = self._elementType(
                        template = self._elementTypeTemplate,
                        argument = self._elementTypeArgument,
                        parent = self)
                self.append(elem_instance)
        else:
            for i in xrange(self._len1()):
                elem = _ListWrap(element_type = element_type, parent = self)
                for j in xrange(self._len2(i)):
                    elem_instance = self._elementType(
                            template = self._elementTypeTemplate,
                            argument = self._elementTypeArgument,
                            parent = elem)
                    elem.append(elem_instance)
                self.append(elem)

    def _len1(self):
        """The length the array should have, obtained by evaluating
        the count1 expression."""
        if self._parent is None:
            return self._count1.eval()
        else:
            return self._count1.eval(self._parent())

    def _len2(self, index1):
        """The length the array should have, obtained by evaluating
        the count2 expression."""
        if self._count2 == None:
            raise ValueError('single array treated as double array (bug?)')
        if self._parent is None:
            expr = self._count2.eval()
        else:
            expr = self._count2.eval(self._parent())
        if isinstance(expr, (int, long)):
            return expr
        else:
            return expr[index1]

    def deepcopy(self, block):
        """Copy attributes from a given array which needs to have at least as
        many elements (possibly more) as self."""
        if self._count2 == None:
            for i in xrange(self._len1()):
                attrvalue = self[i]
                if isinstance(attrvalue, StructBase):
                    attrvalue.deepcopy(block[i])
                elif isinstance(attrvalue, Array):
                    attrvalue.update_size()
                    attrvalue.deepcopy(block[i])
                else:
                    self[i] = block[i]
        else:
            for i in xrange(self._len1()):
                for j in xrange(self._len2(i)):
                    attrvalue = self[i][j]
                    if isinstance(attrvalue, StructBase):
                        attrvalue.deepcopy(block[i][j])
                    elif isinstance(attrvalue, Array):
                        attrvalue.update_size()
                        attrvalue.deepcopy(block[i][j])
                    else:
                        self[i][j] = block[i][j]

    # string of the array
    def __str__(self):
        text = '%s instance at 0x%08X\n' % (self.__class__, id(self))
        if self._count2 == None:
            for i, element in enumerate(list.__iter__(self)):
                if i > 16:
                    text += "etc...\n"
                    break
                text += "%i: %s" % (i, element)
                if text[-1:] != "\n":
                    text += "\n"
        else:
            k = 0
            for i, elemlist in enumerate(list.__iter__(self)):
                for j, elem in enumerate(list.__iter__(elemlist)):
                    if k > 16:
                        text += "etc...\n"
                        break
                    text += "%i, %i: %s" % (i, j, elem)
                    if text[-1:] != "\n":
                        text += "\n"
                    k += 1
                if k > 16:
                    break
        return text

    def update_size(self):
        """Update the array size. Call this function whenever the size
        parameters change in C{parent}."""
        ## TODO also update row numbers
        old_size = len(self)
        new_size = self._len1()
        if self._count2 == None:
            if new_size < old_size:
                del self[new_size:old_size]
            else:
                for i in xrange(new_size-old_size):
                    elem = self._elementType(
                        template = self._elementTypeTemplate,
                        argument = self._elementTypeArgument)
                    self.append(elem)
        else:
            if new_size < old_size:
                del self[new_size:old_size]
            else:
                for i in xrange(new_size-old_size):
                    self.append(_ListWrap(self._elementType))
            for i, elemlist in enumerate(list.__iter__(self)):
                old_size_i = len(elemlist)
                new_size_i = self._len2(i)
                if new_size_i < old_size_i:
                    del elemlist[new_size_i:old_size_i]
                else:
                    for j in xrange(new_size_i-old_size_i):
                        elem = self._elementType(
                            template = self._elementTypeTemplate,
                            argument = self._elementTypeArgument)
                        elemlist.append(elem)

    def read(self, stream, **kwargs):
        """Read array from stream."""
        # parse arguments
        self._elementTypeArgument = kwargs.get('argument')
        # check array size
        len1 = self._len1()
        if len1 > 2000000:
            raise ValueError('array too long (%i)' % len1)
        del self[0:self.__len__()]
        # read array
        if self._count2 == None:
            for i in xrange(len1):
                elem = self._elementType(
                    template = self._elementTypeTemplate,
                    argument = self._elementTypeArgument,
                    parent = self)
                elem.read(stream, **kwargs)
                self.append(elem)
        else:
            for i in xrange(len1):
                len2i = self._len2(i)
                if len2i > 2000000:
                    raise ValueError('array too long (%i)' % len2i)
                elemlist = _ListWrap(self._elementType, parent = self)
                for j in xrange(len2i):
                    elem = self._elementType(
                        template = self._elementTypeTemplate,
                        argument = self._elementTypeArgument,
                        parent = elemlist)
                    elem.read(stream, **kwargs)
                    elemlist.append(elem)
                self.append(elemlist)

    def write(self, stream, **kwargs):
        """Write array to stream."""
        self._elementTypeArgument = kwargs.get('argument')
        len1 = self._len1()
        if len1 != self.__len__():
            raise ValueError('array size (%i) different from to field \
describing number of elements (%i)'%(self.__len__(),len1))
        if len1 > 2000000:
            raise ValueError('array too long (%i)' % len1)
        if self._count2 == None:
            for elem in list.__iter__(self):
                elem.write(stream, **kwargs)
        else:
            for i, elemlist in enumerate(list.__iter__(self)):
                len2i = self._len2(i)
                if len2i != elemlist.__len__():
                    raise ValueError("array size (%i) different from to field \
describing number of elements (%i)"%(elemlist.__len__(),len2i))
                if len2i > 2000000:
                    raise ValueError('array too long (%i)' % len2i)
                for elem in list.__iter__(elemlist):
                    elem.write(stream, **kwargs)

    def fix_links(self, **kwargs):
        """Fix the links in the array by calling C{fix_links} on all elements
        of the array."""
        if not self._elementType._has_links:
            return
        for elem in self._elementList():
            elem.fix_links(**kwargs)

    def get_links(self, **kwargs):
        """Return all links in the array by calling C{get_links} on all elements
        of the array."""
        links = []
        if not self._elementType._has_links:
            return links
        for elem in self._elementList():
            links.extend(elem.get_links(**kwargs))
        return links

    def get_strings(self, **kwargs):
        """Return all strings in the array by calling C{get_strings} on all
        elements of the array."""
        strings = []
        if not self._elementType._has_strings:
            return strings
        for elem in self._elementList():
            strings.extend(elem.get_strings(**kwargs))
        return strings

    def get_refs(self, **kwargs):
        """Return all references in the array by calling C{get_refs} on all
        elements of the array."""
        links = []
        if not self._elementType._has_links:
            return links
        for elem in self._elementList():
            links.extend(elem.get_refs(**kwargs))
        return links

    def get_size(self, **kwargs):
        """Calculate the sum of the size of all elements in the array."""
        return sum(
            (elem.get_size(**kwargs) for elem in self._elementList()), 0)

    def get_hash(self, **kwargs):
        """Calculate a hash value for the array, as a tuple."""
        hsh = []
        for elem in self._elementList():
            hsh.append(elem.get_hash(**kwargs))
        return tuple(hsh)

    def replace_global_node(self, oldbranch, newbranch, **kwargs):
        """Calculate a hash value for the array, as a tuple."""
        for elem in self._elementList():
            elem.replace_global_node(oldbranch, newbranch, **kwargs)

    def _elementList(self, **kwargs):
        """Generator for listing all elements."""
        if self._count2 is None:
            for elem in list.__iter__(self):
                yield elem
        else:
            for elemlist in list.__iter__(self):
                for elem in list.__iter__(elemlist):
                    yield elem

from pyffi.object_models.xml.basic import BasicBase
from pyffi.object_models.xml.struct_ import StructBase
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.