1.1 --- a/encoders.py Tue Nov 29 23:13:18 2016 +0100
1.2 +++ b/encoders.py Wed Nov 30 16:18:17 2016 +0100
1.3 @@ -321,6 +321,15 @@
1.4 else:
1.5 return '"%s"' % str(value).replace('"', '\\"').replace("\n", "\\n").replace("\t", "\\t").replace("\r", "\\r")
1.6
1.7 +def encode_literal_data_initialiser(style):
1.8 +
1.9 + """
1.10 + Encode a reference to a function populating the data for a literal having
1.11 + the given 'style' ("mapping" or "sequence").
1.12 + """
1.13 +
1.14 + return "__newdata_%s" % style
1.15 +
1.16 def encode_literal_instantiator(path):
1.17
1.18 """
2.1 --- a/generator.py Tue Nov 29 23:13:18 2016 +0100
2.2 +++ b/generator.py Wed Nov 30 16:18:17 2016 +0100
2.3 @@ -24,6 +24,7 @@
2.4 encode_instantiator_pointer, \
2.5 encode_literal_constant, encode_literal_constant_member, \
2.6 encode_literal_constant_value, \
2.7 + encode_literal_data_initialiser, \
2.8 encode_literal_instantiator, encode_literal_reference, \
2.9 encode_path, \
2.10 encode_predefined_reference, encode_size, \
2.11 @@ -65,12 +66,17 @@
2.12 ("__builtins__.notimplemented", "NotImplemented"),
2.13 )
2.14
2.15 - literal_instantiator_types = (
2.16 + literal_mapping_types = (
2.17 "__builtins__.dict.dict",
2.18 + )
2.19 +
2.20 + literal_sequence_types = (
2.21 "__builtins__.list.list",
2.22 "__builtins__.tuple.tuple",
2.23 )
2.24
2.25 + literal_instantiator_types = literal_mapping_types + literal_sequence_types
2.26 +
2.27 def __init__(self, importer, optimiser, output):
2.28 self.importer = importer
2.29 self.optimiser = optimiser
2.30 @@ -910,19 +916,19 @@
2.31 # initialisers but instead populate the structures directly.
2.32
2.33 if path in self.literal_instantiator_types:
2.34 + if path in self.literal_mapping_types:
2.35 + style = "mapping"
2.36 + else:
2.37 + style = "sequence"
2.38 +
2.39 print >>f_code, """\
2.40 __attr %s(__attr __args[], unsigned int number)
2.41 {
2.42 - __attr data;
2.43 -
2.44 /* Allocate the structure. */
2.45 __args[0] = __new(&%s, &%s, sizeof(%s));
2.46
2.47 - /* Allocate a structure for the data. */
2.48 - data = __newfragment(__args, number);
2.49 -
2.50 - /* Store a reference to the data in the object's __data__ attribute. */
2.51 - __store_via_object(__args[0].value, %s, data);
2.52 + /* Allocate a structure for the data and set it on the __data__ attribute. */
2.53 + %s(__args, number);
2.54
2.55 /* Return the allocated object details. */
2.56 return __args[0];
2.57 @@ -932,7 +938,7 @@
2.58 encode_tablename("<instance>", path),
2.59 encode_path(path),
2.60 encode_symbol("obj", path),
2.61 - encode_symbol("pos", "__data__")
2.62 + encode_literal_data_initialiser(style)
2.63 )
2.64
2.65 print >>f_signatures, "__attr %s(__attr[], unsigned int);" % encode_literal_instantiator(path)
3.1 --- a/lib/__builtins__/dict.py Tue Nov 29 23:13:18 2016 +0100
3.2 +++ b/lib/__builtins__/dict.py Wed Nov 30 16:18:17 2016 +0100
3.3 @@ -3,7 +3,7 @@
3.4 """
3.5 Dictionary objects.
3.6
3.7 -Copyright (C) 2015 Paul Boddie <paul@boddie.org.uk>
3.8 +Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
3.9
3.10 This program is free software; you can redistribute it and/or modify it under
3.11 the terms of the GNU General Public License as published by the Free Software
3.12 @@ -20,20 +20,120 @@
3.13 """
3.14
3.15 from __builtins__.iterator import listiterator
3.16 +import native
3.17
3.18 -class dict(object):
3.19 - def __init__(self, *args): pass
3.20 - def __setitem__(self, key, value): pass
3.21 +class dict:
3.22 +
3.23 + "A dictionary representation mapping keys to values."
3.24 +
3.25 + MISSING = object()
3.26 +
3.27 + def __init__(self, args=None):
3.28 +
3.29 + "Initialise the dictionary."
3.30 +
3.31 + # Reserve an attribute for a hashtable reference along with some space
3.32 + # for elements.
3.33 +
3.34 + self.__data__ = native._dict_init(args is not None and len(args) or 0)
3.35 +
3.36 + if args is not None:
3.37 + for key, value in args:
3.38 + self.__setitem__(key, value)
3.39 +
3.40 + def _get_index(self, key):
3.41 +
3.42 + "Check 'key' and return an index or raise TypeError."
3.43 +
3.44 + index = key.__hash__()
3.45 + if not native._isinstance(index, int):
3.46 + raise TypeError
3.47 +
3.48 + return index
3.49 +
3.50 + def _find_entry(self, key, index):
3.51 +
3.52 + "Search for 'key', using an 'index' identifying the bucket involved."
3.53 +
3.54 + size = native._dict_bucketsize(self, index)
3.55 + i = 0
3.56 +
3.57 + while i < size:
3.58 + found = native._dict_key(self, index, i)
3.59 + if found == key:
3.60 + return i
3.61 + i += 1
3.62 +
3.63 + return None
3.64 +
3.65 + def __setitem__(self, key, value):
3.66 +
3.67 + "Set a mapping from 'key' to 'value' in the dictionary."
3.68 +
3.69 + # Find an index identifying the bucket involved.
3.70 +
3.71 + index = self._get_index(key)
3.72 +
3.73 + # Find the entry index within the bucket of the key.
3.74 +
3.75 + i = self._find_entry(key, index)
3.76 +
3.77 + # With no existing entry, append to the bucket.
3.78 +
3.79 + if i is None:
3.80 + native._dict_additem(self, index, key, value)
3.81 +
3.82 + # With an existing entry, replace the item.
3.83 +
3.84 + else:
3.85 + native._dict_setitem(self, index, i, key, value)
3.86 +
3.87 def __delitem__(self, key, value): pass
3.88
3.89 - def __getitem__(self, key):
3.90 - # Note usage.
3.91 - KeyError
3.92 + def __getitem__(self, key, default=MISSING):
3.93 +
3.94 + """
3.95 + Return the value stored for 'key'. If 'key' does not have an entry in
3.96 + the dictionary, a KeyError will be raised unless 'default' is specified.
3.97 + In which case, 'default' will be returned instead.
3.98 + """
3.99 +
3.100 + # Find an index identifying the bucket involved.
3.101 +
3.102 + index = self._get_index(key)
3.103 +
3.104 + # Find the entry index within the bucket of the key.
3.105 +
3.106 + i = self._find_entry(key, index)
3.107 +
3.108 + # With no entry index, either raise an exception or return the default.
3.109 +
3.110 + if i is None:
3.111 + if default is self.MISSING:
3.112 + raise KeyError
3.113 + else:
3.114 + return default
3.115 +
3.116 + # With a valid entry index, obtain the corresponding value.
3.117 +
3.118 + else:
3.119 + return native._dict_value(self, index, i)
3.120
3.121 def clear(self): pass
3.122 def has_key(self): pass
3.123 - def keys(self): pass
3.124 - def values(self): pass
3.125 +
3.126 + def keys(self):
3.127 +
3.128 + "Return the keys for this dictionary."
3.129 +
3.130 + return native._dict_keys(self)
3.131 +
3.132 + def values(self):
3.133 +
3.134 + "Return the values in this dictionary."
3.135 +
3.136 + return native._dict_values(self)
3.137 +
3.138 def items(self): pass
3.139 def get(self, key): pass
3.140 def setdefault(self, key, value): pass
4.1 --- a/lib/__builtins__/int.py Tue Nov 29 23:13:18 2016 +0100
4.2 +++ b/lib/__builtins__/int.py Wed Nov 30 16:18:17 2016 +0100
4.3 @@ -36,6 +36,10 @@
4.4 # NOTE: To be implemented.
4.5 self.__data__ = None
4.6
4.7 + def __hash__(self):
4.8 + "Return a value for hashing purposes."
4.9 + return self
4.10 +
4.11 def __iadd__(self, other):
4.12 "Return a new int for the operation."
4.13 return _binary_op(self, other, native._int_add)
5.1 --- a/lib/native.py Tue Nov 29 23:13:18 2016 +0100
5.2 +++ b/lib/native.py Wed Nov 30 16:18:17 2016 +0100
5.3 @@ -72,6 +72,17 @@
5.4 def _list_element(self, index): pass
5.5 def _list_setelement(self, index, value): pass
5.6
5.7 +# Dictionary operations.
5.8 +
5.9 +def _dict_init(size): pass
5.10 +def _dict_bucketsize(self, index): pass
5.11 +def _dict_key(self, index, element): pass
5.12 +def _dict_value(self, index, element): pass
5.13 +def _dict_additem(self, index, key, value): pass
5.14 +def _dict_setitem(self, index, element, key, value): pass
5.15 +def _dict_keys(self): pass
5.16 +def _dict_values(self): pass
5.17 +
5.18 # Buffer operations.
5.19
5.20 def _buffer_str(self): pass
6.1 --- a/templates/native.c Tue Nov 29 23:13:18 2016 +0100
6.2 +++ b/templates/native.c Wed Nov 30 16:18:17 2016 +0100
6.3 @@ -29,6 +29,36 @@
6.4 return attr;
6.5 }
6.6
6.7 +static __attr __new_list(__fragment *f)
6.8 +{
6.9 + /* Create a new list and mutate the __data__ attribute. */
6.10 + __attr attr = __new(&__InstanceTable___builtins___list_list, &__builtins___list_list, sizeof(__obj___builtins___list_list));
6.11 + attr.value->attrs[__pos___data__].seqvalue = f;
6.12 + return attr;
6.13 +}
6.14 +
6.15 +static __fragment *__fragment_append(__fragment *data, __attr * const value)
6.16 +{
6.17 + __fragment *newdata = data;
6.18 + unsigned int size = data->size, capacity = data->capacity;
6.19 + unsigned int n;
6.20 +
6.21 + /* Re-allocate the fragment if the capacity has been reached. */
6.22 + if (size >= capacity)
6.23 + {
6.24 + /* NOTE: Consider various restrictions on capacity increases. */
6.25 + n = capacity ? capacity * 2 : 1;
6.26 + newdata = (__fragment *) __REALLOCATE(data, __FRAGMENT_SIZE(n));
6.27 + newdata->capacity = n;
6.28 + }
6.29 +
6.30 + /* Insert the new element and increment the list size. */
6.31 + newdata->attrs[size] = *value;
6.32 + newdata->size = size + 1;
6.33 +
6.34 + return newdata;
6.35 +}
6.36 +
6.37 /* Native functions. */
6.38
6.39 __attr __fn_native__exit(__attr __args[])
6.40 @@ -338,14 +368,9 @@
6.41 __attr * const size = &__args[1];
6.42 /* size.__data__ interpreted as int */
6.43 unsigned int n = __load_via_object(size->value, __pos___data__).intvalue;
6.44 + __attr attr = {0, .seqvalue=__new_fragment(n)};
6.45
6.46 - /* Allocate space for the list. */
6.47 - __fragment *data = (__fragment *) __ALLOCATE(1, __FRAGMENT_SIZE(n));
6.48 - __attr attr = {0, .seqvalue=data};
6.49 -
6.50 - /* The initial capacity is the same as the given size. */
6.51 - data->size = 0;
6.52 - data->capacity = n;
6.53 + /* Return the __data__ attribute. */
6.54 return attr;
6.55 }
6.56
6.57 @@ -368,22 +393,7 @@
6.58 __attr * const value = &__args[2];
6.59 /* self.__data__ interpreted as list */
6.60 __fragment *data = __load_via_object(self->value, __pos___data__).seqvalue;
6.61 - __fragment *newdata = data;
6.62 - unsigned int size = data->size, capacity = data->capacity;
6.63 - unsigned int n;
6.64 -
6.65 - /* Re-allocate the fragment if the capacity has been reached. */
6.66 - if (size >= capacity)
6.67 - {
6.68 - /* NOTE: Consider various restrictions on capacity increases. */
6.69 - n = capacity ? capacity * 2 : 1;
6.70 - newdata = (__fragment *) __REALLOCATE(data, __FRAGMENT_SIZE(n));
6.71 - newdata->capacity = n;
6.72 - }
6.73 -
6.74 - /* Insert the new element and increment the list size. */
6.75 - newdata->attrs[size] = *value;
6.76 - newdata->size = size + 1;
6.77 + __fragment *newdata = __fragment_append(data, value);
6.78
6.79 /* Replace the __data__ attribute if appropriate. */
6.80 if (newdata != data)
6.81 @@ -466,6 +476,159 @@
6.82 return __builtins___none_None;
6.83 }
6.84
6.85 +__attr __fn_native__dict_init(__attr __args[])
6.86 +{
6.87 + __attr * const size = &__args[1];
6.88 + /* size.__data__ interpreted as int */
6.89 + unsigned int n = __load_via_object(size->value, __pos___data__).intvalue;
6.90 + __mapping *data = __new_mapping(n);
6.91 + __attr attr = {0, .mapvalue=data};
6.92 +
6.93 + /* Return the __data__ attribute. */
6.94 + return attr;
6.95 +}
6.96 +
6.97 +__attr __fn_native__dict_bucketsize(__attr __args[])
6.98 +{
6.99 + __attr * const self = &__args[1];
6.100 + __attr * const index = &__args[2];
6.101 + /* self.__data__ interpreted as dict */
6.102 + __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;
6.103 + /* index.__data__ interpreted as int */
6.104 + int k = __load_via_object(index->value, __pos___data__).intvalue % __MAPPING_BUCKETS;
6.105 +
6.106 + /* Return size of bucket k. */
6.107 + return __new_int(data->keys[k]->size);
6.108 +}
6.109 +
6.110 +__attr __fn_native__dict_keys(__attr __args[])
6.111 +{
6.112 + __attr * const self = &__args[1];
6.113 + /* self.__data__ interpreted as dict */
6.114 + __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;
6.115 + unsigned int k, i, j, size = 0;
6.116 + __fragment *f;
6.117 +
6.118 + /* Count the number of keys. */
6.119 + for (k = 0; k < __MAPPING_BUCKETS; k++)
6.120 + size += data->keys[k]->size;
6.121 +
6.122 + /* Create a fragment for the keys. */
6.123 + f = __new_fragment(size);
6.124 +
6.125 + /* Populate the fragment with the keys. */
6.126 + for (j = 0, k = 0; k < __MAPPING_BUCKETS; k++)
6.127 + for (i = 0; i < data->keys[k]->size; i++, j++)
6.128 + f->attrs[j] = data->keys[k]->attrs[i];
6.129 + f->size = size;
6.130 +
6.131 + /* Return a list. */
6.132 + return __new_list(f);
6.133 +}
6.134 +
6.135 +__attr __fn_native__dict_values(__attr __args[])
6.136 +{
6.137 + __attr * const self = &__args[1];
6.138 + /* self.__data__ interpreted as dict */
6.139 + __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;
6.140 + unsigned int k, i, j, size = 0;
6.141 + __fragment *f;
6.142 +
6.143 + /* Count the number of values. */
6.144 + for (k = 0; k < __MAPPING_BUCKETS; k++)
6.145 + size += data->values[k]->size;
6.146 +
6.147 + /* Create a fragment for the values. */
6.148 + f = __new_fragment(size);
6.149 +
6.150 + /* Populate the fragment with the values. */
6.151 + for (j = 0, k = 0; k < __MAPPING_BUCKETS; k++)
6.152 + for (i = 0; i < data->values[k]->size; i++, j++)
6.153 + f->attrs[j] = data->values[k]->attrs[i];
6.154 + f->size = size;
6.155 +
6.156 + /* Return a list. */
6.157 + return __new_list(f);
6.158 +}
6.159 +
6.160 +__attr __fn_native__dict_key(__attr __args[])
6.161 +{
6.162 + __attr * const self = &__args[1];
6.163 + __attr * const index = &__args[2];
6.164 + __attr * const element = &__args[3];
6.165 + /* self.__data__ interpreted as dict */
6.166 + __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;
6.167 + /* index.__data__ interpreted as int */
6.168 + int k = __load_via_object(index->value, __pos___data__).intvalue % __MAPPING_BUCKETS;
6.169 + /* element.__data__ interpreted as int */
6.170 + int i = __load_via_object(element->value, __pos___data__).intvalue;
6.171 +
6.172 + /* Return key from bucket k, element i. */
6.173 + return data->keys[k]->attrs[i];
6.174 +}
6.175 +
6.176 +__attr __fn_native__dict_value(__attr __args[])
6.177 +{
6.178 + __attr * const self = &__args[1];
6.179 + __attr * const index = &__args[2];
6.180 + __attr * const element = &__args[3];
6.181 + /* self.__data__ interpreted as dict */
6.182 + __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;
6.183 + /* index.__data__ interpreted as int */
6.184 + int k = __load_via_object(index->value, __pos___data__).intvalue % __MAPPING_BUCKETS;
6.185 + /* element.__data__ interpreted as int */
6.186 + int i = __load_via_object(element->value, __pos___data__).intvalue;
6.187 +
6.188 + /* Return value from bucket k, element i. */
6.189 + return data->values[k]->attrs[i];
6.190 +}
6.191 +
6.192 +__attr __fn_native__dict_additem(__attr __args[])
6.193 +{
6.194 + __attr * const self = &__args[1];
6.195 + __attr * const index = &__args[2];
6.196 + __attr * const key = &__args[3];
6.197 + __attr * const value = &__args[4];
6.198 + /* self.__data__ interpreted as dict */
6.199 + __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;
6.200 + /* index.__data__ interpreted as int */
6.201 + int k = __load_via_object(index->value, __pos___data__).intvalue % __MAPPING_BUCKETS;
6.202 + __fragment *keys = data->keys[k], *newkeys;
6.203 + __fragment *values = data->values[k], *newvalues;
6.204 +
6.205 + /* Append the item. */
6.206 + newkeys = __fragment_append(keys, key);
6.207 + newvalues = __fragment_append(values, value);
6.208 +
6.209 + /* Replace the fragments if appropriate. */
6.210 + if (newkeys != keys)
6.211 + data->keys[k] = newkeys;
6.212 + if (newvalues != values)
6.213 + data->values[k] = newvalues;
6.214 + return __builtins___none_None;
6.215 +}
6.216 +
6.217 +__attr __fn_native__dict_setitem(__attr __args[])
6.218 +{
6.219 + __attr * const self = &__args[1];
6.220 + __attr * const index = &__args[2];
6.221 + __attr * const element = &__args[3];
6.222 + __attr * const key = &__args[4];
6.223 + __attr * const value = &__args[5];
6.224 + /* self.__data__ interpreted as dict */
6.225 + __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;
6.226 + /* index.__data__ interpreted as int */
6.227 + int k = __load_via_object(index->value, __pos___data__).intvalue % __MAPPING_BUCKETS;
6.228 + /* element.__data__ interpreted as int */
6.229 + int i = __load_via_object(element->value, __pos___data__).intvalue;
6.230 +
6.231 + /* Replace the item. */
6.232 + data->keys[k]->attrs[i] = *key;
6.233 + data->values[k]->attrs[i] = *value;
6.234 +
6.235 + return __builtins___none_None;
6.236 +}
6.237 +
6.238 __attr __fn_native__buffer_str(__attr __args[])
6.239 {
6.240 __attr * const self = &__args[1];
7.1 --- a/templates/native.h Tue Nov 29 23:13:18 2016 +0100
7.2 +++ b/templates/native.h Wed Nov 30 16:18:17 2016 +0100
7.3 @@ -50,6 +50,15 @@
7.4 __attr __fn_native__list_element(__attr __args[]);
7.5 __attr __fn_native__list_setelement(__attr __args[]);
7.6
7.7 +__attr __fn_native__dict_init(__attr __args[]);
7.8 +__attr __fn_native__dict_bucketsize(__attr __args[]);
7.9 +__attr __fn_native__dict_keys(__attr __args[]);
7.10 +__attr __fn_native__dict_values(__attr __args[]);
7.11 +__attr __fn_native__dict_key(__attr __args[]);
7.12 +__attr __fn_native__dict_value(__attr __args[]);
7.13 +__attr __fn_native__dict_additem(__attr __args[]);
7.14 +__attr __fn_native__dict_setitem(__attr __args[]);
7.15 +
7.16 __attr __fn_native__buffer_str(__attr __args[]);
7.17
7.18 __attr __fn_native__get_using(__attr __args[]);
8.1 --- a/templates/progops.c Tue Nov 29 23:13:18 2016 +0100
8.2 +++ b/templates/progops.c Wed Nov 30 16:18:17 2016 +0100
8.3 @@ -24,11 +24,40 @@
8.4
8.5 /* Generic internal data allocation. */
8.6
8.7 -__attr __newfragment(__attr args[], unsigned int number)
8.8 +__fragment *__new_fragment(unsigned int n)
8.9 +{
8.10 + /* Allocate space for the list. */
8.11 + __fragment *data = (__fragment *) __ALLOCATE(1, __FRAGMENT_SIZE(n));
8.12 +
8.13 + /* The initial capacity is the same as the given size. */
8.14 + data->size = 0;
8.15 + data->capacity = n;
8.16 + return data;
8.17 +}
8.18 +
8.19 +__mapping *__new_mapping(unsigned int n)
8.20 +{
8.21 + /* Allocate a number of buckets. */
8.22 + __mapping *data = (__mapping *) __ALLOCATE(1, __MAPPING_SIZE(__MAPPING_BUCKETS));
8.23 + unsigned int i;
8.24 +
8.25 + /* Allocate fragments with an initial size of 2 * n / __MAPPING_BUCKETS,
8.26 + assuming a mostly uniform distribution of values across the buckets. */
8.27 +
8.28 + for (i = 0; i < __MAPPING_BUCKETS; i++)
8.29 + {
8.30 + data->keys[i] = __new_fragment(2 * n / __MAPPING_BUCKETS);
8.31 + data->values[i] = __new_fragment(2 * n / __MAPPING_BUCKETS);
8.32 + }
8.33 +
8.34 + return data;
8.35 +}
8.36 +
8.37 +void __newdata_sequence(__attr args[], unsigned int number)
8.38 {
8.39 /* Calculate the size of the fragment. */
8.40
8.41 - __fragment *data = (__fragment *) __ALLOCATE(1, __FRAGMENT_SIZE(number));
8.42 + __fragment *data = __new_fragment(number);
8.43 __attr attr = {0, .seqvalue=data};
8.44 unsigned int i, j;
8.45
8.46 @@ -38,8 +67,39 @@
8.47 data->attrs[j] = args[i];
8.48
8.49 data->size = number;
8.50 - data->capacity = number;
8.51 - return attr;
8.52 +
8.53 + /* Store a reference to the data in the object's __data__ attribute. */
8.54 +
8.55 + __store_via_object(args[0].value, __pos___data__, attr);
8.56 +}
8.57 +
8.58 +void __newdata_mapping(__attr args[], unsigned int number)
8.59 +{
8.60 + __mapping *data = __new_mapping(number);
8.61 + __attr attr = {0, .mapvalue=data};
8.62 + __fragment *f;
8.63 + __attr callargs[3];
8.64 + unsigned int i;
8.65 +
8.66 + /* Store a reference to the data in the object's __data__ attribute. */
8.67 +
8.68 + __store_via_object(args[0].value, __pos___data__, attr);
8.69 +
8.70 + /* Store the given number of values, starting from the second element. */
8.71 +
8.72 + for (i = 1; i <= number; i++)
8.73 + {
8.74 + /* Obtain the tuple elements. */
8.75 +
8.76 + f = __load_via_object(args[i].value, __pos___data__).seqvalue;
8.77 + callargs[0] = args[0];
8.78 + callargs[1] = f->attrs[0];
8.79 + callargs[2] = f->attrs[1];
8.80 +
8.81 + /* Call __setitem__ with the key and value. */
8.82 +
8.83 + __fn___builtins___dict_dict___setitem__(callargs);
8.84 + }
8.85 }
8.86
8.87 /* A helper for raising type errors within common operations. */
9.1 --- a/templates/progops.h Tue Nov 29 23:13:18 2016 +0100
9.2 +++ b/templates/progops.h Wed Nov 30 16:18:17 2016 +0100
9.3 @@ -7,7 +7,13 @@
9.4
9.5 __attr __new(const __table *table, __ref cls, size_t size);
9.6
9.7 -__attr __newfragment(__attr args[], unsigned int number);
9.8 +__fragment *__new_fragment(unsigned int n);
9.9 +
9.10 +__mapping *__new_mapping(unsigned int n);
9.11 +
9.12 +void __newdata_sequence(__attr args[], unsigned int number);
9.13 +
9.14 +void __newdata_mapping(__attr args[], unsigned int number);
9.15
9.16 __attr __invoke(__attr callable, int always_callable,
9.17 unsigned int nkwargs, __param kwcodes[], __attr kwargs[],
10.1 --- a/templates/types.h Tue Nov 29 23:13:18 2016 +0100
10.2 +++ b/templates/types.h Wed Nov 30 16:18:17 2016 +0100
10.3 @@ -32,6 +32,7 @@
10.4
10.5 typedef struct __obj __obj;
10.6 typedef struct __fragment __fragment;
10.7 +typedef struct __mapping __mapping;
10.8
10.9 typedef struct __attr
10.10 {
10.11 @@ -54,6 +55,7 @@
10.12 double floatvalue; /* floating point value */
10.13 char * strvalue; /* string value */
10.14 __fragment * seqvalue; /* sequence data */
10.15 + __mapping * mapvalue; /* mapping data */
10.16 };
10.17 } __attr;
10.18
10.19 @@ -77,6 +79,20 @@
10.20
10.21 #define __FRAGMENT_SIZE(NUMBER) (NUMBER * sizeof(__attr) + 2 * sizeof(unsigned int))
10.22
10.23 +/* Mappings are simple collections of fragment references used to hold the
10.24 + "buckets" used in hash tables. Here, separate lists of keys and values hold
10.25 + attributes referring to the actual keys and corresponding values. */
10.26 +
10.27 +#define __MAPPING_BUCKETS 10
10.28 +
10.29 +typedef struct __mapping
10.30 +{
10.31 + __fragment *keys[__MAPPING_BUCKETS];
10.32 + __fragment *values[__MAPPING_BUCKETS];
10.33 +} __mapping;
10.34 +
10.35 +#define __MAPPING_SIZE(NUMBER) (2 * NUMBER * sizeof(__fragment *) + sizeof(unsigned int))
10.36 +
10.37 /* Special instance position value. The pos member of __obj refers to the
10.38 special type attribute for classes, indicating which position holds the
10.39 attribute describing the class type. For instances, it is set to zero. */
11.1 --- a/tests/dict.py Tue Nov 29 23:13:18 2016 +0100
11.2 +++ b/tests/dict.py Wed Nov 30 16:18:17 2016 +0100
11.3 @@ -1,10 +1,21 @@
11.4 def f(d):
11.5 return d.keys()
11.6
11.7 -def g(d):
11.8 - for key, value in d.items():
11.9 - return value
11.10 +#def g(d):
11.11 +# for key, value in d.items():
11.12 +# return value
11.13
11.14 -d = {"a" : 1, "b" : 2}
11.15 -f(d) # ["a", "b"]
11.16 -g(d) # either 1 or 2
11.17 +d = {10 : "a", 20 : "b"}
11.18 +l = f(d)
11.19 +print 10 in l # True
11.20 +print 20 in l # True
11.21 +print 30 in l # False
11.22 +
11.23 +l = d.values()
11.24 +print "a" in l # True
11.25 +print "b" in l # True
11.26 +print "c" in l # False
11.27 +
11.28 +
11.29 +#v = g(d) # either "a" or "b"
11.30 +#print v == "a" or v == "b" # True