summaryrefslogtreecommitdiff
path: root/external/construct/lib/container.py
diff options
context:
space:
mode:
Diffstat (limited to 'external/construct/lib/container.py')
-rw-r--r--external/construct/lib/container.py224
1 files changed, 224 insertions, 0 deletions
diff --git a/external/construct/lib/container.py b/external/construct/lib/container.py
new file mode 100644
index 0000000..f04d037
--- /dev/null
+++ b/external/construct/lib/container.py
@@ -0,0 +1,224 @@
+"""
+Various containers.
+"""
+
+def recursion_lock(retval, lock_name = "__recursion_lock__"):
+ def decorator(func):
+ def wrapper(self, *args, **kw):
+ if getattr(self, lock_name, False):
+ return retval
+ setattr(self, lock_name, True)
+ try:
+ return func(self, *args, **kw)
+ finally:
+ setattr(self, lock_name, False)
+ wrapper.__name__ = func.__name__
+ return wrapper
+ return decorator
+
+class Container(dict):
+ """
+ A generic container of attributes.
+
+ Containers are the common way to express parsed data.
+ """
+ __slots__ = ["__keys_order__"]
+
+ def __init__(self, **kw):
+ object.__setattr__(self, "__keys_order__", [])
+ for k, v in kw.items():
+ self[k] = v
+ def __getattr__(self, name):
+ try:
+ return self[name]
+ except KeyError:
+ raise AttributeError(name)
+ def __setitem__(self, key, val):
+ if key not in self:
+ self.__keys_order__.append(key)
+ dict.__setitem__(self, key, val)
+ def __delitem__(self, key):
+ dict.__delitem__(self, key)
+ self.__keys_order__.remove(key)
+
+ __delattr__ = __delitem__
+ __setattr__ = __setitem__
+
+ def clear(self):
+ dict.clear(self)
+ del self.__keys_order__[:]
+ def pop(self, key, *default):
+ val = dict.pop(self, key, *default)
+ self.__keys_order__.remove(key)
+ return val
+ def popitem(self):
+ k, v = dict.popitem(self)
+ self.__keys_order__.remove(k)
+ return k, v
+
+ def update(self, seq, **kw):
+ if hasattr(seq, "keys"):
+ for k in seq.keys():
+ self[k] = seq[k]
+ else:
+ for k, v in seq:
+ self[k] = v
+ dict.update(self, kw)
+
+ def copy(self):
+ inst = self.__class__()
+ inst.update(self.iteritems())
+ return inst
+
+ __update__ = update
+ __copy__ = copy
+
+ def __iter__(self):
+ return iter(self.__keys_order__)
+ iterkeys = __iter__
+ def itervalues(self):
+ return (self[k] for k in self.__keys_order__)
+ def iteritems(self):
+ return ((k, self[k]) for k in self.__keys_order__)
+ def keys(self):
+ return self.__keys_order__
+ def values(self):
+ return list(self.itervalues())
+ def items(self):
+ return list(self.iteritems())
+
+ def __repr__(self):
+ return "%s(%s)" % (self.__class__.__name__, dict.__repr__(self))
+
+ @recursion_lock("<...>")
+ def __pretty_str__(self, nesting = 1, indentation = " "):
+ attrs = []
+ ind = indentation * nesting
+ for k, v in self.iteritems():
+ if not k.startswith("_"):
+ text = [ind, k, " = "]
+ if hasattr(v, "__pretty_str__"):
+ text.append(v.__pretty_str__(nesting + 1, indentation))
+ else:
+ text.append(repr(v))
+ attrs.append("".join(text))
+ if not attrs:
+ return "%s()" % (self.__class__.__name__,)
+ attrs.insert(0, self.__class__.__name__ + ":")
+ return "\n".join(attrs)
+
+ __str__ = __pretty_str__
+
+
+class FlagsContainer(Container):
+ """
+ A container providing pretty-printing for flags.
+
+ Only set flags are displayed.
+ """
+
+ @recursion_lock("<...>")
+ def __pretty_str__(self, nesting = 1, indentation = " "):
+ attrs = []
+ ind = indentation * nesting
+ for k in self.keys():
+ v = self[k]
+ if not k.startswith("_") and v:
+ attrs.append(ind + k)
+ if not attrs:
+ return "%s()" % (self.__class__.__name__,)
+ attrs.insert(0, self.__class__.__name__+ ":")
+ return "\n".join(attrs)
+
+
+class ListContainer(list):
+ """
+ A container for lists.
+ """
+ __slots__ = ["__recursion_lock__"]
+
+ def __str__(self):
+ return self.__pretty_str__()
+
+ @recursion_lock("[...]")
+ def __pretty_str__(self, nesting = 1, indentation = " "):
+ if not self:
+ return "[]"
+ ind = indentation * nesting
+ lines = ["["]
+ for elem in self:
+ lines.append("\n")
+ lines.append(ind)
+ if hasattr(elem, "__pretty_str__"):
+ lines.append(elem.__pretty_str__(nesting + 1, indentation))
+ else:
+ lines.append(repr(elem))
+ lines.append("\n")
+ lines.append(indentation * (nesting - 1))
+ lines.append("]")
+ return "".join(lines)
+
+
+class LazyContainer(object):
+
+ __slots__ = ["subcon", "stream", "pos", "context", "_value"]
+
+ def __init__(self, subcon, stream, pos, context):
+ self.subcon = subcon
+ self.stream = stream
+ self.pos = pos
+ self.context = context
+ self._value = NotImplemented
+
+ def __eq__(self, other):
+ try:
+ return self._value == other._value
+ except AttributeError:
+ return False
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def __str__(self):
+ return self.__pretty_str__()
+
+ def __pretty_str__(self, nesting = 1, indentation = " "):
+ if self._value is NotImplemented:
+ text = "<unread>"
+ elif hasattr(self._value, "__pretty_str__"):
+ text = self._value.__pretty_str__(nesting, indentation)
+ else:
+ text = str(self._value)
+ return "%s: %s" % (self.__class__.__name__, text)
+
+ def read(self):
+ self.stream.seek(self.pos)
+ return self.subcon._parse(self.stream, self.context)
+
+ def dispose(self):
+ self.subcon = None
+ self.stream = None
+ self.context = None
+ self.pos = None
+
+ def _get_value(self):
+ if self._value is NotImplemented:
+ self._value = self.read()
+ return self._value
+
+ value = property(_get_value)
+
+ has_value = property(lambda self: self._value is not NotImplemented)
+
+
+
+if __name__ == "__main__":
+ c = Container(x=5)
+ c.y = 8
+ c.z = 9
+ c.w = 10
+ c.foo = 5
+
+ print (c)
+
+