def has_allocated_member(validator): """Test if a validator has an allocatable field""" if validator.is_optional or isinstance(validator, (Include, List, Map, String)): return True if isinstance(validator, Any): any_validators = find_nested_any(validator) for val in any_validators: if isinstance(val, (Include, List, Map, String)): return True return False
def __init__(self, type, pointer_order=0, has_list_parent=False, has_map_parent=False): sub_type_list = type.validators sub_type_list = find_nested_any(sub_type_list) self.sub_type_list = sub_type_list self.pointer_order = pointer_order self.is_optional = type.is_optional self.has_list_parent = has_list_parent self.has_map_parent = has_map_parent
def c_free_memory(schema, validator, c_variable, path_to_enum, indent_level, indices=[], recursion_depth=0): """Free the memory of a c variable's allocated elements, without deallocating the c variable itself""" # Lines of code are represented by tuples of two elements: indentation level and string of characters code_lines = [] if validator.is_optional: struct_ref = '->' else: struct_ref = '.' # Freeing the memory of a variable corresponding to an any() validator if isinstance(validator, Any): validator.validators = find_nested_any(validator.validators) sub_validators = [ _val for _val in validator.validators if isinstance(_val, (Include, List, Map, String)) ] # Inside Lists/Maps only Includes/Lists/Maps/Strings are allocated for _val in sub_validators: if isinstance(_val, Include): _val.is_required = False if len(sub_validators) > 0: enum_names, _ = make_union_names( sub_validators ) # We only consider the enum names of allocatable fields enum_name = enum_names[0] code_lines.append( (indent_level + 1, 'if (%s == %s) {' % ('_'.join(path_to_enum) + '_' + enum_name, c_variable + struct_ref + 'type'))) if isinstance(sub_validators[0], String): code_lines.append( (indent_level + 2, 'if (NULL != %s) {' % (c_variable + struct_ref + 'item.' + enum_name + '_value'))) code_lines.append( (indent_level + 3, 'free(%s);' % (c_variable + struct_ref + 'item.' + enum_name + '_value'))) code_lines.append((indent_level + 2, '}')) else: if sub_validators[0].is_optional: indent_level += 1 code_lines.append((indent_level + 1, 'if (NULL != %s) {' % (c_variable + struct_ref + 'item.' + enum_name + '_value'))) code_lines.extend( c_free_memory( schema, sub_validators[0], c_variable + struct_ref + 'item.' + enum_name + '_value', path_to_enum + [enum_name], indent_level + 1, indices, recursion_depth)) if sub_validators[0].is_optional: code_lines.append( (indent_level + 2, 'free(%s);' % (c_variable + struct_ref + 'item.' + enum_name + '_value'))) code_lines.append((indent_level + 1, '}')) indent_level -= 1 code_lines.append((indent_level + 1, '}')) for i, enum_name in enumerate(enum_names[1:], 1): code_lines.append((indent_level + 1, 'else if (%s == %s) {' % ('_'.join(path_to_enum) + '_' + enum_name, c_variable + struct_ref + 'type'))) if isinstance(sub_validators[i], String): code_lines.append((indent_level + 2, 'if (NULL != %s) {' % (c_variable + struct_ref + 'item.' + enum_name + '_value'))) code_lines.append( (indent_level + 3, 'free(%s);' % (c_variable + struct_ref + 'item.' + enum_name + '_value'))) code_lines.append((indent_level + 2, '}')) else: if sub_validators[i].is_optional: indent_level += 1 code_lines.append( (indent_level + 1, 'if (NULL != %s) {' % (c_variable + struct_ref + 'item.' + enum_name + '_value'))) code_lines.extend( c_free_memory( schema, sub_validators[i], c_variable + struct_ref + 'item.' + enum_name + '_value', path_to_enum + [enum_name], indent_level + 1, indices, recursion_depth)) if sub_validators[i].is_optional: code_lines.append( (indent_level + 2, 'free(%s);' % (c_variable + struct_ref + 'item.' + enum_name + '_value'))) code_lines.append((indent_level + 1, '}')) indent_level -= 1 code_lines.append((indent_level + 1, '}')) # Freeing the memory of a variable corresponding to an enum() validator elif isinstance(validator, Enum): new_validator = convert_enum_to_any(validator) code_lines.extend( c_free_memory(schema, new_validator, c_variable, path_to_enum, indent_level, indices, recursion_depth)) # Freeing the memory of a variable corresponding to an include() validator elif isinstance(validator, Include): if validator.is_optional: code_lines.append((indent_level + 1, 'free_%s(%s);' % (replace_chars(validator.args[0]), c_variable))) else: code_lines.append((indent_level + 1, 'free_%s(&(%s));' % (replace_chars(validator.args[0]), c_variable))) # Freeing the memory of a variable corresponding to a list() validator elif isinstance(validator, List): validator.validators = find_nested_any(validator.validators) sub_validators = [ _val for _val in validator.validators if isinstance(_val, (Include, List, Map, String)) ] # Inside Lists/Maps only Includes/Lists/Maps are allocated for sub_val in sub_validators: # Only Includes validators will be pointers if not isinstance(sub_val, Include): sub_val.is_required = True else: sub_val.is_required = False # If the list has been allocated we have to deallocate it code_lines.append( (indent_level + 1, 'if (NULL != %s%stab) {' % (c_variable, struct_ref))) if len(sub_validators) > 0: indices.append('i%d' % (recursion_depth)) code_lines.append( (indent_level + 2, 'for (int %s = 0 ; %s < %s%slen ; ++%s) {' % (indices[-1], indices[-1], c_variable, struct_ref, indices[-1]))) _val = Any() _val.validators = sub_validators code_lines.extend( c_free_memory( schema, _val, '%s%stab[%s]' % (c_variable, struct_ref, indices[-1]), path_to_enum, indent_level + 2, indices, recursion_depth + 1)) code_lines.append((indent_level + 2, '}')) indices.pop() code_lines.append( (indent_level + 2, 'free(%s%stab);' % (c_variable, struct_ref))) code_lines.append((indent_level + 1, '}')) # Freeing the memory of a variable corresponding to a map() validator elif isinstance(validator, Map): validator.validators = find_nested_any(validator.validators) sub_validators = [ _val for _val in validator.validators if isinstance(_val, (Include, List, Map, String)) ] # Inside Lists/Maps only Includes/Lists/Maps are allocated for sub_val in sub_validators: # Only Includes validators will be pointers if not isinstance(sub_val, Include): sub_val.is_required = True else: sub_val.is_required = False # If the map has been allocated we have to deallocate it code_lines.append( (indent_level + 1, 'if (NULL != %s%smap) {' % (c_variable, struct_ref))) indices.append('i%d' % (recursion_depth)) code_lines.append( (indent_level + 2, 'for (int %s = 0 ; %s < %s%slen ; ++%s) {' % (indices[-1], indices[-1], c_variable, struct_ref, indices[-1]))) code_lines.append((indent_level + 3, 'if (NULL != %s%smap[%s].key) {' % (c_variable, struct_ref, indices[-1]))) code_lines.append( (indent_level + 4, 'free(%s%smap[%s].key);' % (c_variable, struct_ref, indices[-1]))) code_lines.append((indent_level + 3, '}')) if len(sub_validators) > 0: _val = Any() _val.validators = sub_validators code_lines.extend( c_free_memory( schema, _val, '%s%smap[%s]' % (c_variable, struct_ref, indices[-1]), path_to_enum, indent_level + 2, indices, recursion_depth + 1)) code_lines.append((indent_level + 2, '}')) code_lines.append( (indent_level + 2, 'free(%s%smap);' % (c_variable, struct_ref))) code_lines.append((indent_level + 1, '}')) indices.pop() return code_lines
def c_free_includes(schema, code_lines, header_lines): """Generate the "free" functions corresponding to the included nodes""" indent_level = 0 header_lines.append((indent_level, '')) # We gather all potentially allocated variables allocated_variables = [] sorted_key_list = [k for k in schema.includes.keys()] sorted_key_list.sort() for included_key in sorted_key_list: allocated_variables.append([]) for key in schema.includes[included_key]._schema.keys(): if schema.includes[included_key]._schema[ key].is_optional or isinstance( schema.includes[included_key]._schema[key], (Include, List, Map, String)): allocated_variables[-1].append(key) elif isinstance(schema.includes[included_key]._schema[key], Any): any_validators = find_nested_any( schema.includes[included_key]._schema[key].validators) for val in any_validators: if isinstance(val, (Include, List, Map, String)): allocated_variables[-1].append(key) break elif isinstance(schema.includes[included_key]._schema[key], Enum): any_val = convert_enum_to_any( schema.includes[included_key]._schema[key]) for val in any_val.validators: if isinstance(val, String): allocated_variables[-1].append(key) break # We add the declaration/definition of "free" functions in the header/code for i, included_key in enumerate(sorted_key_list): header_lines.append( (indent_level, 'void free_%s(%s_t* %s);' % (replace_chars(included_key), replace_chars(included_key), replace_chars(included_key)))) code_lines.append((indent_level, '')) code_lines.append((indent_level, '')) code_lines.append( (indent_level, 'void free_%s(%s_t* %s) {' % (replace_chars(included_key), replace_chars(included_key), replace_chars(included_key)))) code_lines.append( (indent_level + 1, 'if (NULL != %s->generic.node) {' % (replace_chars(included_key)))) code_lines.append( (indent_level + 2, 'free(%s->generic.node);' % (replace_chars(included_key)))) code_lines.append((indent_level + 1, '}')) for key in allocated_variables[i]: val = schema.includes[included_key]._schema[key] path_to_enum = [replace_chars(included_key), replace_chars(key)] header_lines.append( (indent_level, 'void free_%s(%s_t* %s);' % ('_'.join(path_to_enum), replace_chars(included_key), replace_chars(included_key)))) code_lines.append( (indent_level + 1, 'free_%s(%s);' % ('_'.join(path_to_enum), replace_chars(included_key)))) code_lines.append((indent_level, '}')) # We add the declaration/edfinition of free sub-functions in the header/code for i, included_key in enumerate(sorted_key_list): for key in allocated_variables[i]: val = schema.includes[included_key]._schema[key] c_variable = '%s->%s' % (replace_chars(included_key), replace_chars(key)) path_to_enum = [replace_chars(included_key), replace_chars(key)] code_lines.extend( c_free_node(schema, val, c_variable, path_to_enum))
def c_free_root(schema): """Generate the functions' declaration and definitions to free all the root's fields""" code_lines = [] header_lines = [] indent_level = 0 c_free_includes(schema, code_lines, header_lines) code_lines.append((indent_level, '')) code_lines.append((indent_level, 'void free_root(root_t* root) {')) code_lines.append((indent_level, '')) header_lines.append((indent_level, '')) header_lines.append((indent_level, 'void free_root(root_t* root);')) header_lines.append((indent_level, '')) # We free all generic types dependency_tree = make_flat_tree(schema._schema.keys()) code_lines.extend( c_free_generic(dependency_tree, '', 'root->', indent_level + 1)) # We gather all potentially allocated variables allocated_variables = [] for key in schema._schema.keys(): if schema._schema[key].is_optional or isinstance( schema._schema[key], (Include, List, Map, String)): allocated_variables.append(key) elif isinstance(schema._schema[key], Any): any_validators = find_nested_any(schema._schema[key].validators) for val in any_validators: if isinstance(val, (Include, List, Map, String)): allocated_variables.append(key) break allocated_variables.sort() # We call the sub-free functions (free_root_<path_to_depenedncy>()) inside free_root() for allocated_var in allocated_variables: c_path = [replace_chars(s) for s in allocated_var.split('.')] code_lines.append( (indent_level + 1, 'free_root_%s(root);' % ('_'.join(c_path)))) code_lines.append((indent_level, '}')) # We define the sub-free functions (free_root_<path_to_depenedncy>()) for allocated_var in allocated_variables: validator = schema._schema[allocated_var] c_path = [replace_chars(s) for s in allocated_var.split('.')] c_variable = 'root->' + '.'.join(c_path) path_to_enum = ['root'] + c_path code_lines.extend( c_free_node(schema, validator, c_variable, path_to_enum)) header_lines.append( (indent_level, 'void free_root_%s(root_t* root);' % ('_'.join(c_path)))) # We generate the end of the header file header_lines.append((indent_level, '')) header_lines.append((indent_level, '')) header_lines.append((indent_level, '#endif')) return code_lines, header_lines