Index: infra/libs/data_structures/data_structures.py |
diff --git a/infra/libs/data_structures/data_structures.py b/infra/libs/data_structures/data_structures.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9bf2214be71c2afc71bfb4820848231d9e8e9111 |
--- /dev/null |
+++ b/infra/libs/data_structures/data_structures.py |
@@ -0,0 +1,69 @@ |
+# Copyright 2014 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+import collections |
Vadim Sh.
2014/06/27 18:26:22
nit: \n
iannucci
2014/06/28 08:33:35
Done.
|
+import operator |
+ |
+ |
+def freeze(obj): |
Vadim Sh.
2014/06/27 18:26:22
if |obj| is already frozen, it makes a copy. In th
iannucci
2014/06/28 08:33:35
Don't think this is the case
|
+ """Takes a jsonish object |obj|, and returns an immutable version of it.""" |
Vadim Sh.
2014/06/27 18:26:22
There's no asserts anywhere that verify it's 'json
iannucci
2014/06/28 08:33:35
Clarified in the comment
|
+ if isinstance(obj, dict): |
+ return FrozenDict((freeze(k), freeze(v)) for k, v in obj.iteritems()) |
+ elif isinstance(obj, list): |
Vadim Sh.
2014/06/27 18:26:22
tuples with non-frozen items will not be frozen.
iannucci
2014/06/28 08:33:35
Done.
|
+ return tuple(freeze(i) for i in obj) |
+ elif isinstance(obj, set): |
+ return frozenset(freeze(i) for i in obj) |
+ else: |
+ hash(obj) |
Vadim Sh.
2014/06/27 18:26:21
assert getattr(obj, '__hash__' , None), 'Can\'t fr
iannucci
2014/06/28 08:33:35
it recurses, so 'guarantees' that all objects insi
|
+ return obj |
+ |
+ |
+def thaw(obj): |
+ """Takes an object from freeze() and returns a mutable copy of it.""" |
+ if isinstance(obj, FrozenDict): |
+ return collections.OrderedDict( |
+ (thaw(k), thaw(v)) for k, v in obj.iteritems()) |
+ elif isinstance(obj, tuple): |
+ return list(thaw(i) for i in obj) |
Vadim Sh.
2014/06/27 18:26:22
distinction between tuples and lists will be lost
iannucci
2014/06/28 08:33:35
disinclined to care... that seems like a much hard
|
+ elif isinstance(obj, frozenset): |
+ return set(thaw(i) for i in obj) |
+ else: |
+ return obj |
+ |
+ |
+class FrozenDict(collections.Mapping): |
+ """An immutable OrderedDict. |
+ |
+ Modified From: http://stackoverflow.com/a/2704866 |
+ """ |
+ def __init__(self, *args, **kwargs): |
+ self._d = collections.OrderedDict(*args, **kwargs) |
+ self._hash = reduce(operator.xor, |
Vadim Sh.
2014/06/27 18:26:22
Why not make it lazy?
iannucci
2014/06/28 08:33:35
Added comment
|
+ (hash(i) for i in enumerate(self._d.iteritems())), 0) |
+ |
+ def __eq__(self, other): |
+ if not isinstance(other, collections.Mapping): |
+ return NotImplemented |
+ if self is other: |
+ return True |
+ if len(self) != len(other): |
+ return False |
+ for k, v in self.iteritems(): |
+ if k not in other or other[k] != v: |
+ return False |
+ return True |
+ |
+ def __iter__(self): |
+ return iter(self._d) |
+ |
+ def __len__(self): |
+ return len(self._d) |
+ |
+ def __getitem__(self, key): |
+ return self._d[key] |
+ |
+ def __hash__(self): |
+ return self._hash |
+ |
+ def __repr__(self): |
+ return 'FrozenDict(%r)' % (self._d.items(),) |