Skip to content

Commit

Permalink
WIP: User defined expression.
Browse files Browse the repository at this point in the history
  • Loading branch information
Kerilk committed Aug 21, 2024
1 parent 04e867e commit a7d511b
Show file tree
Hide file tree
Showing 6 changed files with 796 additions and 173 deletions.
161 changes: 160 additions & 1 deletion bindings/python/cconfigspace/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ class ExpressionType(CEnumeration):
'IN',
'LIST',
'LITERAL',
'VARIABLE' ]
'VARIABLE',
'USER_DEFINED' ]

class AssociativityType(CEnumeration):
_members_ = [
Expand Down Expand Up @@ -476,6 +477,163 @@ def __str__(self):

Expression.List = ExpressionList

ccs_user_defined_expression_del_type = ct.CFUNCTYPE(Result, ccs_expression)
ccs_user_defined_expression_eval_type = ct.CFUNCTYPE(Result, ccs_expression, ct.c_size_t, ct.POINTER(ccs_expression), ct.POINTER(Datum))
ccs_user_defined_expression_serialize_type = ct.CFUNCTYPE(Result, ccs_expression, ct.c_size_t, ct.c_void_p, ct.POINTER(ct.c_size_t))
ccs_user_defined_expression_deserialize_type = ct.CFUNCTYPE(Result, ct.c_size_t, ct.c_void_p, ct.POINTER(ct.c_void_p))

class UserDefinedExpressionVector(ct.Structure):
_fields_ = [
('delete', ccs_user_defined_expression_del_type),
('evaluate', ccs_user_defined_expression_eval_type),
('serialize', ccs_user_defined_expression_serialize_type),
('deserialize', ccs_user_defined_expression_deserialize_type) ]

ccs_create_user_defined_expression = _ccs_get_function("ccs_create_user_defined_expression", [ct.c_char_p, ct.c_size_t, ct.POINTER(Datum), ct.POINTER(UserDefinedExpressionVector), ct.py_object, ct.POINTER(ccs_expression)])
ccs_user_defined_expression_get_name = _ccs_get_function("ccs_user_defined_expression_get_name", [ccs_expression, ct.POINTER(ct.c_char_p)])
ccs_user_defined_expresion_get_expression_data = _ccs_get_function("ccs_user_defined_expression_get_expression_data", [ccs_expression, ct.POINTER(ct.c_void_p)])

class ExpressionUserDefined(Expression):
def __init__(self, handle = None, retain = False, auto_release = True,
name = "", nodes = [], delete = None, evaluate = None, serialize = None, deserialize = None, expression_data = None):
if handle is None:
if evaluate is None:
raise Error(Result(Result.ERROR_INVALID_VALUE))

vec = self.get_vector(delete, evaluate, serialize, deserialize)
c_expression_data = None
if expression_data is not None:
c_expression_data = ct.py_object(expression_data)
handle = ccs_expression()
sz = len(nodes)
v = (Datum*sz)()
ss = []
for i in range(sz):
v[i].set_value(values[i], string_store = ss)
res = ccs_create_user_defined_expression(str.encode(name), sz, v, ct.byref(vec), c_expression_data, ct.byref(handle))
Error.check(res)
super().__init__(handle = handle, retain = False)
ct.pythonapi.Py_IncRef(ct.py_object(vec))
if c_expression_data is not None:
ct.pythonapi.Py_IncRef(c_expression_data)
else:
super().__init__(handle = handle, retain = retain, auto_release = auto_release)

@property
def name(self):
if hasattr(self, "_name"):
return self._name
v = ct.c_char_p()
res = ccs_expression_get_name(self.handle, ct.byref(v))
Error.check(res)
self._name = v.value.decode()
return self._name

@property
def expression_data(self):
if hasattr(self, "_expression_data"):
return self._expression_data
v = ct.c_void_p()
res = ccs_user_defined_expression_get_expression_data(self.handle, ct.byref(v))
Error.check(res)
if v:
self._expression_data = ct.cast(v, ct.py_object).value
else:
self._expression_data = None
return self._expression_data

@classmethod
def get_vector(self, delete = None, evaluate = None, serialize = None, deserialize = None):
vec = UserDefinedExpressionVector()
setattr(vec, '_string_store', list())
setattr(vec, '_object_store', list())
def delete_wrapper(expr):
try:
expr = ct.cast(expr, ccs_expression)
o = Object.from_handle(expr)
edata = o.expression_data
if delete is not None:
delete(o)
if edata is not None:
ct.pythonapi.Py_DecRef(ct.py_object(edata))
ct.pythonapi.Py_DecRef(ct.py_object(vec))
return Result.SUCCESS
except Exception as e:
return Error.set_error(e)

def evaluate_wrapper(expr, num_values, p_values, p_value_ret):
try:
expr = ct.cast(expr, ccs_expression)
if num_values == 0:
value_ret = evaluate(Expression.from_handle(expr))
else:
values = tuple(p_values[i] for i in range(num_values))
value_ret = evaluate(Expression.from_handle(expr), *values)
p_value_ret[0].set_value(value_ret, string_store = getattr(vec, '_string_store'), object_store = getattr(vec, '_object_store'))
return Result.SUCCESS
except Exception as e:
return Error.set_error(e)

if serialize is not None:
def serialize_wrapper(expr, state_size, p_state, p_state_size):
try:
expr = ct.cast(expr, ccs_expression)
p_s = ct.cast(p_state, ct.c_void_p)
p_sz = ct.cast(p_state_size, ct.c_void_p)
state = serialize(Expression.from_handle(expr), 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(state_size, p_state, p_expression_data):
try:
p_s = ct.cast(p_state, ct.c_void_p)
p_e = ct.cast(p_expression_data, ct.c_void_p)
if p_s.value is None:
state = None
else:
state = ct.cast(p_s, POINTER(c_byte * state_size))
expression_data = deserialize(state)
c_expression_data = ct.py_object(expression_data)
p_e[0] = c_expression_data
ct.pythonapi.Py_IncRef(c_expression_data)
return Result.SUCCESS
except Exception as e:
return Error.set_error(e)
else:
deserialize_wrapper = 0

delete_wrapper_func = ccs_user_defined_expression_del_type(delete_wrapper)
evaluate_wrapper_func = ccs_user_defined_expression_eval_type(evaluate_wrapper)
serialize_wrapper_func = ccs_user_defined_expression_serialize_type(serialize_wrapper)
deserialize_wrapper_func = ccs_user_defined_expression_deserialize_type(deserialize_wrapper)
vec.delete = delete_wrapper_func
vec.evaluate = evaluate_wrapper_func
vec.serialize = serialize_wrapper_func
vec.deserialize = deserialize_wrapper_func

setattr(vec, '_wrappers', (
delete_wrapper,
evaluate_wrapper,
serialize_wrapper,
deserialize_wrapper,
delete_wrapper_func,
evaluate_wrapper_func,
serialize_wrapper_func,
deserialize_wrapper_func))
return vec

Expression.UserDefined = ExpressionUserDefined

setattr(Expression, 'EXPRESSION_MAP', {
ExpressionType.OR: ExpressionOr,
ExpressionType.AND: ExpressionAnd,
Expand All @@ -497,4 +655,5 @@ def __str__(self):
ExpressionType.LIST: ExpressionList,
ExpressionType.LITERAL: ExpressionLiteral,
ExpressionType.VARIABLE: ExpressionVariable,
ExpressionType.USER_DEFINED: ExpressionUserDefined,
})
6 changes: 4 additions & 2 deletions bindings/ruby/lib/cconfigspace/expression.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ module CCS
:CCS_EXPRESSION_TYPE_IN,
:CCS_EXPRESSION_TYPE_LIST,
:CCS_EXPRESSION_TYPE_LITERAL,
:CCS_EXPRESSION_TYPE_VARIABLE
:CCS_EXPRESSION_TYPE_VARIABLE,
:CCS_EXPRESSION_TYPE_USER_DEFINED,
]
class MemoryPointer
def read_ccs_expression_type_t
Expand Down Expand Up @@ -115,7 +116,8 @@ def self.expression_map
CCS_EXPRESSION_TYPE_IN: In,
CCS_EXPRESSION_TYPE_LIST: List,
CCS_EXPRESSION_TYPE_LITERAL: Literal,
CCS_EXPRESSION_TYPE_VARIABLE: Variable
CCS_EXPRESSION_TYPE_VARIABLE: Variable,
# CCS_EXPRESSION_TYPE_USER_DEFINED: UserDefined
}
end

