Commit 24ce4000 authored by Xavier Thompson's avatar Xavier Thompson

Add dict, list and set types

parent a032f43b
from ._iterator cimport *
cdef extern from * nogil:
"""
template<typename base_iterator_t, typename reference_t>
constexpr reference_t dict_key_getter_t(base_iterator_t iter)
{
return iter->first;
}
template<typename base_iterator_t, typename reference_t>
constexpr reference_t dict_value_getter_t(base_iterator_t iter)
{
return iter->second;
}
template<typename base_iterator_t, typename reference_t>
constexpr reference_t dict_item_getter_t(base_iterator_t iter)
{
return *iter;
}
template<typename dict_t, typename base_iterator_t, typename reference_t>
using dict_key_iterator_t = cy_iterator_t<dict_t, base_iterator_t, reference_t, dict_key_getter_t<base_iterator_t, reference_t>>;
template<typename dict_t, typename base_iterator_t, typename reference_t>
using dict_value_iterator_t = cy_iterator_t<dict_t, base_iterator_t, reference_t, dict_value_getter_t<base_iterator_t, reference_t>>;
template<typename dict_t, typename base_iterator_t, typename reference_t>
using dict_item_iterator_t = cy_iterator_t<dict_t, base_iterator_t, reference_t, dict_item_getter_t<base_iterator_t, reference_t>>;
template <typename dict_t, typename iterator_t>
class dict_view
{
private:
dict_t urange = NULL;
public:
using iterator = iterator_t;
dict_view() = default;
dict_view(const dict_view & rhs) = default;
dict_view(dict_view && rhs) = default;
dict_view & operator=(const dict_view& rhs) = default;
dict_view & operator=(dict_view&& rhs) = default;
~dict_view() = default;
dict_view(dict_t urange) : urange(urange) {}
iterator begin() const
{
return iterator(std::begin(urange->_items), urange);
}
typename iterator::base end() const
{
return std::end(urange->_items);
}
};
template<typename dict_t, typename base_iterator_t, typename reference_t>
using dict_keys_view_t = dict_view<dict_t, dict_key_iterator_t<dict_t, base_iterator_t, reference_t>>;
template<typename dict_t, typename base_iterator_t, typename reference_t>
using dict_values_view_t = dict_view<dict_t, dict_value_iterator_t<dict_t, base_iterator_t, reference_t>>;
template<typename dict_t, typename base_iterator_t, typename reference_t>
using dict_items_view_t = dict_view<dict_t, dict_item_iterator_t<dict_t, base_iterator_t, reference_t>>;
"""
cdef cppclass dict_key_iterator_t[dict_t, base_iterator_t, reference_t]:
dict_key_iterator_t()
dict_key_iterator_t(base_iterator_t)
dict_key_iterator_t(base_iterator_t, dict_t)
reference_t operator*()
dict_key_iterator_t operator++()
bint operator!=(base_iterator_t)
cdef cppclass dict_value_iterator_t[dict_t, base_iterator_t, reference_t]:
dict_value_iterator_t()
dict_value_iterator_t(base_iterator_t)
dict_value_iterator_t(base_iterator_t, dict_t)
reference_t operator*()
dict_value_iterator_t operator++()
bint operator!=(base_iterator_t)
cdef cppclass dict_item_iterator_t[dict_t, base_iterator_t, reference_t]:
dict_item_iterator_t()
dict_item_iterator_t(base_iterator_t)
dict_item_iterator_t(base_iterator_t, dict_t)
reference_t operator*()
dict_item_iterator_t operator++()
bint operator!=(base_iterator_t)
cdef cppclass dict_keys_view_t[dict_t, base_iterator_t, reference_t]:
ctypedef dict_key_iterator_t[dict_t, base_iterator_t, reference_t] iterator
dict_keys_view_t()
dict_keys_view_t(dict_t)
dict_key_iterator_t[dict_t, base_iterator_t, reference_t] begin()
base_iterator_t end()
cdef cppclass dict_values_view_t[dict_t, base_iterator_t, reference_t]:
ctypedef dict_value_iterator_t[dict_t, base_iterator_t, reference_t] iterator
dict_values_view_t()
dict_values_view_t(dict_t)
dict_value_iterator_t[dict_t, base_iterator_t, reference_t] begin()
base_iterator_t end()
cdef cppclass dict_items_view_t[dict_t, base_iterator_t, reference_t]:
ctypedef dict_item_iterator_t[dict_t, base_iterator_t, reference_t] iterator
dict_items_view_t()
dict_items_view_t(dict_t)
dict_item_iterator_t[dict_t, base_iterator_t, reference_t] begin()
base_iterator_t end()
cdef extern from * nogil:
"""
template<typename urng_t, typename base_iterator_t, typename reference_t, reference_t (*getter_t)(base_iterator_t)>
struct cy_iterator_t : base_iterator_t
{
using base = base_iterator_t;
using reference = reference_t;
urng_t urange = NULL;
friend void swap(cy_iterator_t & first, cy_iterator_t & second)
{
using std::swap;
swap(first.urange, second.urange);
swap(static_cast<base&>(first), static_cast<base&>(second));
}
cy_iterator_t() = default;
cy_iterator_t(cy_iterator_t const & rhs) : urange(rhs.urange)
{
if (urange != NULL)
{
urange->_active_iterators++;
}
}
cy_iterator_t(cy_iterator_t && rhs) : cy_iterator_t()
{
swap(*this, rhs);
}
cy_iterator_t & operator=(cy_iterator_t rhs)
{
swap(*this, rhs);
return *this;
}
cy_iterator_t & operator=(base_iterator_t rhs)
{
static_cast<base&>(*this) = rhs;
if (urange != NULL) {
urange->_active_iterators--;
urange = NULL;
}
return *this;
}
~cy_iterator_t()
{
if (urange != NULL) {
urange->_active_iterators--;
urange = NULL;
}
}
cy_iterator_t(base const & b) : base{b} {}
cy_iterator_t(base const & b, urng_t urange) : base{b}, urange{urange}
{
if (urange != NULL) {
urange->_active_iterators++;
}
}
cy_iterator_t operator++(int)
{
return static_cast<base&>(*this)++;
}
cy_iterator_t & operator++()
{
++static_cast<base&>(*this);
return (*this);
}
reference operator*() const
{
return getter_t(static_cast<base>(*this));
}
};
"""
from ._iterator cimport *
cdef extern from * nogil:
"""
template<typename base_iterator_t, typename reference_t>
constexpr reference_t list_value_getter_t(base_iterator_t iter)
{
return *iter;
}
template<typename list_t, typename base_iterator_t, typename reference_t>
using list_iterator_t = cy_iterator_t<list_t, base_iterator_t, reference_t, list_value_getter_t<base_iterator_t, reference_t>>;
"""
cdef cppclass list_iterator_t[list_t, base_iterator_t, reference_t]:
list_iterator_t()
list_iterator_t(base_iterator_t)
list_iterator_t(base_iterator_t, const list_t)
reference_t operator*()
list_iterator_t operator++()
bint operator!=(base_iterator_t)
from ._iterator cimport *
cdef extern from * nogil:
"""
template<typename base_iterator_t, typename reference_t>
constexpr reference_t set_value_getter_t(base_iterator_t iter)
{
return *iter;
}
template<typename set_t, typename base_iterator_t, typename reference_t>
using set_iterator_t = cy_iterator_t<set_t, base_iterator_t, reference_t, set_value_getter_t<base_iterator_t, reference_t>>;
"""
cdef cppclass set_iterator_t[set_t, base_iterator_t, reference_t]:
set_iterator_t()
set_iterator_t(base_iterator_t)
set_iterator_t(base_iterator_t, const set_t)
reference_t operator*()
set_iterator_t operator++()
bint operator!=(base_iterator_t)
from libcpp.unordered_map cimport unordered_map
from libcpp.pair cimport pair
from libcpp.vector cimport vector
from libcpp.atomic cimport atomic
from cython.operator cimport dereference
from ._dict cimport *
cdef cypclass Dict[K, V]:
ctypedef K key_type
ctypedef V value_type
ctypedef pair[key_type, value_type] item_type
ctypedef vector[item_type].size_type size_type
ctypedef dict_key_iterator_t[const Dict[K, V], vector[item_type].const_iterator, key_type] iterator
ctypedef dict_keys_view_t[const Dict[K, V], vector[item_type].const_iterator, key_type] keys_view
ctypedef dict_values_view_t[const Dict[K, V], vector[item_type].const_iterator, value_type] values_view
ctypedef dict_items_view_t[const Dict[K, V], vector[item_type].const_iterator, item_type] items_view
vector[item_type] _items
unordered_map[key_type, size_type] _indices
mutable atomic[int] _active_iterators
__init__(self):
self._active_iterators.store(0)
V __getitem__(const self, const key_type key) except ~:
it = self._indices.const_find(key)
if it != self._indices.end():
return self._items[dereference(it).second].second
with gil:
raise KeyError("Getting nonexistent item")
void __setitem__(self, const key_type key, const value_type value) except ~:
it = self._indices.find(key)
if it != self._indices.end():
index = dereference(it).second
self._items[index].second = value
elif self._active_iterators == 0:
self._indices[key] = self._items.size()
self._items.push_back(item_type(key, value))
else:
with gil:
raise RuntimeError("Modifying a dictionary with active iterators")
void __delitem__(self, const key_type key) except ~:
it = self._indices.find(key)
if it == self._indices.end():
with gil:
raise KeyError("Deleting nonexistent item")
if self._active_iterators != 0:
with gil:
raise RuntimeError("Modifying a dictionary with active iterators")
index = dereference(it).second
self._indices.erase(it)
if index < self._items.size() - 1:
self._items[index] = self._items[self._items.size() - 1]
self._items.pop_back()
void update(self, const Dict[K, V] other) except ~:
for item in other.items():
self[item.first] = item.second
void clear(self) except ~:
if self._active_iterators == 0:
self._items.clear()
self._indices.clear()
else:
with gil:
raise RuntimeError("Modifying a dictionary with active iterators")
iterator begin(const self):
return iterator(self._items.const_begin(), self)
vector[item_type].const_iterator end(const self):
return self._items.const_end()
size_type __len__(const self):
return self._items.size()
bint __contains__(const self, const key_type key):
return self._indices.count(key)
keys_view keys(const self):
return keys_view(self)
values_view values(const self):
return values_view(self)
items_view items(const self):
return items_view(self)
from libcpp.vector cimport vector
from libcpp.atomic cimport atomic
from cython.operator cimport dereference
from ._list cimport *
cdef cypclass List[V]:
ctypedef V value_type
ctypedef vector[value_type].size_type size_type
ctypedef list_iterator_t[const List[V], vector[value_type].const_iterator, value_type] iterator
vector[value_type] _elements
mutable atomic[int] _active_iterators
__init__(self):
self._active_iterators.store(0)
V __getitem__(const self, const size_type index) except ~:
if index < self._elements.size():
return self._elements[index]
else:
with gil:
raise IndexError("Getting list index out of range")
void __setitem__(self, size_type index, const value_type value) except ~:
if index < self._elements.size():
self._elements[index] = value
else:
with gil:
raise IndexError("Setting list index out of range")
void __delitem__(self, size_type index) except ~:
if index < self._elements.size():
if self._active_iterators == 0:
it = self._elements.begin() + index
self._elements.erase(it)
else:
with gil:
raise RuntimeError("Modifying a list with active iterators")
else:
with gil:
raise IndexError("Deleting list index out of range")
void append(self, const value_type value) except ~:
if self._active_iterators == 0:
self._elements.push_back(value)
else:
with gil:
raise RuntimeError("Modifying a list with active iterators")
void insert(self, size_type index, const value_type value) except ~:
if self._active_iterators == 0:
if index <= self._elements.size():
it = self._elements.begin() + index
self._elements.insert(it, value)
else:
with gil:
raise IndexError("Inserting list index out of range")
else:
with gil:
raise RuntimeError("Modifying a list with active iterators")
void clear(self) except ~:
if self._active_iterators == 0:
self._elements.clear()
else:
with gil:
raise RuntimeError("Modifying a list with active iterators")
List[V] __add__(const self, const List[V] other):
result = List[V]()
result._elements.reserve(self._elements.size() + other._elements.size())
result._elements.insert(result._elements.end(), self._elements.const_begin(), self._elements.const_end())
result._elements.insert(result._elements.end(), other._elements.const_begin(), other._elements.const_end())
return result
List[V] __iadd__(self, const List[V] other):
if self._active_iterators == 0:
self._elements.insert(self._elements.end(), other._elements.const_begin(), other._elements.const_end())
return self
else:
with gil:
raise RuntimeError("Modifying a list with active iterators")
List[V] __mul__(const self, size_type n):
result = List[V]()
result._elements.reserve(self._elements.size() * n)
for i in range(n):
result._elements.insert(result._elements.end(), self._elements.const_begin(), self._elements.const_end())
return result
List[V] __imul__(self, size_type n):
if self._active_iterators == 0:
if n > 1:
elements = self._elements
self._elements.reserve(elements.size() * n)
for i in range(1, n):
self._elements.insert(self._elements.end(), elements.begin(), elements.end())
return self
elif n == 1:
return self
else:
self._elements.clear()
return self
else:
with gil:
raise RuntimeError("Modifying a list with active iterators")
iterator begin(const self):
return iterator(self._elements.const_begin(), self)
vector[value_type].const_iterator end(const self):
return self._elements.const_end()
size_type __len__(const self):
return self._elements.size()
bint __contains__(const self, const value_type value):
for v in self._elements:
if value is v:
return 1
return 0
from libcpp.unordered_set cimport unordered_set
from libcpp.atomic cimport atomic
from cython.operator cimport dereference
from cython.operator cimport postincrement
from ._set cimport *
cdef cypclass Set[V]:
ctypedef V value_type
ctypedef size_t size_type
ctypedef set_iterator_t[const Set[V], unordered_set[value_type].const_iterator, value_type] iterator
unordered_set[value_type] _elements
mutable atomic[int] _active_iterators
__init__(self):
self._active_iterators.store(0)
# set elementary operations
void add(self, const value_type value) except ~:
if self._active_iterators == 0:
self._elements.insert(value)
else:
with gil:
raise RuntimeError("Modifying a set with active iterators")
void remove(self, const value_type value) except ~:
if self._active_iterators == 0:
if self._elements.erase(value) == 0:
with gil:
raise KeyError("Element not in set")
else:
with gil:
raise RuntimeError("Modifying a set with active iterators")
void discard(self, const value_type value) except ~:
if self._active_iterators == 0:
self._elements.erase(value)
else:
with gil:
raise RuntimeError("Modifying a set with active iterators")
V pop(self) except ~:
if self._active_iterators == 0:
it = self._elements.begin()
value = dereference(it)
self._elements.erase(it)
return value
else:
with gil:
raise RuntimeError("Modifying a set with active iterators")
void clear(self) except ~:
if self._active_iterators == 0:
self._elements.clear()
else:
with gil:
raise RuntimeError("Modifying a set with active iterators")
# inspection operations
size_type __len__(const self):
return self._elements.size()
bint __contains__(const self, const value_type value):
return self._elements.count(value)
bint isdisjoint(const self, const Set[V] other):
cdef const Set[V] smallest
cdef const Set[V] greatest
if self._elements.size() < other._elements.size():
smallest = self
greatest = other
else:
smallest = other
greatest = self
for value in smallest._elements:
if greatest._elements.count(value) > 0:
return 0
return 1
# set comparisons
bint __eq__(const self, const Set[V] other):
if self._elements.size() != other._elements.size():
return 0
for value in self._elements:
if other._elements.count(value) == 0:
return 0
return 1
bint __ne__(const self, const Set[V] other):
if self._elements.size() != other._elements.size():
return 1
for value in self._elements:
if other._elements.count(value) == 0:
return 1
return 0
bint __le__(const self, const Set[V] other):
if self._elements.size() > other._elements.size():
return 0
for value in self._elements:
if other._elements.count(value) == 0:
return 0
return 1
bint __lt__(const self, const Set[V] other):
return self <= other and self._elements.size() < other._elements.size()
bint issubset(const self, const Set[V] other):
return self <= other
bint __ge__(const self, const Set[V] other):
if self._elements.size() < other._elements.size():
return 0
for value in other._elements:
if self._elements.count(value) == 0:
return 0
return 1
bint __gt__(const self, const Set[V] other):
return self >= other and self._elements.size() > other._elements.size()
bint issuperset(const self, const Set[V] other):
return self >= other
# set non-modifying operations
Set[V] __or__(const self, const Set[V] other):
result = Set[V]()
result._elements.insert(self._elements.const_begin(), self._elements.const_end())
result._elements.insert(other._elements.const_begin(), other._elements.const_end())
return result
Set[V] union "set_union"(const self, const Set[V] other):
return self | other
Set[V] __and__(const self, const Set[V] other):
cdef const Set[V] smallest
cdef const Set[V] greatest
if self._elements.size() < other._elements.size():
smallest = self
greatest = other
else:
smallest = other
greatest = self
result = Set[V]()
for value in smallest._elements:
if greatest._elements.count(value) > 0:
result._elements.insert(value)
return result
Set[V] intersection(const self, const Set[V] other):
return self & other
Set[V] __sub__(const self, const Set[V] other):
result = Set[V]()
for value in self._elements:
if other._elements.count(value) == 0:
result._elements.insert(value)
return result
Set[V] difference(const self, const Set[V] other):
return self - other
Set[V] __xor__(const self, const Set[V] other):
result = Set[V]()
result._elements = other._elements
for value in self._elements:
it = result._elements.find(value)
if it != result._elements.end():
result._elements.erase(it)
else:
result._elements.insert(value)
return result
Set[V] symmetric_difference(const self, const Set[V] other):
return self ^ other
# set in-place (modifying) operations
Set[V] __ior__(self, const Set[V] other) except ~:
if self._active_iterators == 0:
self._elements.insert(other._elements.const_begin(), other._elements.end())
return self
else:
with gil:
raise RuntimeError("Modifying a set with active iterators")
Set[V] update(self, const Set[V] other) except ~:
self |= other
return self
Set[V] __iand__(self, const Set[V] other) except ~:
if self._active_iterators == 0:
it = self._elements.begin()
end = self._elements.end()
while it != end:
value = dereference(it)
if other._elements.count(value) == 0:
it = self._elements.erase(it)
else:
postincrement(it)
return self
else:
with gil:
raise RuntimeError("Modifying a set with active iterators")
Set[V] intersection_update(self, const Set[V] other) except ~:
self &= other
return self
Set[V] __isub__(self, const Set[V] other) except ~:
if self._active_iterators == 0:
for value in other._elements:
self._elements.erase(value)
return self
else:
with gil:
raise RuntimeError("Modifying a set with active iterators")
Set[V] difference_update(self, const Set[V] other) except ~:
self -= other
return self
Set[V] __ixor__(self, const Set[V] other) except ~:
if self._active_iterators == 0:
for value in other._elements:
if self._elements.erase(value) == 0:
self._elements.insert(value)
else:
with gil:
raise RuntimeError("Modifying a set with active iterators")
Set[V] symmetric_difference_update(self, const Set[V] other) except ~:
self ^= other
return self
# iterators
iterator begin(const self):
return iterator(self._elements.const_begin(), self)
unordered_set[value_type].const_iterator end(const self):
return self._elements.const_end()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment