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:
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.