Tuesday, May 16, 2017

GNU Compiler Collection: extensions, nested functions, object-oriented programming, functional paradigm etc. It's the C language only!

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.

No comments:

Post a Comment

How to reverse singly linked list in C (trivial way)

There is a beautiful morning. It's snowing. And I decided to write one more article. Today it will be just simple article where I would...