summaryrefslogtreecommitdiffstats
path: root/pym/portage/cache/mappings.py
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2008-06-25 22:36:19 +0000
committerZac Medico <zmedico@gentoo.org>2008-06-25 22:36:19 +0000
commit04066d484cf68bda8de37c037aad003a44088e8a (patch)
treec1b7bc121c23ac651303c8d91e896f6622fa5bc7 /pym/portage/cache/mappings.py
parent4ac209e6cf6c49d88b06a4ddaa3bacd11695791d (diff)
downloadportage-04066d484cf68bda8de37c037aad003a44088e8a.tar.gz
portage-04066d484cf68bda8de37c037aad003a44088e8a.tar.bz2
portage-04066d484cf68bda8de37c037aad003a44088e8a.zip
Add a generic portage.cache.mappings.slot_dict_class() function which
generates mapping classes that behave similar to a dict but store values as object attributes that are allocated via __slots__. Instances of these objects have a smaller memory footprint than a normal dict object. These classes are used to reduce the memory footprint of the dbapi.aux_get() caches and the Package.metadata attribute. svn path=/main/trunk/; revision=10790
Diffstat (limited to 'pym/portage/cache/mappings.py')
-rw-r--r--pym/portage/cache/mappings.py126
1 files changed, 126 insertions, 0 deletions
diff --git a/pym/portage/cache/mappings.py b/pym/portage/cache/mappings.py
index 9aa5a21e2..7c347a4f9 100644
--- a/pym/portage/cache/mappings.py
+++ b/pym/portage/cache/mappings.py
@@ -4,6 +4,7 @@
# $Id$
import UserDict
+import weakref
class ProtectedDict(UserDict.DictMixin):
"""
@@ -101,3 +102,128 @@ class LazyLoad(UserDict.DictMixin):
self.pull = None
return key in self.d
+_slot_dict_classes = weakref.WeakValueDictionary()
+
+def slot_dict_class(keys):
+ if isinstance(keys, frozenset):
+ keys_set = keys
+ else:
+ keys_set = frozenset(keys)
+ v = _slot_dict_classes.get(keys_set)
+ if v is None:
+
+ class SlotDict(object):
+
+ _keys = keys_set
+ __slots__ = ("__weakref__",) + tuple("_val_" + k for k in _keys)
+
+ def __iter__(self):
+ for k, v in self.iteritems():
+ yield k
+
+ def __len__(self):
+ l = 0
+ for i in self.iteritems():
+ l += 1
+ return l
+
+ def keys(self):
+ return list(self)
+
+ def iteritems(self):
+ for k in self._keys:
+ try:
+ yield (k, getattr(self, "_val_" + k))
+ except AttributeError:
+ pass
+
+ def items(self):
+ return list(self.iteritems())
+
+ def itervalues(self):
+ for k, v in self.itervalues():
+ yield v
+
+ def values(self):
+ return list(self.itervalues())
+
+ def __delitem__(self, k):
+ try:
+ delattr(self, "_val_" + k)
+ except AttributeError:
+ raise KeyError(k)
+
+ def __setitem__(self, k, v):
+ setattr(self, "_val_" + k, v)
+
+ def setdefault(self, key, default=None):
+ try:
+ return self[key]
+ except KeyError:
+ self[key] = default
+ return default
+
+ def update(self, d):
+ i = getattr(d, "iteritems", None)
+ if i is None:
+ i = d
+ else:
+ i = i()
+ for k, v in i:
+ self[k] = v
+
+ def __getitem__(self, k):
+ try:
+ return getattr(self, "_val_" + k)
+ except AttributeError:
+ raise KeyError(k)
+
+ def get(self, key, default=None):
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+ def __contains__(self, k):
+ return hasattr(self, "_val_" + k)
+
+ def has_key(self, k):
+ return k in self
+
+ def pop(self, key, *args):
+ if len(args) > 1:
+ raise TypeError(
+ "pop expected at most 2 arguments, got " + \
+ repr(1 + len(args)))
+ try:
+ value = self[key]
+ except KeyError:
+ if args:
+ return args[0]
+ raise
+ del self[key]
+ return value
+
+ def popitem(self):
+ try:
+ k, v = self.iteritems().next()
+ except StopIteration:
+ raise KeyError, 'container is empty'
+ del self[k]
+ return (k, v)
+
+ def copy(self):
+ c = self.__class__()
+ c.update(self)
+ return c
+
+ def clear(self):
+ for k in self._keys:
+ try:
+ delattr(self, "_val_" + k)
+ except AttributError:
+ pass
+
+ v = SlotDict
+ _slot_dict_classes[keys_set] = v
+ return v