From patchwork Tue Jul 12 23:39:36 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Roth X-Patchwork-Id: 104447 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id E7D23B6F68 for ; Wed, 13 Jul 2011 09:56:32 +1000 (EST) Received: from localhost ([::1]:34134 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QgmoX-00033k-Du for incoming@patchwork.ozlabs.org; Tue, 12 Jul 2011 19:56:29 -0400 Received: from eggs.gnu.org ([140.186.70.92]:35633) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QgmZq-00007G-Vu for qemu-devel@nongnu.org; Tue, 12 Jul 2011 19:41:22 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QgmZl-0005EI-KE for qemu-devel@nongnu.org; Tue, 12 Jul 2011 19:41:18 -0400 Received: from mout.perfora.net ([74.208.4.194]:59962) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QgmZl-0005EB-7J for qemu-devel@nongnu.org; Tue, 12 Jul 2011 19:41:13 -0400 Received: from localhost.localdomain ([32.97.110.59]) by mrelay.perfora.net (node=mrus1) with ESMTP (Nemesis) id 0M4G3X-1RYC6k0xaV-00rRLT; Tue, 12 Jul 2011 19:41:11 -0400 From: Michael Roth To: qemu-devel@nongnu.org Date: Tue, 12 Jul 2011 18:39:36 -0500 Message-Id: <1310513984-1163-11-git-send-email-mdroth@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1310513984-1163-1-git-send-email-mdroth@linux.vnet.ibm.com> References: <1310513984-1163-1-git-send-email-mdroth@linux.vnet.ibm.com> X-Provags-ID: V02:K0:wrJSx9FLORnIhKmuluwouOK9r0cu2fVJum/vC409pKs UgWKG74f9b9ZSFHzFkuaXQWP/2yrX+VwbNA8+NQsO+CSthhDC8 eKhZbmxmSXf40W4KR3uICQy0J9y1GGIlJZghXOhPcEZJDrspMw idX8Mas5kJhtI1dtCkYgpJOu5VN8smZDVzxIVRyXN+Hxy9c04B YGPn6nXnVTkWBcSJFrAglvjmUoLzBbXSsINOFlXbS8= X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 74.208.4.194 Cc: aliguori@linux.vnet.ibm.com, Jes.Sorensen@redhat.com, agl@linux.vnet.ibm.com, mdroth@linux.vnet.ibm.com, lcapitulino@redhat.com Subject: [Qemu-devel] [PATCH v6 10/18] qapi: add ordereddict.py helper library X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org We need this to parse dictionaries with schema ordering intact so that C prototypes can be generated deterministically. Signed-off-by: Michael Roth --- scripts/ordereddict.py | 128 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 128 insertions(+), 0 deletions(-) create mode 100644 scripts/ordereddict.py diff --git a/scripts/ordereddict.py b/scripts/ordereddict.py new file mode 100644 index 0000000..e17269f --- /dev/null +++ b/scripts/ordereddict.py @@ -0,0 +1,128 @@ +# Copyright (c) 2009 Raymond Hettinger +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +from UserDict import DictMixin + +class OrderedDict(dict, DictMixin): + + def __init__(self, *args, **kwds): + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__end + except AttributeError: + self.clear() + self.update(*args, **kwds) + + def clear(self): + self.__end = end = [] + end += [None, end, end] # sentinel node for doubly linked list + self.__map = {} # key --> [key, prev, next] + dict.clear(self) + + def __setitem__(self, key, value): + if key not in self: + end = self.__end + curr = end[1] + curr[2] = end[1] = self.__map[key] = [key, curr, end] + dict.__setitem__(self, key, value) + + def __delitem__(self, key): + dict.__delitem__(self, key) + key, prev, next = self.__map.pop(key) + prev[2] = next + next[1] = prev + + def __iter__(self): + end = self.__end + curr = end[2] + while curr is not end: + yield curr[0] + curr = curr[2] + + def __reversed__(self): + end = self.__end + curr = end[1] + while curr is not end: + yield curr[0] + curr = curr[1] + + def popitem(self, last=True): + if not self: + raise KeyError('dictionary is empty') + if last: + key = reversed(self).next() + else: + key = iter(self).next() + value = self.pop(key) + return key, value + + def __reduce__(self): + items = [[k, self[k]] for k in self] + tmp = self.__map, self.__end + del self.__map, self.__end + inst_dict = vars(self).copy() + self.__map, self.__end = tmp + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def keys(self): + return list(self) + + setdefault = DictMixin.setdefault + update = DictMixin.update + pop = DictMixin.pop + values = DictMixin.values + items = DictMixin.items + iterkeys = DictMixin.iterkeys + itervalues = DictMixin.itervalues + iteritems = DictMixin.iteritems + + def __repr__(self): + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + + def copy(self): + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + if isinstance(other, OrderedDict): + if len(self) != len(other): + return False + for p, q in zip(self.items(), other.items()): + if p != q: + return False + return True + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other +