Chromium Code Reviews| 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(),) |