Skip to content

Commit

Permalink
WIP: use vector dispatcher callback for user defined objects. Working…
Browse files Browse the repository at this point in the history
… python bindings.
  • Loading branch information
Kerilk committed Jul 12, 2024
1 parent 7d9c901 commit adfa73d
Show file tree
Hide file tree
Showing 17 changed files with 527 additions and 398 deletions.
53 changes: 35 additions & 18 deletions bindings/python/cconfigspace/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,10 +395,9 @@ class DeserializeOption(CEnumeration):
_members_ = [
('END', 0),
'HANDLE_MAP',
'VECTOR',
'DATA',
'VECTOR_CALLBACK',
'NON_BLOCKING',
'CALLBACK'
'DATA_CALLBACK'
]

def _ccs_get_function(method, argtypes = [], restype = Result):
Expand All @@ -422,7 +421,8 @@ def _ccs_get_function(method, argtypes = [], restype = Result):
ccs_object_get_user_data = _ccs_get_function("ccs_object_get_user_data", [ccs_object, ct.POINTER(ct.c_void_p)])
ccs_object_serialize_callback_type = ct.CFUNCTYPE(Result, ccs_object, ct.c_size_t, ct.c_void_p, ct.POINTER(ct.c_size_t), ct.c_void_p)
ccs_object_set_serialize_callback = _ccs_get_function("ccs_object_set_serialize_callback", [ccs_object, ccs_object_serialize_callback_type, ct.c_void_p])
ccs_object_deserialize_callback_type = ct.CFUNCTYPE(Result, ccs_object, ct.c_size_t, ct.c_void_p, ct.c_void_p)
ccs_object_deserialize_data_callback_type = ct.CFUNCTYPE(Result, ccs_object, ct.c_size_t, ct.c_void_p, ct.c_void_p)
ccs_object_deserialize_vector_callback_type = ct.CFUNCTYPE(Result, ct.c_int, ct.c_char_p, ct.c_void_p, ct.POINTER(ct.c_void_p), ct.POINTER(ct.py_object))
# Variadic methods
ccs_object_serialize = getattr(libcconfigspace, "ccs_object_serialize")
ccs_object_serialize.argtypes = ccs_object, SerializeFormat, SerializeOperation,
Expand Down Expand Up @@ -556,7 +556,7 @@ def serialize(self, format = 'binary', path = None, file_descriptor = None, call
return v

@classmethod
def deserialize(cls, format = 'binary', handle_map = None, vector = None, data = None, path = None, buffer = None, file_descriptor = None, callback = None, callback_data = None):
def deserialize(cls, format = 'binary', handle_map = None, vector_callback = None, vector_callback_data = None, path = None, buffer = None, file_descriptor = None, callback = None, callback_data = None):
if format != 'binary':
raise Error(Result(Result.ERROR_INVALID_VALUE))
mode_count = 0;
Expand All @@ -572,16 +572,16 @@ def deserialize(cls, format = 'binary', handle_map = None, vector = None, data =
options = [DeserializeOption.END]
if handle_map:
options = [DeserializeOption.HANDLE_MAP, handle_map.handle] + options
if vector:
options = [DeserializeOption.VECTOR, ct.byref(vector)] + options
if data:
options = [DeserializeOption.DATA, ct.py_object(data)] + options
if vector_callback:
vector_cb_wrapper = _get_deserialize_vector_callback_wrapper(vector_callback)
vector_cb_wrapper_func = ccs_object_deserialize_vector_callback_type(vector_cb_wrapper)
options = [DeserializeOption.VECTOR_CALLBACK, vector_cb_wrapper_func, ct.py_object(vector_callback_data)] + options
if callback:
cb_wrapper = _get_deserialize_callback_wrapper(callback)
cb_wrapper_func = ccs_object_deserialize_callback_type(cb_wrapper)
options = [DeserializeOption.CALLBACK, cb_wrapper_func, ct.py_object(callback_data)] + options
cb_wrapper = _get_deserialize_data_callback_wrapper(callback)
cb_wrapper_func = ccs_object_deserialize_data_callback_type(cb_wrapper)
options = [DeserializeOption.DATA_CALLBACK, cb_wrapper_func, ct.py_object(callback_data)] + options
elif _default_user_data_deserializer:
options = [DeserializeOption.CALLBACK, _default_user_data_deserializer, ct.py_object()] + options
options = [DeserializeOption.DATA_CALLBACK, _default_user_data_deserializer, ct.py_object()] + options
if buffer:
s = ct.c_size_t(ct.sizeof(buffer))
res = ccs_object_deserialize(ct.byref(o), SerializeFormat.BINARY, SerializeOperation.MEMORY, s, buffer, *options)
Expand Down Expand Up @@ -621,8 +621,8 @@ def serialize_callback_wrapper(obj, serialize_data_size, serialize_data, seriali
return Error.set_error(e)
return serialize_callback_wrapper

def _get_deserialize_callback_wrapper(callback):
def deserialize_callback_wrapper(obj, serialize_data_size, serialize_data, cb_data):
def _get_deserialize_data_callback_wrapper(callback):
def deserialize_data_callback_wrapper(obj, serialize_data_size, serialize_data, cb_data):
try:
p_sd = ct.cast(serialize_data, ct.c_void_p)
cb_data = ct.cast(cb_data, ct.c_void_p)
Expand All @@ -638,7 +638,24 @@ def deserialize_callback_wrapper(obj, serialize_data_size, serialize_data, cb_da
return Result.SUCCESS
except Exception as e:
return Error.set_error(e)
return deserialize_callback_wrapper
return deserialize_data_callback_wrapper

def _get_deserialize_vector_callback_wrapper(callback):
def deserialize_vector_callback_wrapper(obj_type, name, callback_user_data, vector_ret, data_ret):
try:
cb_data = ct.cast(callback_user_data, ct.py_object).value if callback_user_data else None
o_type = ObjectType(obj_type)
(vector, data) = callback(o_type, name, cb_data)
c_vector = ct.py_object(vector)
c_data = ct.py_object(data)
vector_ret[0] = ct.cast(ct.byref(vector), ct.c_void_p)
data_ret[0] = c_data
ct.pythonapi.Py_IncRef(c_vector)
ct.pythonapi.Py_IncRef(c_data)
return Result.SUCCESS
except Exception as e:
return Error.set_error(e)
return deserialize_vector_callback_wrapper

def _json_user_data_serializer(obj, data, size):
string = json.dumps(obj.user_data).encode("ascii")
Expand All @@ -651,8 +668,8 @@ def _json_user_data_deserializer(obj, serialized, data):
_json_user_data_serializer_wrap = _get_serialize_callback_wrapper(_json_user_data_serializer)
_json_user_data_serializer_func = ccs_object_serialize_callback_type(_json_user_data_serializer_wrap)

_json_user_data_deserializer_wrap = _get_deserialize_callback_wrapper(_json_user_data_deserializer)
_json_user_data_deserializer_func = ccs_object_deserialize_callback_type(_json_user_data_deserializer_wrap)
_json_user_data_deserializer_wrap = _get_deserialize_data_callback_wrapper(_json_user_data_deserializer)
_json_user_data_deserializer_func = ccs_object_deserialize_data_callback_type(_json_user_data_deserializer_wrap)

_default_user_data_serializer = _json_user_data_serializer_func
_default_user_data_deserializer = _json_user_data_deserializer_func
Expand Down
191 changes: 91 additions & 100 deletions bindings/python/cconfigspace/tree_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,93 +178,6 @@ class DynamicTreeSpaceVector(ct.Structure):
ccs_create_dynamic_tree_space = _ccs_get_function("ccs_create_dynamic_tree_space", [ct.c_char_p, ccs_tree, ccs_feature_space, ccs_rng, ct.POINTER(DynamicTreeSpaceVector), ct.py_object, ct.POINTER(ccs_tree_space)])
ccs_dynamic_tree_space_get_tree_space_data = _ccs_get_function("ccs_dynamic_tree_space_get_tree_space_data", [ccs_tree_space, ct.POINTER(ct.c_void_p)])

def _wrap_user_defined_callbacks(delete, get_child, serialize, deserialize):
vec = DynamicTreeSpaceVector()
def delete_wrapper(ts):
try:
ts = ct.cast(ts, ccs_tree_space)
o = Object.from_handle(ts)
tsdata = o.tree_space_data
if delete is not None:
delete(o)
if tsdata is not None:
ct.pythonapi.Py_DecRef(ct.py_object(tsdata))
ct.pythonapi.Py_DecRef(ct.py_object(vec))
return Result.SUCCESS
except Exception as e:
return Error.set_error(e)

def get_child_wrapper(ts, parent, index, p_child):
try:
ts = ct.cast(ts, ccs_tree_space)
parent = ct.cast(parent, ccs_tree)
child = get_child(TreeSpace.from_handle(ts), Tree.from_handle(parent), index)
res = ccs_retain_object(child.handle)
Error.check(res)
p_child[0] = child.handle.value
return Result.SUCCESS
except Exception as e:
return Error.set_error(e)

if serialize is not None:
def serialize_wrapper(ts, state_size, p_state, p_state_size):
try:
ts = ct.cast(ts, ccs_tree_space)
p_s = ct.cast(p_state, ct.c_void_p)
p_sz = ct.cast(p_state_size, ct.c_void_p)
state = serialize(TreeSpace.from_handle(ts), True if state_size == 0 else False)
if p_s.value is not None and state_size < ct.sizeof(state):
raise Error(Result(Result.ERROR_INVALID_VALUE))
if p_s.value is not None:
ct.memmove(p_s, ct.byref(state), ct.sizeof(state))
if p_sz.value is not None:
p_state_size[0] = ct.sizeof(state)
return Result.SUCCESS
except Exception as e:
return Error.set_error(e)
else:
serialize_wrapper = 0

if deserialize is not None:
def deserialize_wrapper(tree, feature_space, state_size, p_state, p_tree_space_data):
try:
t = ct.cast(tree, ccs_tree)
p_s = ct.cast(p_state, ct.c_void_p)
p_t = ct.cast(p_tree_space_data, ct.c_void_p)
if p_s.value is None:
state = None
else:
state = ct.cast(p_s, POINTER(c_byte * state_size))
tree_space_data = deserialize(Tree.from_handle(t), FeatureSpace.from_handle(feature_space) if feature_space else None, state)
c_tree_space_data = ct.py_object(tree_space_data)
p_t[0] = c_tree_space_data
ct.pythonapi.Py_IncRef(c_tree_space_data)
return Result.SUCCESS
except Exception as e:
return Error.set_error(e)
else:
deserialize_wrapper = 0

delete_wrapper_func = ccs_dynamic_tree_space_del_type(delete_wrapper)
get_child_wrapper_func = ccs_dynamic_tree_space_get_child_type(get_child_wrapper)
serialize_wrapper_func = ccs_dynamic_tree_space_serialize_type(serialize_wrapper)
deserialize_wrapper_func = ccs_dynamic_tree_space_deserialize_type(deserialize_wrapper)
vec.delete = delete_wrapper_func
vec.get_child = get_child_wrapper_func
vec.serialize = serialize_wrapper_func
vec.deserialize = deserialize_wrapper_func

setattr(vec, '_wrappers', (
delete_wrapper,
get_child_wrapper,
serialize_wrapper,
deserialize_wrapper,
delete_wrapper_func,
get_child_wrapper_func,
serialize_wrapper_func,
deserialize_wrapper_func))
return vec

class DynamicTreeSpace(TreeSpace):

def __init__(self, handle = None, retain = False, auto_release = True,
Expand All @@ -273,7 +186,7 @@ def __init__(self, handle = None, retain = False, auto_release = True,
if get_child is None:
raise Error(Result(Result.ERROR_INVALID_VALUE))

vec = _wrap_user_defined_callbacks(delete, get_child, serialize, deserialize)
vec = self.get_vector(delete, get_child, serialize, deserialize)
if tree_space_data is not None:
c_tree_space_data = ct.py_object(tree_space_data)
else:
Expand All @@ -292,18 +205,6 @@ def __init__(self, handle = None, retain = False, auto_release = True,
else:
super().__init__(handle = handle, retain = retain, auto_release = auto_release)

@classmethod
def deserialize(cls, delete, get_child, serialize = None, deserialize = None, tree_space_data = None, format = 'binary', handle_map = None, path = None, buffer = None, file_descriptor = None, callback = None, callback_data = None):
if get_child is None:
raise Error(Result(Result.ERROR_INVALID_VALUE))

vec = _wrap_user_defined_callbacks(delete, get_child, serialize, deserialize)
res = super().deserialize(format = format, handle_map = handle_map, vector = vec, data = tree_space_data, path = path, buffer = buffer, file_descriptor = file_descriptor, callback = callback, callback_data = callback_data)
ct.pythonapi.Py_IncRef(ct.py_object(vec))
if tree_space_data is not None:
ct.pythonapi.Py_IncRef(ct.py_object(tree_space_data))
return res

@property
def tree_space_data(self):
if hasattr(self, "_tree_space_data"):
Expand All @@ -317,6 +218,96 @@ def tree_space_data(self):
self._tree_space_data = None
return self._tree_space_data

@classmethod
def get_vector(self, delete = None, get_child = None, serialize = None, deserialize = None):
if get_child is None:
raise Error(Result(Result.ERROR_INVALID_VALUE))
vec = DynamicTreeSpaceVector()
def delete_wrapper(ts):
try:
ts = ct.cast(ts, ccs_tree_space)
o = Object.from_handle(ts)
tsdata = o.tree_space_data
if delete is not None:
delete(o)
if tsdata is not None:
ct.pythonapi.Py_DecRef(ct.py_object(tsdata))
ct.pythonapi.Py_DecRef(ct.py_object(vec))
return Result.SUCCESS
except Exception as e:
return Error.set_error(e)

def get_child_wrapper(ts, parent, index, p_child):
try:
ts = ct.cast(ts, ccs_tree_space)
parent = ct.cast(parent, ccs_tree)
child = get_child(TreeSpace.from_handle(ts), Tree.from_handle(parent), index)
res = ccs_retain_object(child.handle)
Error.check(res)
p_child[0] = child.handle.value
return Result.SUCCESS
except Exception as e:
return Error.set_error(e)

if serialize is not None:
def serialize_wrapper(ts, state_size, p_state, p_state_size):
try:
ts = ct.cast(ts, ccs_tree_space)
p_s = ct.cast(p_state, ct.c_void_p)
p_sz = ct.cast(p_state_size, ct.c_void_p)
state = serialize(TreeSpace.from_handle(ts), True if state_size == 0 else False)
if p_s.value is not None and state_size < ct.sizeof(state):
raise Error(Result(Result.ERROR_INVALID_VALUE))
if p_s.value is not None:
ct.memmove(p_s, ct.byref(state), ct.sizeof(state))
if p_sz.value is not None:
p_state_size[0] = ct.sizeof(state)
return Result.SUCCESS
except Exception as e:
return Error.set_error(e)
else:
serialize_wrapper = 0

if deserialize is not None:
def deserialize_wrapper(tree, feature_space, state_size, p_state, p_tree_space_data):
try:
t = ct.cast(tree, ccs_tree)
p_s = ct.cast(p_state, ct.c_void_p)
p_t = ct.cast(p_tree_space_data, ct.c_void_p)
if p_s.value is None:
state = None
else:
state = ct.cast(p_s, POINTER(c_byte * state_size))
tree_space_data = deserialize(Tree.from_handle(t), FeatureSpace.from_handle(feature_space) if feature_space else None, state)
c_tree_space_data = ct.py_object(tree_space_data)
p_t[0] = c_tree_space_data
ct.pythonapi.Py_IncRef(c_tree_space_data)
return Result.SUCCESS
except Exception as e:
return Error.set_error(e)
else:
deserialize_wrapper = 0

delete_wrapper_func = ccs_dynamic_tree_space_del_type(delete_wrapper)
get_child_wrapper_func = ccs_dynamic_tree_space_get_child_type(get_child_wrapper)
serialize_wrapper_func = ccs_dynamic_tree_space_serialize_type(serialize_wrapper)
deserialize_wrapper_func = ccs_dynamic_tree_space_deserialize_type(deserialize_wrapper)
vec.delete = delete_wrapper_func
vec.get_child = get_child_wrapper_func
vec.serialize = serialize_wrapper_func
vec.deserialize = deserialize_wrapper_func

setattr(vec, '_wrappers', (
delete_wrapper,
get_child_wrapper,
serialize_wrapper,
deserialize_wrapper,
delete_wrapper_func,
get_child_wrapper_func,
serialize_wrapper_func,
deserialize_wrapper_func))
return vec

TreeSpace.Dynamic = DynamicTreeSpace

from .tree_configuration import TreeConfiguration
Loading

0 comments on commit adfa73d

Please sign in to comment.