вторник, 4 марта 2014 г.

How to return value from C macro

Usually I use variable name in C macro as out parameter (it's standard way in Tcl, for example). But there is another way, something like in functional languages, with expression. See:
#define GETX(X) ({ \
        int x = (X)*2; \
        x; \
        })

void main()
{
    printf("%d\n", GETX(56));
}
This example shows hot to return value from GETX(), which really is expression. Works in GCC :)

вторник, 4 февраля 2014 г.

Debug messages support for C, ver 2

This C module support debug/logging system with custom levels of messages. Suppressing of some level/levels are possible via DBG_LEVEL macro variable. Each custom level is created with DBG_LEVEL_ALIAS() macro. USer can define own print/dump implementations via DBG_PRN_IMPL/DBG_DUMP_IMPL.
#ifndef __DBG_H
#define __DBG_H

#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>

#define DBG_LEVEL_ALIAS(L) (1<<(L))

#ifndef DBG_LEVEL
#define DBG_LEVEL 0
#endif

#ifndef DBG_LEVEL_FMT
#define DBG_LEVEL_FMT "%s: "
#endif

#define _DBG_PRN_IMPL_L(L, F, ...) printf(F, L, __VA_ARGS__)
#define _DBG_PRN_IMPL(F, ...) printf(F, __VA_ARGS__)
#define _DBG_DUMP_IMPL_L(L, p, sz) do { \
    int i; \
    for (i=0; i<(sz); i++) { \
        if (0 == i%16) { \
            DBG_PRN_IMPL("", "%s%s%08" PRIXPTR ": %02X "/*"%s%s%08lX: %02X "*/, i?"\n":"", \
                    16*i/16 + (uintptr_t)p, (uint8_t)(p)[i]); \
        } else if (0 == (i-7)%16) { \
            DBG_PRN_IMPL("", "%s%02X|", (uint8_t)(p)[i]); \
        } else { \
            DBG_PRN_IMPL("", "%s%02X ", (uint8_t)(p)[i]); \
        } \
    } \
    DBG_PRN_IMPL("", "%s%s", "\n"); \
} while (0)
#define _DBG_DUMP_IMPL(p, sz) do { \
    int i; \
    for (i=0; i<(sz); i++) { \
        if (0 == i%16) { \
            DBG_PRN_IMPL("%s%08" PRIXPTR ": %02X "/*"%s%08lX: %02X "*/, i?"\n":"", \
                    16*i/16 + (uintptr_t)p, (uint8_t)(p)[i]); \
        } else if (0 == (i-7)%16) { \
            DBG_PRN_IMPL("%02X|", (uint8_t)(p)[i]); \
        } else { \
            DBG_PRN_IMPL("%02X ", (uint8_t)(p)[i]); \
        } \
    } \
    DBG_PRN_IMPL("%s", "\n"); \
} while (0)

#ifdef DBG_LEVEL_IS_ARG

#ifndef DBG_PRN_IMPL
#define DBG_PRN_IMPL _DBG_PRN_IMPL_L
#endif
#ifndef DBG_DUMP_IMPL
#define DBG_DUMP_IMPL _DBG_DUMP_IMPL_L
#endif

#define DBG_PRN(L, F, ...) if ((DBG_LEVEL) & (L)) DBG_PRN_IMPL(#L, DBG_LEVEL_FMT F, __VA_ARGS__)
#define DBG_DUMP(L, ...) if ((DBG_LEVEL) & (L)) DBG_DUMP_IMPL(#L, __VA_ARGS__)

#else

#ifndef DBG_PRN_IMPL
#define DBG_PRN_IMPL _DBG_PRN_IMPL
#endif
#ifndef DBG_DUMP_IMPL
#define DBG_DUMP_IMPL _DBG_DUMP_IMPL
#endif

#define DBG_PRN(L, ...) if ((DBG_LEVEL) & (L)) DBG_PRN_IMPL(__VA_ARGS__)
#define DBG_DUMP(L, ...) if ((DBG_LEVEL) & (L)) DBG_DUMP_IMPL(__VA_ARGS__)

#endif

/// Print without level
#define DBG_PRN_UL(L, F, ...) if ((DBG_LEVEL) & (L)) DBG_PRN_IMPL("", "%s" F, __VA_ARGS__)

#endif /* EOF */
Usage:
#include <string.h>

// use level name as 1st argument of out DBG_PRN_IMPL
#define DBG_LEVEL_IS_ARG
#define DBG_LEVEL_FMT "[%s] "
#include "dbg.h"

// define levels
#define HARDWARE_LEVEL   DBG_LEVEL_ALIAS(1)
#define WRAPPER_LEVEL   DBG_LEVEL_ALIAS(2)
#define APP_LEVEL       DBG_LEVEL_ALIAS(3)

#undef DBG_LEVEL
#define DBG_LEVEL (HARDWARE_LEVEL|APP_LEVEL)

