Hello my dear frineds!
I want to tell you about possibilities of the C language. I will do it with the example of a linear list.
You can see the links:
All GCC Extensions
Nested Functions
So. It's a structure of the linked list:
It's a structure of the storage with the linked list:
The first argument of all functions is a pointer to "this" (self, this etc).
This is the complete text of the code (I apologize for the strange syntax highlighting):
storage.h:
storage.c:
test.c:
build.sh:
It's a result (without Valgrind):
It's a result (with Valgrind):
I want to tell you about possibilities of the C language. I will do it with the example of a linear list.
You can see the links:
All GCC Extensions
Nested Functions
So. It's a structure of the linked list:
struct storage_data_s { value_t value; char* name; char* comment; struct storage_data_s* next; }* data;
It's a structure of the storage with the linked list:
/* It's a storage */ typedef struct storage_s { struct storage_data_s { value_t value; char* name; char* comment; struct storage_data_s* next; }* data; void (*init)(struct storage_s* _this); void (*add)(struct storage_s* _this, value_t _value, char* _name, char* _comment); void (*for_each)(struct storage_s const* _this, output_f output); void (*clear)(struct storage_s* _this); void (*deinit)(struct storage_s* _this); } storage_t, *storage_p, **storage_pp, *const storage_cp; typedef storage_t const* storage_pc; typedef storage_t const* const storage_cpc;
The first argument of all functions is a pointer to "this" (self, this etc).
This is the complete text of the code (I apologize for the strange syntax highlighting):
storage.h:
/* **************************************************************************** * Programmer: Vasiliy V. Bodrov aka Bodro * May 15, 2016. * **************************************************************************** * The MIT License (MIT) * * Copyright (c) 2016 Vasiliy V. Bodrov aka Bodro * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************************** */ #pragma once #include <stdbool.h> /* It's a type of value */ typedef void* value_t; typedef void** value_p; typedef void const* value_tc; /* The user must to determine these functions */ #ifndef __STORAGE_C_FILE__ typedef struct __value_user_helpers_handlers_s { value_t (*new)(user_value_t _uv); user_value_t (*get)(value_tc _v); user_value_t (*get2)(value_tc _v, user_value_t _container); } __value_user_helpers_handlers_t, *__value_user_helpers_handlers_p; #else /* __STORAGE_C_FILE__ */ typedef void* __value_user_helpers_handlers_p; #endif /* __STORAGE_C_FILE__ */ typedef struct value_handlers_s { void (*delete)(value_p _v); value_t (*copy)(value_tc _v); value_t (*move)(value_p _v); bool (*p_move)(void); /* predicate */ __value_user_helpers_handlers_p x; } value_handlers_t; #ifdef __STORAGE_C_FILE__ value_handlers_t __value_helpers_handlers; #else /* __STORAGE_C_FILE__ */ extern value_handlers_t __value_helpers_handlers; #endif /* __STORAGE_C_FILE__ */ /* This type is pointer to output function */ typedef void (*output_f)(value_t _value, char const* _name, char const* _comment); /* It's a storage */ typedef struct storage_s { struct storage_data_s { value_t value; char* name; char* comment; struct storage_data_s* next; }* data; void (*init)(struct storage_s* _this); void (*add)(struct storage_s* _this, value_t _value, char* _name, char* _comment); void (*for_each)(struct storage_s const* _this, output_f output); void (*clear)(struct storage_s* _this); void (*deinit)(struct storage_s* _this); } storage_t, *storage_p, **storage_pp, *const storage_cp; typedef storage_t const* storage_pc; typedef storage_t const* const storage_cpc; /* These are creator and remover */ storage_p storage_creator(void); void storage_remover(storage_pp); /* **************************************************************************** * End of file **************************************************************************** */
storage.c:
/* **************************************************************************** * Programmer: Vasiliy V. Bodrov aka Bodro * May 15, 2016. * **************************************************************************** * The MIT License (MIT) * * Copyright (c) 2016 Vasiliy V. Bodrov aka Bodro * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************************** */ #define __STORAGE_C_FILE__ #include "storage.h" #include <stdlib.h> #include <string.h> #include <assert.h> #include <stdbool.h> static void handler_init(struct storage_s*); static void handler_add(struct storage_s*, value_t, char*, char*); static void handler_for_each(struct storage_s const*, output_f); static void handler_clear(struct storage_s*); static void handler_deinit(struct storage_s*); /* * These are exported functions */ storage_p storage_creator(void) { storage_p _storage = NULL; _storage = (storage_p) calloc(1, sizeof(storage_t)); assert(_storage); if(_storage) { _storage->init = handler_init; _storage->add = handler_add; _storage->for_each = handler_for_each; _storage->clear = handler_clear; _storage->deinit = handler_deinit; _storage->init(_storage); } return _storage; } void storage_remover(storage_pp _storage) { assert(*_storage); if(*_storage) { if((*_storage)->deinit) { (*_storage)->deinit(*_storage); } free(*_storage); *_storage = NULL; } } /* * These are static (internal) functions */ void handler_init(struct storage_s* _this) { assert(_this); _this->clear(_this); _this->data = NULL; } void handler_add(struct storage_s* _this, value_t _value, char* _name, char* _comment) { assert(_this); auto struct storage_data_s* _search_end(struct storage_data_s*); auto struct storage_data_s* _allocator(struct storage_data_s*); auto void _add(struct storage_data_s*); auto value_t _copy(value_p _value); _add(_allocator(_search_end(_this->data))); struct storage_data_s* _search_end(struct storage_data_s* _) { if(!_ || !_->next) return _; return _search_end(_->next); } struct storage_data_s* _allocator(struct storage_data_s* _) { struct storage_data_s* _new = (struct storage_data_s*) calloc(1, sizeof(struct storage_data_s)); assert(_new); if(_) _->next = _new; else _this->data = _new; return _new; } void _add(struct storage_data_s* _) { assert(_); _->value = _copy(&_value); _->name = (_name) ? strdup(_name) : NULL; _->comment = (_comment) ? strdup(_comment) : NULL; _->next = NULL; } value_t _copy(value_p _value) { return (__value_helpers_handlers.p_move()) ? __value_helpers_handlers.move(_value) : __value_helpers_handlers.copy(*_value); } } void handler_for_each(struct storage_s const* _this, output_f _output) { assert(_this); assert(_output); auto void _f(struct storage_data_s*); _f(_this->data); void _f(struct storage_data_s* _) { if(!_) return; _output(_->value, _->name, _->comment); _f(_->next); } } void handler_clear(struct storage_s* _this) { assert(_this); auto void _purge(struct storage_data_s*); _purge(_this->data); _this->data = NULL; void _purge(struct storage_data_s* _) { if(!_) return; if(_->name) { free(_->name); } if(_->comment) { free(_->comment); } __value_helpers_handlers.delete(&(_->value)); _->value = NULL; _->name = NULL; _->comment = NULL; /* Note. It isn't a tail call! I can do the tail recursion, * but I don't want this. So I use direct recursion. Bodro. */ _purge(_->next); _->next = NULL; free(_); _ = NULL; } } void handler_deinit(struct storage_s* _this) { assert(_this); _this->clear(_this); _this->data = NULL; } #ifdef __STORAGE_C_FILE__ #undef __STORAGE_C_FILE__ #endif /* __STORAGE_C_FILE__ */ /* **************************************************************************** * End of file **************************************************************************** */
test.c:
/* **************************************************************************** * Programmer: Vasiliy V. Bodrov aka Bodro * May 15, 2016. * **************************************************************************** * The MIT License (MIT) * * Copyright (c) 2016 Vasiliy V. Bodrov aka Bodro * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************************** */ #include <assert.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdbool.h> /* BEGIN >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */ /* We prepare the user types and functions */ struct string_s; typedef struct string_func_s { char* (*s_new)(struct string_s* _this, char const* _s); char const* (*s_get)(struct string_s* _this); void (*s_del)(struct string_s* _this); } string_func_t; typedef struct string_s { struct string_s* _self; /* It's a pointer to yourself */ char* s; /* It's a date (string) */ struct string_func_s* f; /* It's a pointer to table of functions */ } string; typedef string user_value_t; #include "storage.h" /* END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ string new_string(string_func_t* _f); string new_string2(string_func_t* _f, char const* _v); void del_string(string* _s); inline static char* handler_s_new(struct string_s*, char const*); inline static char const* handler_s_get(struct string_s*); inline static void handler_s_del(struct string_s*); void user_handler_delete(value_p); value_t user_handler_copy(value_tc); value_t user_handler_move(value_p); value_t user_handler_new(user_value_t); user_value_t user_handler_get(value_tc); user_value_t user_handler_get2(value_tc, user_value_t); string new_string(string_func_t* _f) { string* _s = malloc(sizeof(string)); assert(_s); _s->_self = _s; _s->s = NULL; _s->f = _f; return *_s; } string new_string2(string_func_t* _f, char const* _v) { string s = new_string(_f); s.f->s_new(s._self, _v); return s; } void del_string(string* _s) { if(_s) { _s->f->s_del(_s); _s->f = NULL; _s->_self = NULL; free(_s); } } char* handler_s_new(struct string_s* _this, char const* _s) { assert(_this); if(_this && _this->s) _this->f->s_del(_this); _this->s = (_s) ? strdup(_s) : NULL; return _this->s; } char const* handler_s_get(struct string_s* _this) { assert(_this); return _this->s; } void handler_s_del(struct string_s* _this) { assert(_this); if(_this && _this->s) { free(_this->s); _this->s = NULL; } } void user_handler_delete(value_p _v) { if(_v && *_v) { del_string((string*) *_v); *_v = NULL; } } value_t user_handler_copy(value_tc _v) { string s_old = user_handler_get(_v); string s_new = new_string2(s_old.f, s_old.f->s_get(s_old._self)); return user_handler_new(s_new); } value_t user_handler_move(value_p _v) { assert(_v); string s_old = user_handler_get(*_v); string s_new = new_string2(s_old.f, s_old.f->s_get(s_old._self)); del_string(s_old._self); return user_handler_new(s_new); } value_t user_handler_new(user_value_t _uv) { return (value_t) _uv._self; } user_value_t user_handler_get(value_tc _v) { assert(_v); return *((string*) _v); } user_value_t user_handler_get2(value_tc _v, user_value_t _container) { (void) _container; return user_handler_get(_v); } int main(int argc, char** argv) { (void) argc; (void) argv; auto bool p_true(void); auto bool p_false(void); string_func_t s_func; s_func.s_new = handler_s_new; s_func.s_get = handler_s_get; s_func.s_del = handler_s_del; __value_user_helpers_handlers_t user_helpers; user_helpers.new = user_handler_new; user_helpers.get = user_handler_get; user_helpers.get2 = user_handler_get2; __value_helpers_handlers.delete = user_handler_delete; __value_helpers_handlers.copy = user_handler_copy; __value_helpers_handlers.move = user_handler_move; __value_helpers_handlers.x = &user_helpers; /* It's a work (#1) */ do { storage_p storage = storage_creator(); do { /* We don't use "move". We use "copy"*/ __value_helpers_handlers.p_move = p_false; string data = new_string2(&s_func, "> "); storage->add(storage, __value_helpers_handlers.x->new(data), NULL, NULL); del_string(data._self); } while(0); /* We don't use "copy". We use "move"*/ __value_helpers_handlers.p_move = p_true; storage->add(storage, __value_helpers_handlers.x->new( new_string2(&s_func, "Hello")), NULL, NULL); storage->add(storage, __value_helpers_handlers.x->new( new_string2(&s_func, ",")), NULL, NULL); storage->add(storage, __value_helpers_handlers.x->new( new_string2(&s_func, " ")), NULL, NULL); storage->add(storage, __value_helpers_handlers.x->new( new_string2(&s_func, "World")), NULL, NULL); storage->add(storage, __value_helpers_handlers.x->new( new_string2(&s_func, "!")), NULL, NULL); void output1(value_t _value, char const* _name, char const* _comment) { (void) _name; (void) _comment; string s = __value_helpers_handlers.x->get(_value); (void) printf("%s", s.f->s_get(s._self)); } storage->for_each(storage, output1); (void) puts(""); storage_remover(&storage); } while(0); /* It's the end of work */ bool p_true(void) { return true; } bool p_false(void) { return false; } return EXIT_SUCCESS; } /* **************************************************************************** * End of file **************************************************************************** */
build.sh:
#! /bin/bash # To use: # $ rm -f test; clear; ./build.sh; ./test # $ rm -f test; clear; ./build.sh; valgrind ./test # $ rm -f test; clear; ./build.sh; valgrind --leak-check=full ./test gcc -std=gnu99 -Wall -Wextra storage.c test.c -lm -lc -o test #gcc -std=gnu99 -Wall -Wextra -Wtrampolines storage.c test.c -lm -lc -o test
It's a result (without Valgrind):
bodro@vbodrov-pc:~/workspace/develop/test/test62$ rm -f test; ./build.sh; ./test > Hello, World! bodro@vbodrov-pc:~/workspace/develop/test/test62$
It's a result (with Valgrind):
bodro@vbodrov-pc:~/workspace/develop/test/test62$ rm -f test; ./build.sh; valgrind --leak-check=full ./test ==23326== Memcheck, a memory error detector ==23326== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==23326== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info ==23326== Command: ./test ==23326== > Hello, World! ==23326== ==23326== HEAP SUMMARY: ==23326== in use at exit: 0 bytes in 0 blocks ==23326== total heap usage: 32 allocs, 32 frees, 1,594 bytes allocated ==23326== ==23326== All heap blocks were freed -- no leaks are possible ==23326== ==23326== For counts of detected and suppressed errors, rerun with: -v ==23326== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) bodro@vbodrov-pc:~/workspace/develop/test/test62$
Best regards,
Vasiliy V. Bodrov aka Bodro,
May 15-16, 2017.
No comments:
Post a Comment