Expand Down
124 changes: 122 additions & 2 deletions include/cconfigspace/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ enum ccs_expression_type_e {
CCS_EXPRESSION_TYPE_LITERAL,
/** Variable */
CCS_EXPRESSION_TYPE_VARIABLE,
/** User defined */
CCS_EXPRESSION_TYPE_USER_DEFINED,
/** Guard */
CCS_EXPRESSION_TYPE_MAX,
/** Try forcing 32 bits value for bindings */
Expand All @@ -79,7 +81,7 @@ typedef enum ccs_expression_type_e ccs_expression_type_t;
* - 6 : POSITIVE, NEGATIVE, NOT
* - 7 : IN
* - max - 1: LIST
* - max : LITERAL, VARIABLE
* - max : LITERAL, VARIABLE, USER_DEFINED
*
* Those are similar to C's precedence
*/
Expand Down Expand Up @@ -117,7 +119,7 @@ typedef enum ccs_associativity_type_e ccs_associativity_type_t;
* - right: POSITIVE, NEGATIVE, NOT
* - left: IN
* - left: LIST
* - none: LITERAL, VARIABLE
* - none: LITERAL, VARIABLE, USER_DEFINED
*/
extern const ccs_associativity_type_t ccs_expression_associativity[];

Expand All @@ -143,6 +145,7 @@ extern const ccs_associativity_type_t ccs_expression_associativity[];
* - LIST: NULL
* - LITERAL: NULL
* - VARIABLE: NULL
* - USER_DEFINED: NULL
*/
extern const char *ccs_expression_symbols[];

Expand All @@ -158,6 +161,7 @@ extern const char *ccs_expression_symbols[];
* - 2: IN
* - -1: LIST
* - 0: LITERAL, VARIABLE
* - -1: USER_DEFINED
*/
extern const int ccs_expression_arity[];

Expand Down Expand Up @@ -349,6 +353,87 @@ ccs_create_literal(ccs_datum_t value, ccs_expression_t *expression_ret);
extern ccs_result_t
ccs_create_variable(ccs_parameter_t parameter, ccs_expression_t *expression_ret);

/**
* A structure that define the callbacks the user must provide to create a user
* defined expression.
*/
struct ccs_user_defined_expression_vector_s {
/**
* The deletion callback that will be called once the reference count
* of the expression reaches 0.
*/
ccs_result_t (*del)(ccs_expression_t expression);

/**
* The expression evaluation interface.
*/
ccs_result_t (*eval)(
ccs_expression_t expression,
size_t num_values,
ccs_datum_t *values,
ccs_datum_t *value_ret);

/**
* The expression serialization interface, can be NULL.
*/
ccs_result_t (*serialize_user_state)(
ccs_expression_t expression,
size_t sate_size,
void *state,
size_t *state_size_ret);

/**
* The expression deserialization interface, can be NULL.
*/
ccs_result_t (*deserialize_state)(
size_t state_size,
const void *state,
void **expression_data_ret);
};

/**
* a commodity type to represent a user defined expression callback vector.
*/
typedef struct ccs_user_defined_expression_vector_s
ccs_user_defined_expression_vector_t;


/**
* Create a new user defined expression.
* @param[in] name the name of the expression
* @param[in] num_nodes the number of the expression children nodes. Must be
* compatible with the arity of the expression
* @param[in] nodes an array of \p num_nodes expressions
* @param[in] vector the vector of callbacks implementing the expression
* interface
* @param[in] expression_data a pointer to the expression internal data
* structures. Can be NULL
* @param[out] expression_ret a pointer to the variable that will hold the newly
* created expression
* @return #CCS_RESULT_SUCCESS on success
* @return #CCS_RESULT_ERROR_INVALID_OBJECT if one the nodes given is of type
* #CCS_DATA_TYPE_OBJECT but the object is not a valid CCS object
* @return #CCS_RESULT_ERROR_INVALID_VALUE if \p name is NULL; or if one the
* nodes given is of type #CCS_DATA_TYPE_OBJECT but is neither a
* #CCS_OBJECT_TYPE_PARAMETER nor a #CCS_OBJECT_TYPE_EXPRESSION; or if one the
* nodes given node is not a type #CCS_DATA_TYPE_OBJECT, #CCS_DATA_TYPE_NONE,
* #CCS_DATA_TYPE_INT, #CCS_DATA_TYPE_FLOAT, #CCS_DATA_TYPE_BOOL, or
* #CCS_DATA_TYPE_STRING; or if \p expression_ret is NULL; or if \p vector is
* NULL; or if any non optional interface pointer is NULL
* @return #CCS_RESULT_ERROR_OUT_OF_MEMORY if there was not enough memory to
* allocate the new expression instance
* @remarks
* This function is thread-safe
*/
extern ccs_result_t
ccs_create_user_defined_expression(
const char *name,
size_t num_nodes,
ccs_datum_t *nodes,
ccs_user_defined_expression_vector_t *vector,
void *expression_data,
ccs_expression_t *expression_ret);

/**
* Get the type of an expression.
* @param[in] expression
Expand Down Expand Up @@ -427,6 +512,41 @@ ccs_variable_get_parameter(
ccs_expression_t expression,
ccs_parameter_t *parameter_ret);

/**
* Get the name of a user defined expression.
* @param[in] expression
* @param[out] name_ret a pointer to the variable that will contain a pointer to
* the name of the expression
* @return #CCS_RESULT_SUCCESS on success
* @return #CCS_RESULT_ERROR_INVALID_VALUE if \p name_ret is NULL
* @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p expression is not a valid CCS expression
* @return #CCS_RESULT_ERROR_INVALID_EXPRESSION if \p expression is not a user
* defined expression
* @remarks
* This function is thread-safe
*/
extern ccs_result_t
ccs_user_defined_expression_get_name(
ccs_expression_t expression,
const char **name_ret);

/**
* Get the user defined expression internal data pointer.
* @param[in] expression
* @param[out] expression_data_ret
* @return #CCS_RESULT_SUCCESS on success
* @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p expression is not a valid CCS expression
* @return #CCS_RESULT_ERROR_INVALID_EXPRESSION if \p expression is not a user
* defined expression
* @return #CCS_RESULT_ERROR_INVALID_VALUE if \p expression_data_ret is NULL
* @remarks
* This function is thread-safe
*/
extern ccs_result_t
ccs_user_defined_expression_get_expression_data(
ccs_expression_t expression,
void **expression_data_ret);

/**
* Get the value of an expression, in a given list of bindings.
* @param[in] expression
Expand Down
Loading

0 comments on commit a7d511b

Please sign in to comment.