...
 
Commits (67)
This diff is collapsed.
......@@ -849,7 +849,7 @@ class FunctionState(object):
elif type.is_cfunction:
from . import PyrexTypes
type = PyrexTypes.c_ptr_type(type) # A function itself isn't an l-value
if not type.is_pyobject and not type.is_memoryviewslice and not type.is_cyp_class:
if not type.is_pyobject and not type.is_memoryviewslice:
# Make manage_ref canonical, so that manage_ref will always mean
# a decref is needed.
manage_ref = False
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -170,6 +170,11 @@ api_name = pyrex_prefix + "capi__"
# cname for the type that defines the essential memory layout of a cypclass wrapper.
cypclass_wrapper_layout_type = "CyPyObject"
# active cypclass
cypclass_reified_prefix = builtin_prefix + 'active_'
cypclass_active_func_prefix = func_prefix + 'active_'
cypclass_active_self_cname = "_active_self"
# the h and api guards get changed to:
# __PYX_HAVE__FILENAME (for ascii filenames)
# __PYX_HAVE_U_PUNYCODEFILENAME (for non-ascii filenames)
......
This diff is collapsed.
......@@ -309,6 +309,8 @@ def _p_factor(s):
return p_typecast(s)
elif sy == 'IDENT' and s.systring == "sizeof":
return p_sizeof(s)
elif sy == 'IDENT' and s.systring == "consume":
return p_consume(s)
return p_power(s)
def p_typecast(s):
......@@ -319,7 +321,8 @@ def p_typecast(s):
is_memslice = isinstance(base_type, Nodes.MemoryViewSliceTypeNode)
is_template = isinstance(base_type, Nodes.TemplatedTypeNode)
is_const_volatile = isinstance(base_type, Nodes.CConstOrVolatileTypeNode)
if not is_memslice and not is_template and not is_const_volatile and base_type.name is None:
is_qualified = isinstance(base_type, Nodes.QualifiedCypclassNode)
if not is_memslice and not is_template and not is_const_volatile and not is_qualified and base_type.name is None:
s.error("Unknown type")
declarator = p_c_declarator(s, empty = 1)
if s.sy == '?':
......@@ -357,6 +360,13 @@ def p_sizeof(s):
s.expect(')')
return node
def p_consume(s):
# s.sy == ident "consume"
pos = s.position()
s.next()
operand = p_factor(s)
return ExprNodes.ConsumeNode(pos, operand = operand)
def p_yield_expression(s):
# s.sy == "yield"
......@@ -2503,6 +2513,19 @@ def p_c_complex_base_type(s, templates = None):
return type_node
def p_cypclass_qualifier(s):
qualifier = None
if s.sy == 'IDENT':
if s.systring in ('active', 'iso', 'lock', 'locked', 'read', 'frozen'):
qualifier = s.systring
s.next()
elif s.systring == 'self' and s.peek()[0] == '->':
qualifier = 'self->'
s.next()
s.next()
return qualifier
def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
#print "p_c_simple_base_type: self_flag =", self_flag, nonempty
is_basic = 0
......@@ -2534,6 +2557,12 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
return Nodes.CConstOrVolatileTypeNode(pos,
base_type=base_type, is_const=is_const, is_volatile=is_volatile)
# Handle cypclass qualifiers
qualifier = p_cypclass_qualifier(s)
if qualifier:
base_type = p_c_base_type(s, self_flag=self_flag, nonempty=nonempty, templates=templates)
return Nodes.QualifiedCypclassNode(pos, base_type=base_type, qualifier=qualifier)
if s.sy != 'IDENT':
error(pos, "Expected an identifier, found '%s'" % s.sy)
if looking_at_base_type(s):
......@@ -3366,7 +3395,7 @@ def p_c_func_or_var_declaration(s, pos, ctx):
s.next()
p_test(s) # Keep going, but ignore result.
if s.sy == ':':
if ctx.level not in ('module', 'c_class', 'module_pxd', 'c_class_pxd', 'cpp_class') and not ctx.templates:
if ctx.level not in ('module', 'c_class', 'module_pxd', 'c_class_pxd', 'cpp_class', 'cyp_class') and not ctx.templates:
s.error("C function definition not allowed here")
doc, suite = p_suite_with_docstring(s, Ctx(level='function'))
if 'mutable' in modifiers:
......@@ -3848,10 +3877,8 @@ def p_cpp_class_definition(s, pos, ctx):
if s.sy == '[':
error(s.position(), "Name options not allowed for C++ class")
nogil = p_nogil(s) or cypclass
lock_mode = None
activable = False
if cypclass:
lock_mode = p_cypclass_lock_mode(s)
activable = p_cypclass_activable(s)
if s.sy == ':':
s.next()
......@@ -3862,7 +3889,8 @@ def p_cpp_class_definition(s, pos, ctx):
# so why not on the cppclass itself ?
p_doc_string(s)
attributes = []
body_ctx = Ctx(visibility = ctx.visibility, level='cpp_class', nogil=nogil or ctx.nogil)
body_level = 'cyp_class' if cypclass else 'cpp_class'
body_ctx = Ctx(visibility = ctx.visibility, level=body_level, nogil=nogil or ctx.nogil)
body_ctx.templates = template_names
while s.sy != 'DEDENT':
if s.sy != 'pass':
......@@ -3881,7 +3909,7 @@ def p_cpp_class_definition(s, pos, ctx):
visibility = ctx.visibility,
in_pxd = ctx.level == 'module_pxd',
attributes = attributes,
templates = templates, cypclass=cypclass, lock_mode=lock_mode, activable=activable)
templates = templates, cypclass=cypclass, activable=activable)
def p_cpp_class_attribute(s, ctx):
decorators = None
......@@ -3907,14 +3935,6 @@ def p_cpp_class_attribute(s, ctx):
node.decorators = decorators
return node
def p_cypclass_lock_mode(s):
if s.sy == 'IDENT' and s.systring in ('nolock', 'checklock', 'autolock'):
mode = s.systring
s.next()
return mode
else:
return None
def p_cypclass_activable(s):
if s.sy == 'IDENT' and s.systring == 'activable':
s.next()
......
This diff is collapsed.
This diff is collapsed.
......@@ -538,6 +538,8 @@ def simply_type(result_type, pos):
result_type = result_type.ref_base_type
if result_type.is_cv_qualified:
result_type = result_type.cv_base_type
if result_type.is_qualified_cyp_class and result_type.qualifier == 'iso~':
result_type = PyrexTypes.cyp_class_qualified_type(result_type.qual_base_type, 'iso')
if result_type.is_cpp_class:
result_type.check_nullary_constructor(pos)
if result_type.is_array:
......
......@@ -125,26 +125,26 @@ cdef cypclass cypdict[K, V]:
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 cypdict[K, V], vector[item_type].const_iterator, key_type] iterator
ctypedef dict_keys_view_t[const cypdict[K, V], vector[item_type].const_iterator, key_type] keys_view
ctypedef dict_values_view_t[const cypdict[K, V], vector[item_type].const_iterator, value_type] values_view
ctypedef dict_items_view_t[const cypdict[K, V], vector[item_type].const_iterator, item_type] items_view
ctypedef dict_key_iterator_t[cypdict[K, V], vector[item_type].const_iterator, key_type] iterator
ctypedef dict_keys_view_t[cypdict[K, V], vector[item_type].const_iterator, key_type] keys_view
ctypedef dict_values_view_t[cypdict[K, V], vector[item_type].const_iterator, value_type] values_view
ctypedef dict_items_view_t[cypdict[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
atomic[int] _active_iterators
__init__(self):
self._active_iterators.store(0)
V __getitem__(const self, const key_type key) except ~:
V __getitem__(self, 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 ~:
void __setitem__(self, key_type key, value_type value) except ~:
it = self._indices.find(key)
if it != self._indices.end():
index = dereference(it).second
......@@ -156,7 +156,7 @@ cdef cypclass cypdict[K, V]:
with gil:
raise RuntimeError("Modifying a dictionary with active iterators")
void __delitem__(self, const key_type key) except ~:
void __delitem__(self, key_type key) except ~:
it = self._indices.find(key)
if it == self._indices.end():
with gil:
......@@ -170,7 +170,7 @@ cdef cypclass cypdict[K, V]:
self._items[index] = self._items[self._indices.size() - 1]
self._items.pop_back()
void update(self, const cypdict[K, V] other) except ~:
void update(self, cypdict[K, V] other) except ~:
for item in other.items():
self[item.first] = item.second
......@@ -182,23 +182,23 @@ cdef cypclass cypdict[K, V]:
with gil:
raise RuntimeError("Modifying a dictionary with active iterators")
iterator begin(const self):
iterator begin(self):
return iterator(self._items.const_begin(), self)
vector[item_type].const_iterator end(const self):
vector[item_type].const_iterator end(self):
return self._items.const_end()
size_type __len__(const self):
size_type __len__(self):
return self._items.size()
bint __contains__(const self, const key_type key):
bint __contains__(self, key_type key):
return self._indices.count(key)
keys_view keys(const self):
keys_view keys(self):
return keys_view(self)
values_view values(const self):
values_view values(self):
return values_view(self)
items_view items(const self):
items_view items(self):
return items_view(self)
......@@ -18,7 +18,7 @@ cdef extern from * nogil:
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)
list_iterator_t(base_iterator_t, list_t)
reference_t operator*()
list_iterator_t operator++()
bint operator!=(base_iterator_t)
......@@ -26,22 +26,22 @@ cdef extern from * nogil:
cdef cypclass cyplist[V]:
ctypedef V value_type
ctypedef vector[value_type].size_type size_type
ctypedef list_iterator_t[const cyplist[V], vector[value_type].const_iterator, value_type] iterator
ctypedef list_iterator_t[cyplist[V], vector[value_type].const_iterator, value_type] iterator
vector[value_type] _elements
mutable atomic[int] _active_iterators
atomic[int] _active_iterators
__init__(self):
self._active_iterators.store(0)
V __getitem__(const self, const size_type index) except ~:
V __getitem__(self, 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 ~:
void __setitem__(self, size_type index, value_type value) except ~:
if index < self._elements.size():
self._elements[index] = value
else:
......@@ -60,14 +60,14 @@ cdef cypclass cyplist[V]:
with gil:
raise IndexError("Deleting list index out of range")
void append(self, const value_type value) except ~:
void append(self, 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 ~:
void insert(self, size_type index, value_type value) except ~:
if self._active_iterators == 0:
if index <= self._elements.size():
it = self._elements.begin() + index
......@@ -86,14 +86,14 @@ cdef cypclass cyplist[V]:
with gil:
raise RuntimeError("Modifying a list with active iterators")
cyplist[V] __add__(const self, const cyplist[V] other):
cyplist[V] __add__(self, cyplist[V] other):
result = cyplist[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
cyplist[V] __iadd__(self, const cyplist[V] other):
cyplist[V] __iadd__(self, cyplist[V] other):
if self._active_iterators == 0:
self._elements.insert(self._elements.end(), other._elements.const_begin(), other._elements.const_end())
return self
......@@ -101,7 +101,7 @@ cdef cypclass cyplist[V]:
with gil:
raise RuntimeError("Modifying a list with active iterators")
cyplist[V] __mul__(const self, size_type n):
cyplist[V] __mul__(self, size_type n):
result = cyplist[V]()
result._elements.reserve(self._elements.size() * n)
for i in range(n):
......@@ -125,16 +125,16 @@ cdef cypclass cyplist[V]:
with gil:
raise RuntimeError("Modifying a list with active iterators")
iterator begin(const self):
iterator begin(self):
return iterator(self._elements.const_begin(), self)
vector[value_type].const_iterator end(const self):
vector[value_type].const_iterator end(self):
return self._elements.const_end()
size_type __len__(const self):
size_type __len__(self):
return self._elements.size()
bint __contains__(const self, const value_type value):
bint __contains__(self, value_type value):
for v in self._elements:
if value is v:
return 1
......
......@@ -19,7 +19,7 @@ cdef extern from * nogil:
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)
set_iterator_t(base_iterator_t, set_t)
reference_t operator*()
set_iterator_t operator++()
bint operator!=(base_iterator_t)
......@@ -27,24 +27,24 @@ cdef extern from * nogil:
cdef cypclass cypset[V]:
ctypedef V value_type
ctypedef size_t size_type
ctypedef set_iterator_t[const cypset[V], unordered_set[value_type].const_iterator, value_type] iterator
ctypedef set_iterator_t[cypset[V], unordered_set[value_type].const_iterator, value_type] iterator
unordered_set[value_type] _elements
mutable atomic[int] _active_iterators
atomic[int] _active_iterators
__init__(self):
self._active_iterators.store(0)
# set elementary operations
void add(self, const value_type value) except ~:
void add(self, 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 ~:
void remove(self, value_type value) except ~:
if self._active_iterators == 0:
if self._elements.erase(value) == 0:
with gil:
......@@ -53,7 +53,7 @@ cdef cypclass cypset[V]:
with gil:
raise RuntimeError("Modifying a set with active iterators")
void discard(self, const value_type value) except ~:
void discard(self, value_type value) except ~:
if self._active_iterators == 0:
self._elements.erase(value)
else:
......@@ -79,15 +79,15 @@ cdef cypclass cypset[V]:
# inspection operations
size_type __len__(const self):
size_type __len__(self):
return self._elements.size()
bint __contains__(const self, const value_type value):
bint __contains__(self, value_type value):
return self._elements.count(value)
bint isdisjoint(const self, const cypset[V] other):
cdef const cypset[V] smallest
cdef const cypset[V] greatest
bint isdisjoint(self, cypset[V] other):
cdef cypset[V] smallest
cdef cypset[V] greatest
if self._elements.size() < other._elements.size():
smallest = self
greatest = other
......@@ -101,7 +101,7 @@ cdef cypclass cypset[V]:
# set comparisons
bint __eq__(const self, const cypset[V] other):
bint __eq__(self, cypset[V] other):
if self._elements.size() != other._elements.size():
return 0
for value in self._elements:
......@@ -109,7 +109,7 @@ cdef cypclass cypset[V]:
return 0
return 1
bint __ne__(const self, const cypset[V] other):
bint __ne__(self, cypset[V] other):
if self._elements.size() != other._elements.size():
return 1
for value in self._elements:
......@@ -117,7 +117,7 @@ cdef cypclass cypset[V]:
return 1
return 0
bint __le__(const self, const cypset[V] other):
bint __le__(self, cypset[V] other):
if self._elements.size() > other._elements.size():
return 0
for value in self._elements:
......@@ -125,13 +125,13 @@ cdef cypclass cypset[V]:
return 0
return 1
bint __lt__(const self, const cypset[V] other):
bint __lt__(self, cypset[V] other):
return self <= other and self._elements.size() < other._elements.size()
bint issubset(const self, const cypset[V] other):
bint issubset(self, cypset[V] other):
return self <= other
bint __ge__(const self, const cypset[V] other):
bint __ge__(self, cypset[V] other):
if self._elements.size() < other._elements.size():
return 0
for value in other._elements:
......@@ -139,27 +139,27 @@ cdef cypclass cypset[V]:
return 0
return 1
bint __gt__(const self, const cypset[V] other):
bint __gt__(self, cypset[V] other):
return self >= other and self._elements.size() > other._elements.size()
bint issuperset(const self, const cypset[V] other):
bint issuperset(self, cypset[V] other):
return self >= other
# set non-modifying operations
cypset[V] __or__(const self, const cypset[V] other):
cypset[V] __or__(self, cypset[V] other):
result = cypset[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
cypset[V] union "set_union"(const self, const cypset[V] other):
cypset[V] union "set_union"(self, cypset[V] other):
return self | other
cypset[V] __and__(const self, const cypset[V] other):
cdef const cypset[V] smallest
cdef const cypset[V] greatest
cypset[V] __and__(self, cypset[V] other):
cdef cypset[V] smallest
cdef cypset[V] greatest
if self._elements.size() < other._elements.size():
smallest = self
greatest = other
......@@ -172,20 +172,20 @@ cdef cypclass cypset[V]:
result._elements.insert(value)
return result
cypset[V] intersection(const self, const cypset[V] other):
cypset[V] intersection(self, cypset[V] other):
return self & other
cypset[V] __sub__(const self, const cypset[V] other):
cypset[V] __sub__(self, cypset[V] other):
result = cypset[V]()
for value in self._elements:
if other._elements.count(value) == 0:
result._elements.insert(value)
return result
cypset[V] difference(const self, const cypset[V] other):
cypset[V] difference(self, cypset[V] other):
return self - other
cypset[V] __xor__(const self, const cypset[V] other):
cypset[V] __xor__(self, cypset[V] other):
result = cypset[V]()
result._elements = other._elements
for value in self._elements:
......@@ -196,13 +196,13 @@ cdef cypclass cypset[V]:
result._elements.insert(value)
return result
cypset[V] symmetric_difference(const self, const cypset[V] other):
cypset[V] symmetric_difference(self, cypset[V] other):
return self ^ other
# set in-place (modifying) operations
cypset[V] __ior__(self, const cypset[V] other) except ~:
cypset[V] __ior__(self, cypset[V] other) except ~:
if self._active_iterators == 0:
self._elements.insert(other._elements.const_begin(), other._elements.end())
return self
......@@ -210,11 +210,11 @@ cdef cypclass cypset[V]:
with gil:
raise RuntimeError("Modifying a set with active iterators")
cypset[V] update(self, const cypset[V] other) except ~:
cypset[V] update(self, cypset[V] other) except ~:
self |= other
return self
cypset[V] __iand__(self, const cypset[V] other) except ~:
cypset[V] __iand__(self, cypset[V] other) except ~:
if self._active_iterators == 0:
it = self._elements.begin()
end = self._elements.end()
......@@ -229,11 +229,11 @@ cdef cypclass cypset[V]:
with gil:
raise RuntimeError("Modifying a set with active iterators")
cypset[V] intersection_update(self, const cypset[V] other) except ~:
cypset[V] intersection_update(self, cypset[V] other) except ~:
self &= other
return self
cypset[V] __isub__(self, const cypset[V] other) except ~:
cypset[V] __isub__(self, cypset[V] other) except ~:
if self._active_iterators == 0:
for value in other._elements:
self._elements.erase(value)
......@@ -242,11 +242,11 @@ cdef cypclass cypset[V]:
with gil:
raise RuntimeError("Modifying a set with active iterators")
cypset[V] difference_update(self, const cypset[V] other) except ~:
cypset[V] difference_update(self, cypset[V] other) except ~:
self -= other
return self
cypset[V] __ixor__(self, const cypset[V] other) except ~:
cypset[V] __ixor__(self, cypset[V] other) except ~:
if self._active_iterators == 0:
for value in other._elements:
if self._elements.erase(value) == 0:
......@@ -255,14 +255,14 @@ cdef cypclass cypset[V]:
with gil:
raise RuntimeError("Modifying a set with active iterators")
cypset[V] symmetric_difference_update(self, const cypset[V] other) except ~:
cypset[V] symmetric_difference_update(self, cypset[V] other) except ~:
self ^= other
return self
# iterators
iterator begin(const self):
iterator begin(self):
return iterator(self._elements.const_begin(), self)
unordered_set[value_type].const_iterator end(const self):
unordered_set[value_type].const_iterator end(self):
return self._elements.const_end()
This diff is collapsed.
# tag: cpp
# mode: compile
cdef cypclass A[T] activable:
int foo(self):
return 0
void bar(self):
pass
# tag: cpp
# mode: compile
cdef cypclass B:
pass
cdef cypclass A[T]:
T t
B b
# mode: error
# tag: cpp, cpp11, pthread
# cython: experimental_cpp_class_def=True, language_level=2
cdef cypclass A activable:
void f(self, A other):
pass
void f_iso(self, iso A other):
pass
void f_lock(self, lock A other):
pass
void f_active(self, active A other):
pass
def test_aliasing():
cdef active A active_a
# Aliasing from active
cdef iso A iso_a
iso_a = active_a
cdef lock A lock_a
lock_a = active_a
cdef A ref_a
ref_a = active_a
# Aliasing to active
cdef active A active_b
active_b = A()
cdef active A active_c
active_c = consume A()
cdef active A active_d
active_d = <lock A> consume A()
def test_calling():
a = activate(consume A())
a.f(NULL, A())
a.f(NULL, consume A())
cdef iso A iso_a
a.f_iso(NULL, consume iso_a)
cdef lock A lock_a
a.f_lock(NULL, lock_a)
cdef active A active_a
a.f_active(NULL, active_a)
def test_typecast():
cdef active A active_a
# Casting from active
cdef iso A iso_a
iso_a = consume <iso A> active_a
cdef lock A lock_a
lock_a = <lock A> active_a
cdef A ref_a
ref_a = <A> active_a
# Casting to active
cdef active A active_b
active_b = <active A> A()
cdef active A active_c
active_c = <active A> <iso A> consume A()
cdef active A active_d
active_d = <active A> <lock A> consume A()
_ERRORS = u'''
24:12: Cannot assign type 'active A' to 'iso A'
27:13: Cannot assign type 'active A' to 'lock A'
30:12: Cannot assign type 'active A' to 'A'
34:16: Cannot assign type 'A' to 'active A'
40:15: Cannot assign type 'lock A' to 'active A'
46:15: Cannot assign type 'A' to 'iso-> A'
65:20: Cannot cast 'active A' to 'iso A'
68:13: Cannot cast 'active A' to 'lock A'
71:12: Cannot cast 'active A' to 'A'
75:15: Cannot cast 'A' to 'active A'
78:15: Cannot cast 'iso A' to 'active A'
81:15: Cannot cast 'lock A' to 'active A'
'''
# mode: error
# tag: cpp, cpp11, pthread
# cython: experimental_cpp_class_def=True, language_level=2
cdef cypclass A activable:
pass
def test_name_aliasing():
cdef iso A iso_a
iso_a = consume A()
# Aliasing to iso
cdef iso A iso_b
iso_b = iso_a
cdef iso A iso_c
iso_c = A()
cdef iso A iso_d
iso_d = activate(consume A())
cdef iso A iso_e
iso_e = <object> A()
# Aliasing iso
cdef iso A iso_f
iso_f = iso_a
cdef active A active_a
active_a = iso_a
cdef A ref_a
ref_a = iso_a
cdef object py_a
py_a = iso_a
cdef cypclass Field:
Field foo(self, Field other):
return other
cdef cypclass Origin:
Field field
__init__(self):
self.field = Field()
Field bar(self, Field other):
return other
def test_field_aliasing():
cdef iso Origin o = consume Origin()
cdef object py_field
# OK - can pass consumed arguments
o.bar(consume Field()).foo(consume Field())
# ERR - aliasing field of iso to pyobject
py_field = o.field
# ERR - pyobject to field of iso
o.field = py_field
# ERR - aliasing field of iso
field = o.field
# ERR - consuming field of iso
field2 = consume o.field
# ERR - non_consumed argument
o.bar(Field())
# ERR - aliasing the returned reference
c = o.bar(consume Field())
def test_typecast():
cdef iso A iso_a
iso_a = consume A()
# Casting to iso
cdef iso A iso_b
iso_b = <iso A> A()
cdef iso A iso_c
iso_c = <iso A> activate(consume A())
cdef iso A iso_d
iso_d = <iso A> <object> A()
# Casting from iso
cdef active A active_a
active_a = <active A> iso_a
cdef A ref_a
ref_a = <A> iso_a
cdef object py_a
py_a = <object> iso_a
cdef iso A iso_e
iso_e = <iso A> iso_a
cdef iso A iso_f
iso_f = consume <iso A> iso_a
_ERRORS = u'''
14:12: Cannot assign type 'iso A' to 'iso A'
17:13: Cannot assign type 'A' to 'iso A'
20:20: Cannot assign type 'active A' to 'iso A'
23:12: Cannot convert Python object to 'iso A'
27:12: Cannot assign type 'iso A' to 'iso A'
30:15: Cannot assign type 'iso A' to 'active A'
33:12: Cannot assign type 'iso A' to 'A'
36:11: Cannot convert 'iso A' to Python object
60:16: Cannot convert 'iso-> Field' to Python object
63:14: Cannot convert Python object to 'iso-> Field'
66:13: Cannot assign type 'iso-> Field' to 'iso-> Field'
72:15: Cannot assign type 'Field' to 'iso-> Field'
75:13: Cannot assign type 'iso-> Field' to 'iso-> Field'
84:12: Cannot assign type 'iso A' to 'iso A'
84:12: Cannot cast 'A' to 'iso A'
87:12: Cannot assign type 'iso A' to 'iso A'
87:12: Cannot cast 'active A' to 'iso A'
90:12: Cannot assign type 'iso A' to 'iso A'
94:15: Cannot cast 'iso A' to 'active A'
97:12: Cannot cast 'iso A' to 'A'
100:11: Cannot cast 'iso A' to 'Python object'
103:12: Cannot assign type 'iso A' to 'iso A'
'''
# mode: error
# tag: cpp, cpp11, pthread
# cython: experimental_cpp_class_def=True, language_level=2
cdef cypclass A checklock:
int a
int getter(const self):
return self.a
void setter(self, int a):
self.a = a
cdef void take_write_locked(A obj):
pass
cdef int take_read_locked(const A obj):
return 3
def incorrect_locks():
obj = A()
obj.a = 3
obj.getter()
with rlocked obj:
obj.setter(42)
take_write_locked(obj)
obj.a
take_read_locked(obj)
cdef A global_cyobject
cdef void global_lock_taking():
with wlocked global_cyobject:
global_cyobject.setter(global_cyobject.getter() + 1)
_ERRORS = u"""
20:4: Reference 'obj' is not correctly locked in this expression (write lock required)
21:4: Reference 'obj' is not correctly locked in this expression (read lock required)
23:8: Reference 'obj' is not correctly locked in this expression (write lock required)
24:26: Reference 'obj' is not correctly locked in this expression (write lock required)
25:4: Reference 'obj' is not correctly locked in this expression (read lock required)
26:21: Reference 'obj' is not correctly locked in this expression (read lock required)
32:17: Can only lock local variables or arguments
"""
# mode: error
# tag: cpp, cpp11, pthread
# cython: experimental_cpp_class_def=True, language_level=2
cdef cypclass A activable:
void f(self, A other):
pass
void f_iso(self, iso A other):
pass
void f_lock(self, lock A other):
pass
void f_active(self, active A other):
pass
void f_locked_self(locked self):
cdef lock A l = self
def test_aliasing():
cdef lock A lock_a
# Aliasing from lock
cdef iso A iso_a
iso_a = lock_a
cdef active A active_a
active_a = lock_a
cdef locked A locked_a
locked_a = lock_a
cdef A ref_a
ref_a = lock_a
# Aliasing to lock
cdef lock A lock_b
lock_b = A()
cdef lock A lock_c
lock_c = consume A()
cdef lock A lock_d
lock_d = <lock A> consume A()
cdef lock A lock_e
cdef locked A locked_b
lock_e = locked_b
def test_calling():
cdef lock A a
a.f(A())
a.f(consume A())
a.f_locked_self()
cdef iso A iso_a
a.f_iso(consume iso_a)
cdef lock A lock_a
a.f_lock(lock_a)
cdef active A active_a
a.f_active(active_a)
def test_typecast():
cdef lock A lock_a
# Casting from lock
cdef iso A iso_a
iso_a = consume <iso A> lock_a
cdef active A active_a
active_a = <active A> lock_a
cdef locked A locked_a
locked_a = <locked A> lock_a
cdef A ref_a
ref_a = <A> lock_a
# Casting to lock
cdef lock A lock_b
lock_b = <lock A> A()
cdef lock A lock_c
lock_c = <lock A> <iso A> consume A()
cdef lock A lock_d
lock_d = <lock A> activate(consume A())
cdef lock A lock_e
cdef locked A locked_b
lock_e = <lock A> locked_b
_ERRORS = u'''
27:12: Cannot assign type 'lock A' to 'iso A'
30:15: Cannot assign type 'lock A' to 'active A'
33:15: Cannot assign type 'lock A' to 'locked A'
36:12: Cannot assign type 'lock A' to 'A'
40:14: Cannot assign type 'A' to 'lock A'
56:9: Cannot assign type 'A' to 'iso-> A'
77:20: Cannot cast 'lock A' to 'iso A'
80:15: Cannot cast 'lock A' to 'active A'
83:15: Cannot cast 'lock A' to 'locked A'
86:12: Cannot cast 'lock A' to 'A'
90:13: Cannot cast 'A' to 'lock A'
93:13: Cannot cast 'iso A' to 'lock A'
96:13: Cannot cast 'active A' to 'lock A'
'''
# mode: error
# tag: cpp, cpp11, pthread
# cython: experimental_cpp_class_def=True, language_level=2
cdef cypclass Error:
locked Error prohibited_field_type
locked Error forward_prohibited_return_type(self)
locked Error prohibited_return_type(self):
pass
cdef locked Error prohibited_global_variable
cdef cypclass A:
void f(locked self):
pass
void g(self, locked A other):
pass
void h(self, A other):
cdef locked A a
def test_aliasing():
cdef locked A locked_a
cdef lock A lock_a
lock_a = locked_a
locked_a = lock_a
lock_a.f()
A().g(locked_a)
A().g(lock_a)
_ERRORS = u'''
6:4: 'locked' variables are only allowed inside a function
8:47: Function cannot return a 'locked' cypclass instance
10:39: Function cannot return a 'locked' cypclass instance
13:5: 'locked' variables are only allowed inside a function
33:15: Cannot assign type 'lock A' to 'locked A'
39:10: Cannot assign type 'lock A' to 'locked A'
'''
......@@ -14,7 +14,7 @@ cdef extern from "<semaphore.h>" nogil:
int sem_destroy(sem_t* sem)
cdef cypclass BasicQueue(ActhonQueueInterface) checklock:
cdef cypclass BasicQueue(ActhonQueueInterface):
message_queue_t* _queue
__init__(self):
......@@ -23,13 +23,13 @@ cdef cypclass BasicQueue(ActhonQueueInterface) checklock:
__dealloc__(self):
del self._queue
bint is_empty(const self):
bint is_empty(self):
return self._queue.empty()
void push(self, ActhonMessageInterface message):
void push(locked self, ActhonMessageInterface message):
self._queue.push_back(message)
if message._sync_method is not NULL:
message._sync_method.insertActivity(message)
message._sync_method.insertActivity()
bint activate(self):
cdef bint one_message_processed
......@@ -47,23 +47,23 @@ cdef cypclass BasicQueue(ActhonQueueInterface) checklock:
if next_message._sync_method is not NULL:
next_sync_method = next_message._sync_method
with wlocked next_sync_method:
next_sync_method.removeActivity(next_message)
next_sync_method.removeActivity()
else:
self._queue.push_back(next_message)
# Don't forget to incref to avoid premature deallocation
return one_message_processed
cdef cypclass NoneResult(ActhonResultInterface) checklock:
cdef cypclass NoneResult(ActhonResultInterface):
void pushVoidStarResult(self, void* result):
pass
void pushIntResult(self, int result):
pass
void* getVoidStarResult(const self):
void* getVoidStarResult(self):
return NULL
int getIntResult(const self):
int getIntResult(self):
return 0
cdef cypclass WaitResult(ActhonResultInterface) checklock:
cdef cypclass WaitResult(ActhonResultInterface):
union result_t:
int int_val
void* ptr
......@@ -89,39 +89,38 @@ cdef cypclass WaitResult(ActhonResultInterface) checklock:
self.result.int_val = result
sem_post(&self.semaphore)
result_t _getRawResult(const self):
result_t _getRawResult(self):
# We must ensure a result exists, but we can let others access it immediately
# The cast here is a way of const-casting (we're modifying the semaphore in a const method)
sem_wait(<sem_t*> &self.semaphore)
sem_post(<sem_t*> &self.semaphore)
sem_wait(&self.semaphore)
sem_post(&self.semaphore)
return self.result
void* getVoidStarResult(const self):
void* getVoidStarResult(self):
res = self._getRawResult()
return res.ptr
int getIntResult(const self):
int getIntResult(self):
res = self._getRawResult()
return res.int_val
cdef cypclass ActivityCounterSync(ActhonSyncInterface) checklock:
cdef cypclass ActivityCounterSync(ActhonSyncInterface):
int count
ActivityCounterSync previous_sync
lock ActivityCounterSync previous_sync
__init__(self, ActivityCounterSync prev = <ActivityCounterSync> NULL):
__init__(self, lock ActivityCounterSync prev = NULL):
self.count = 0
self.previous_sync = prev
void insertActivity(self, ActhonMessageInterface msg):
void insertActivity(self):
self.count += 1
void removeActivity(self, ActhonMessageInterface msg):
void removeActivity(self):
self.count -= 1
bint isCompleted(const self):
bint isCompleted(self):
return self.count == 0
bint isActivable(const self):
bint isActivable(self):
cdef bint res = True
if self.previous_sync is not NULL:
prev_sync = self.previous_sync
......@@ -129,13 +128,13 @@ cdef cypclass ActivityCounterSync(ActhonSyncInterface) checklock:
res = prev_sync.isCompleted()
return res
cdef cypclass A checklock activable:
cdef cypclass A activable:
int a
__init__(self):
self.a = 0
self._active_result_class = WaitResult.construct
self._active_queue_class = BasicQueue()
int getter(const self):
self._active_queue_class = consume BasicQueue()
int getter(self):
return self.a
void setter(self, int a):
self.a = a
......@@ -146,21 +145,19 @@ def test_acthon_chain(n):
42
"""
cdef ActhonResultInterface res
cdef ActhonQueueInterface queue
sync1 = ActivityCounterSync()
with wlocked sync1:
after_sync1 = ActivityCounterSync(sync1)
cdef lock ActhonQueueInterface queue
sync1 = <lock ActivityCounterSync> consume ActivityCounterSync()
after_sync1 = <lock ActivityCounterSync> consume ActivityCounterSync(sync1)
obj = A()
with wlocked obj:
obj_actor = obj.__activate__()
with wlocked obj_actor, wlocked sync1, wlocked after_sync1:
# Pushing things in the queue
obj_actor.setter(sync1, n)
res = obj_actor.getter(after_sync1)
queue = obj._active_queue_class
obj_actor = activate(consume obj)
# Pushing things in the queue
obj_actor.setter(sync1, n)
res = obj_actor.getter(after_sync1)
# Processing the queue
with rlocked obj:
queue = obj._active_queue_class
with wlocked queue:
while not queue.is_empty():
queue.activate()
while not queue.is_empty():
queue.activate()
print <int> res
This diff is collapsed.
This diff is collapsed.
......@@ -2,7 +2,7 @@
# tag: cpp, cpp11
# cython: experimental_cpp_class_def=True, language_level=2
cdef cypclass Refcounted nolock:
cdef cypclass Refcounted:
pass
cdef int raises(Refcounted r) except 0:
......
......@@ -2,18 +2,18 @@
# tag: cpp, cpp11
# cython: experimental_cpp_class_def=True, language_level=2
cdef cypclass A nolock:
cdef cypclass A:
int val
__init__(self, int a):
self.val = a
A __iadd__(self, A other):
self.val += (other.val + 1)
cdef cypclass B(A) nolock:
cdef cypclass B(A):
B __iadd__(self, A other):
self.val += (other.val + 10)
int is_inferred_as_B(self):
return 1
......@@ -30,7 +30,7 @@ def test_inplace_operator_inference():
a += b # should add 1
# before it being fixed, 'b += a' where 'a' is of type A caused 'b' to be inferred as type A instead of B.
b += a # should add 10
# since all cypclass methods are virtual, 'b' being erroneously inferred as type A would cause a compilation error
......
......@@ -21,14 +21,3 @@ def test_is_cypclass():
r = <RightBase> d
return d is d, l is d, r is d, l is r
def test_is_cypclass_const():
"""
>>> test_is_cypclass_const()
(True, True, True, True)
"""
cdef const Derived d = Derived()
cdef const LeftBase l = <LeftBase> d
cdef const RightBase r = <RightBase> d
return d is d, l is d, r is d, l is r
......@@ -26,22 +26,3 @@ def test_insinstanceof():
cdef int r6 = isinstanceof[Derived](derived)
print(r1, r2, r3, r4, r5, r6)
def test_const_insinstanceof():
"""
>>> test_const_insinstanceof()
(1, 1, 1, 0, 1, 1)
"""
cdef const Base base = Base()
cdef const Base derived_as_base = Derived()
cdef const Derived derived = Derived()
cdef int r1 = isinstanceof[Base](base)
cdef int r2 = isinstanceof[Base](derived_as_base)
cdef int r3 = isinstanceof[Base](derived)
cdef int r4 = isinstanceof[Derived](base)
cdef int r5 = isinstanceof[Derived](derived_as_base)
cdef int r6 = isinstanceof[Derived](derived)
print(r1, r2, r3, r4, r5, r6)
# mode: run
# tag: cpp, cpp11, pthread
# cython: experimental_cpp_class_def=True, language_level=2
cdef cypclass A checklock:
int a
__init__(self):
self.a = 0
int getter(const self):
return self.a
void setter(self, int a):
self.a = a
def test_basic_locking():
"""
>>> test_basic_locking()
0
"""
obj = A()
with rlocked obj:
print obj.getter()
cdef argument_recursivity(A obj, int arg):
if arg > 0:
obj.setter(obj.getter() + 1)
argument_recursivity(obj, arg - 1)
def test_argument_recursivity(n):
"""
>>> test_argument_recursivity(42)
42
"""
obj = A()
with wlocked obj:
argument_recursivity(obj, n)
print obj.a
cdef cypclass Container:
A object
__init__(self):
self.object = A()
def test_lock_traversal(n):
"""
>>> test_lock_traversal(42)
42
"""
container = Container()
with rlocked container:
contained = container.object
with wlocked contained:
argument_recursivity(contained, n)
print contained.getter()
......@@ -2,10 +2,10 @@
# tag: cpp, cpp11
# cython: experimental_cpp_class_def=True, language_level=2
cdef cypclass A nolock:
cdef cypclass A:
int a
cypclass B nolock:
cypclass B:
int b
__init__(self, int b):
self.b = b
......@@ -18,7 +18,7 @@ cdef cypclass A nolock:
__init__(self, int a, int b):
self.a = a
self.b = B(b)
int foo(self):
return self.a + self.b.foo()
......
This diff is collapsed.
......@@ -175,7 +175,7 @@ cdef cypclass Subscript:
self.value = NULL
self.index = NULL
Value __getitem__(const self, Index index):
Value __getitem__(self, Index index):
if self.index is index:
return value
return NULL
......
......@@ -129,3 +129,57 @@ def test_getting_and_setting():
if Cy_GETREF(v) != 3:
return -(i+2)
return 0
def test_field_getting():
"""
>>> test_field_getting()
Template destroyed
Value destroyed
0
"""
v = Value()
h = Template[Value](v)
if Cy_GETREF(v) != 3:
return -1
for i in range(10):
v = h.value
if Cy_GETREF(v) != 3:
return -(i+2)
return 0
def test_field_setting():
"""
>>> test_field_setting()
Template destroyed
Value destroyed
0
"""
h = Template[Value](NULL)
v = Value()
for i in range(10):
h.value = v
if Cy_GETREF(v) != 3:
return -(i+1)
return 0
def test_field_deleting():
"""
>>> test_field_deleting()
Template destroyed
Value destroyed
0
"""
v = Value()
h = Template[Value](v)
if Cy_GETREF(v) != 3:
return -1
del h.value
if Cy_GETREF(v) != 2:
return -1
del h
return 0
This diff is collapsed.