Lichen

lib/__builtins__/dict.py

493:0dbc7ba27dbd
2017-01-21 Paul Boddie Merged branches.
     1 #!/usr/bin/env python     2      3 """     4 Dictionary objects.     5      6 Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>     7      8 This program is free software; you can redistribute it and/or modify it under     9 the terms of the GNU General Public License as published by the Free Software    10 Foundation; either version 3 of the License, or (at your option) any later    11 version.    12     13 This program is distributed in the hope that it will be useful, but WITHOUT    14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    15 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    16 details.    17     18 You should have received a copy of the GNU General Public License along with    19 this program.  If not, see <http://www.gnu.org/licenses/>.    20 """    21     22 from __builtins__.iterator import itemiterator    23 from __builtins__.span import _max    24 from native import isinstance as _isinstance    25     26 class dict:    27     28     "A dictionary representation mapping keys to values."    29     30     MISSING = object()    31     32     def __init__(self, args=None):    33     34         "Initialise the dictionary."    35     36         self.clear()    37     38         if args is not None:    39             for key, value in args:    40                 self.__setitem__(key, value)    41     42     def __str__(self):    43     44         "Return a string representation."    45     46         b = buffer()    47         b.append("{")    48     49         first = True    50     51         for key, value in self.items():    52             if first:    53                 first = False    54             else:    55                 b.append(", ")    56             b.append(key.__repr__())    57             b.append(" : ")    58             b.append(value.__repr__())    59     60         b.append("}")    61         return str(b)    62     63     __repr__ = __str__    64     65     def _get_buckets(self, capacity):    66     67         """    68         Reserve an attribute for a hashtable reference along with some space    69         for elements.    70         """    71     72         buckets = []    73         capacity = _max(capacity, 5)    74         i = 0    75     76         while i < capacity:    77             buckets.append([])    78             i += 1    79     80         return buckets    81     82     def _get_entry(self, key):    83     84         "Return the index and entry index as a tuple for 'key'."    85     86         # Find an index identifying the bucket involved.    87     88         index = self._get_index(key)    89     90         # Find the entry index within the bucket of the key.    91     92         i = self._find_entry(key, index)    93     94         return index, i    95     96     def _get_index(self, key):    97     98         "Check 'key' and return an index or raise TypeError."    99    100         index = key.__hash__()   101    102         if not _isinstance(index, int):   103             raise TypeError   104    105         return index % len(self.buckets)   106    107     def _find_entry(self, key, index):   108    109         "Search for 'key', using an 'index' identifying the bucket involved."   110    111         i = 0   112    113         for found, value in self.buckets[index]:   114             if found == key:   115                 return i   116             i += 1   117    118         return None   119    120     def _resize(self, capacity):   121    122         "Resize the hashtable to have the given 'capacity'."   123    124         buckets = self._get_buckets(capacity)   125    126         for key, value in self.items():   127             self._setitem(buckets, key, value)   128    129         self.buckets = buckets   130    131     def _setitem(self, buckets, key, value):   132    133         "Set in the 'buckets' an item having the given 'key' and 'value'."   134    135         index, i = self._get_entry(key)   136    137         # With no existing entry, append to the bucket.   138    139         if i is None:   140             buckets[index].append((key, value))   141             self.size += 1   142    143         # With an existing entry, replace the item.   144    145         else:   146             buckets[index][i] = key, value   147    148     # Public special methods.   149    150     def __delitem__(self, key):   151    152         "Remove the entry associated with the given 'key' from this dictionary."   153    154         index, i = self._get_entry(key)   155    156         if index is None or i is None:   157             raise KeyError, key   158    159         del self.buckets[index][i]   160         self.size -= 1   161    162     def __getitem__(self, key):   163    164         "Return the value associated with 'key' from the dictionary."   165    166         return self.get(key, self.MISSING)   167    168     def __iter__(self):   169    170         "Return an iterator."   171    172         return itemiterator(self.keys())   173    174     def __setitem__(self, key, value):   175    176         "Set a mapping from 'key' to 'value' in the dictionary."   177    178         capacity = len(self.buckets)   179    180         if self.size > capacity:   181             self._resize(capacity * 2)   182    183         self._setitem(self.buckets, key, value)   184    185     # Public conventional methods.   186    187     def clear(self):   188    189         "Reset the dictionary to an empty state."   190    191         self.size = 0   192         self.buckets = self._get_buckets(0)   193    194     def get(self, key, default=None):   195    196         """   197         Return the value stored for 'key'. If 'key' does not have an entry in   198         the dictionary, 'default' will be returned instead.   199         """   200    201         index, i = self._get_entry(key)   202    203         # With no entry index, either raise an exception or return the default.   204    205         if i is None:   206             if default is self.MISSING:   207                 raise KeyError(key)   208             else:   209                 return default   210    211         # With a valid entry index, obtain the corresponding value.   212    213         else:   214             return self.buckets[index][i][1]   215    216     def has_key(self, key):   217    218         "Return whether the given 'key' is used with this dictionary."   219    220         return self.get(key) and True or False   221    222     def keys(self):   223    224         "Return the keys for this dictionary."   225    226         l = []   227         for key, value in self.items():   228             l.append(key)   229         return l   230    231     def items(self):   232    233         "Return the items, each being a (key, value) tuple, in this dictionary."   234    235         l = []   236         for bucket in self.buckets:   237             l += bucket   238         return l   239    240     def setdefault(self, key, value): pass   241    242     def update(self, other): pass   243    244     def values(self):   245    246         "Return the values in this dictionary."   247    248         l = []   249         for key, value in self.items():   250             l.append(value)   251         return l   252    253 # vim: tabstop=4 expandtab shiftwidth=4