void main() {
    char dim[] = "0123456789Hello World!";
    DBG_PRN(HARDWARE_LEVEL, "There %d\n", 1);
    DBG_PRN(WRAPPER_LEVEL, "There %d\n", 2);
    DBG_PRN(APP_LEVEL, "There %d\n", 3);
    DBG_DUMP(APP_LEVEL, dim, strlen(dim));
    DBG_PRN_UL(APP_LEVEL, "%s\n", "Done.");
}
Output:
[HARDWARE_LEVEL] There 1
[APP_LEVEL] There 3
0022FEF5: 30 31 32 33 34 35 36 37 38|39 48 65 6C 6C 6F 20
0022FF05: 57 6F 72 6C 64 21
Done.

воскресенье, 2 февраля 2014 г.

Dithering algorithm implemented for IMSH

Today I implemented Dithering algorithms for IMSH (IMage SHell) - see Project WiKi - Dithering. They are: general purpose (see matrixes in imsh.scm library) and special purpose: Atkinson, Floyd-Steinberg, Ordered, Random, General Sierra, General Sierra Two Rows, General Sierra Low, General Floyd-Steinberg, General False Floyd-Steinberg, General Jarvis, General Stucki, General Atkinson, General Burkes.

суббота, 21 декабря 2013 г.

Thread-Safe Circular Queue

Often in data processing applications are needed circular queue implemented in thread-safe way. This is the such implementation without any mutex, locks and so on:
/**
 * @file cqueue.h
 * @defgroup cqueue Circular queue support
 * @{
 * @brief Fast circular queue support
 */
#ifndef _CQUEUE_H
#define _CQUEUE_H

/** It's possible to use another (wrapper) structure or structure with another
name for cqueue implementation. CQUEUE_STRUCT_IMPL should be defined as name
of such structure in this case before to include cqueue.h. This structure
must have members:
 - unsigned integer "size"
 - integer "rpos"
 - integer "wpos"
 - integer "rwrap"
 - integer "wwrap"
 - any other custom fields
*/
#ifdef CQUEUE_STRUCT_IMPL
typedef CQUEUE_STRUCT_IMPL cqueue_t;
#else
/// Circular queue
typedef struct cqueue_t {
    /// Capacity of queue
    unsigned int size;
    /// Reader position
    int rpos;
    /// Writer position
    int wpos;
    /// Reader wrapping flag
    unsigned char rwrap;
    /// Writer wrapping flag
    unsigned char wwrap;
} cqueue_t;

#endif

/** Initializer for circular queue structure instance. Additional args are
needs if separate implementation struct is used */
#define CQUEUE_INITIALIZER(SIZE, ...) { \
    .size = (SIZE), \
    .rpos = 0, \
    .wpos = 0, \
    .wwrap = 0, \
    .rwrap = 0, \
    __VA_ARGS__ }

/// Init. function for queue structure instance
#define CQUEUE_INIT(Q, SIZE) do { \
    (Q)->size = (SIZE); \
    (Q)->rpos = (Q)->wpos = 0; \
    (Q)->wwrap = (Q)->rwrap = 0; \
} while (0)

/// Reset circular queue into initial state
#define CQUEUE_RESET(Q) CQUEUE_INIT(Q, (Q)->size)

/// General position incrementing
#define CQUEUE_INCR(Q, PPOS, PWRAP) do { \
    *(PPOS) = *(PPOS) +1; \
    if (*(PPOS) == (Q)->size) { \
        *(PWRAP) ^= 1; \
        *(PPOS) = 0; \
    } \
} while (0)

/// Reader position (for user-side)
#define CQUEUE_RPOS(Q) ((Q)->rpos)

/// Writer position (for user-side)
#define CQUEUE_WPOS(Q) ((Q)->wpos)

/// Reader position incrementing
#define CQUEUE_INCR_R(Q) do { \
    CQUEUE_INCR(Q, &((Q)->rpos), &((Q)->rwrap)); \
} while (0)

/// Writer position incrementing
#define CQUEUE_INCR_W(Q) do { \
    CQUEUE_INCR(Q, &((Q)->wpos), &((Q)->wwrap)); \
} while (0)

/// Test of circular queue fullness
#define CQUEUE_IS_FULL(Q) \
    ((Q)->wpos == (Q)->rpos && (Q)->rwrap != (Q)->wwrap)

/// Test of circular queue emptiness
#define CQUEUE_IS_EMPTY(Q) \
    ((Q)->wpos == (Q)->rpos && (Q)->rwrap == (Q)->wwrap)

/// Number of free slots in circular queue
#define CQUEUE_NFREE(Q) \
    ((Q)->rwrap == (Q)->wwrap ? \
     ((Q)->size - (Q)->wpos + (Q)->rpos) : \
     ((Q)->rpos - (Q)->wpos))

/// Number of used slots in circular queue
#define CQUEUE_LEN(Q) \
    ((Q)->rwrap != (Q)->wwrap ? \
     ((Q)->size - (Q)->rpos + (Q)->wpos) : \
     ((Q)->wpos - (Q)->rpos))

#endif
/// @}
USe doxygen to gen documentation of this module (it's only one .h-file).