Dynamic Type - [ int, char, bool, ... => dtype ]
Dynamic Type in C, A project that I had been thinking of for a while and made it.
How it works ?
Dtype currently is same as char
, when doing dtype var[size];
size
bytes are reserved for var as normal char
would do. The actual working of dtype is that it stores the type of variable in first 1 byte i.e var[0] = (char)type;
, and stores its size info in second & third bytes as unsigned short, i.e * ( unsigned short * ) (var + 1) = size;
after that any data to be stored is checked with the size, i.e * (unsigned short * ) (var + 1)
and if the size is equal or greater than the data to be stored, the data is then hard-copied from fourth byte onwards, i.e from ( var + 3)
and to get data, it simply checks the type and grabs the data, if type mismatch occurs, it produces a warning [ in runtime ].
Advantages over normal types
- Dynamic types enable you to store any kind of variable type in one variable
- has reusability, meaning an integer dynamic variable can be reused to store string!
- saving memory space, kind of - If you need let's say long integer, string with 10 bytes, integer, normally you would make different variables for each of them which causes more use of memory whereas you can just make a dtype of maximum size among all and use it to store anything of that byte size, no need to take more memory.
- custom types are also supported!
Runtme Speed test ( with -O2 flag
, on my device - results may vary on yours. ) :-
No. | Normal variables doing same thing | Dtype variables doing same thing |
---|---|---|
1 | ~20.945 ms on average [50+ tests] | ~21.025 ms on average [50+ tests] |
2 | ~19.881 ms on average [100+ tests] | ~19.997 ms on average [100+ tests] |
As seen above not much performance impact has been seen. And considering the advantages, It seems to be good
The code :-
/**
* @file dtype.h
*
* @brief Contains the definition for `dtype` along with `dtypes` & `dtypes.*` function signatures.
*/
#ifndef DTYPE_H_INCL
#define DTYPE_H_INCL
#include <stdbool.h>
/**
* @brief the actual dtype which stores the data
* @example dtype var[size_in_bytes];
*/
typedef char dtype;
/// @brief Current size_type for `dtype`
typedef unsigned short DTYPE_SIZE;
/// @brief Display warning if true
#ifndef DTYPE_WARN_OUT
#define DTYPE_WARN_OUT true
#endif
/// @brief Immediately display errors if true
#ifndef DTYPE_ERROR_OUT
#define DTYPE_ERROR_OUT true
#endif
/// @brief Exit on error if true
#ifndef DTYPE_EXIT_ON_ERR
#define DTYPE_EXIT_ON_ERR true
#endif
/**
* @enum DTYPES_ERR
* @brief ErrorCode enums for DTYPES_ERR
*/
enum DTYPES_ERR {
DTYPE_NO_ERR,
DTYPE_SIZE_LOW,
DTYPE_SIZE_HIGH,
DTYPE_MIN_MEM,
DTYPE_VALUE_ERR,
DTYPE_NOT_INIT,
DTYPE_UNKNOWN_ERR
};
/**
* @enum DTYPES_TYPES
* @brief Typecode for identifying current type of `dtype`.
* @brief DTYPE_TYPE for normal types,
* @brief DTYPE_UTYPE for unsigned types.
*/
enum DTYPES_TYPES {
DTYPE_INVALID, // Invalid type, not initialized!
DTYPE_NONE,
DTYPE_BOOL,
DTYPE_SHORT,
DTYPE_USHORT,
DTYPE_INT,
DTYPE_UINT,
DTYPE_LONG,
DTYPE_ULONG,
DTYPE_FLOAT,
DTYPE_DOUBLE,
DTYPE_CHAR,
DTYPE_STR,
DTYPE_OBJECT, // object type -> currently holds a custom type of variable.
DTYPE_UNKNOWN // unknown type!
};
/**
* @struct __dtypes_struct
* @typedef __dtypes_struct
*
* @brief a wrapper for all dtype functions.
*/
typedef struct __dtypes_struct {
/**
* @brief Initializes the variable.
* @param var The variable to initialize.
* @param size Size of the variable in bytes
*/
void (*init)(dtype* var, DTYPE_SIZE size);
/**
* @brief Prints the current error even if there is not an error.
* @returns The ErrorCode of current error
*/
enum DTYPES_ERR (*get_error)(void);
/**
* @brief Returns the usable size of variable..
* @param var The varible to get size of.
* @returns The usable size of given variable.
*/
DTYPE_SIZE (*get_size)(dtype* var);
/**
* @brief Returns the current `typecode` of the variable..
* @param var The variable to get `typecode` of.
* @returns The typecode of given variable.
*/
enum DTYPES_TYPES (*get_type)(dtype* var);
/**
* @brief Returns the current `type` of variable..
* @param var The variable to get type from.
* @returns The `type` of variable in readable string.
*/
const char* (*get_str_type)(dtype* var);
/**
* @brief Set the type of variable..
* @param var The variable to set the type..
* @param type the typecode to set.
*/
void (*set_type)(dtype* var, enum DTYPES_TYPES);
/**
* @brief Set the content of variable to none..
* @param var The variable to set to.
*/
void (*set_none)(dtype* var);
/**
* @brief Set the content of variable to given boolean value..
* @param var The variable to set to..
* @param value The value to set to.
*/
void (*set_bool)(dtype* var, bool value);
/**
* @brief Set the content of variable to given short value..
* @param var The variable to set to..
* @param value The value to set to.
*/
void (*set_short)(dtype* var, short value);
/**
* @brief Set the content of variable to given unsigned short value..
* @param var The variable to set to..
* @param value The value to set to.
*/
void (*set_ushort)(dtype* var, unsigned short value);
/**
* @brief Set the content of variable to given integer value..
* @param var The variable to set to..
* @param value The value to set to.
*/
void (*set_int)(dtype* var, int value);
/**
* @brief Set the content of variable to given unsigned integer value..
* @param var The variable to set to..
* @param value The value to set to.
*/
void (*set_uint)(dtype* var, unsigned int value);
/**
* @brief Set the content of variable to given long integer value..
* @param var The variable to set to..
* @param value The value to set to.
*/
void (*set_long)(dtype* var, long value);
/**
* @brief Set the content of variable to given unsigned long integer value..
* @param var The variable to set to..
* @param value The value to set to.
*/
void (*set_ulong)(dtype* var, unsigned long value);
/**
* @brief Set the content of variable to given float value..
* @param var The variable to set to..
* @param value The value to set to.
*/
void (*set_float)(dtype* var, float value);
/**
* @brief Set the content of variable to given double value..
* @param var The variable to set to..
* @param value The value to set to.
*/
void (*set_double)(dtype* var, double value);
/**
* @brief Set the content of variable to given character value..
* @param var The variable to set to..
* @param value The value to set to.
*/
void (*set_char)(dtype* var, char value);
/**
* @brief Set the content of variable to given string..
* @param var The variable to set to..
* @param value The value to set to.
*/
void (*set_str)(dtype* var, char * value);
/**
* @brief Copy the contents of the object into the variable..
* @param var The variable to copy to..
* @param obj The void pointer of object to copy from..
* @param size The size of the object.
*/
void (*set_object)(dtype* var, void * obj, DTYPE_SIZE size);
/**
* @brief Get the content of variable as boolean.
* @param var The variable to get from
*/
bool (*get_bool)(dtype* var);
/**
* @brief Get the content of variable as short.
* @param var The variable to get from
*/
short (*get_short)(dtype* var);
/**
* @brief Get the content of variable as unsigned short.
* @param var The variable to get from
*/
unsigned short (*get_ushort)(dtype* var);
/**
* @brief Get the content of variable as integer.
* @param var The variable to get from
*/
int (*get_int)(dtype* var);
/**
* @brief Get the content of variable as unsigned integer.
* @param var The variable to get from
*/
unsigned int (*get_uint)(dtype* var);
/**
* @brief Get the content of variable as long integer.
* @param var The variable to get from
*/
long (*get_long)(dtype* var);
/**
* @brief Get the content of variable as unsigned long integer.
* @param var The variable to get from
*/
unsigned long (*get_ulong)(dtype* var);
/**
* @brief Get the content of variable as float.
* @param var The variable to get from
*/
float (*get_float)(dtype* var);
/**
* @brief Get the content of variable as double.
* @param var The variable to get from
*/
double (*get_double)(dtype* var);
/**
* @brief Get the content of variable as character.
* @param var The variable to get from
*/
char (*get_char)(dtype* var);
/**
* @brief Get the content of variable as string (char *).
* @param var The variable to get from
*/
char * (*get_str)(dtype* var);
/**
* @brief Get the content of variable as object [ void pointer ].
* @param var The variable to get from
*/
void * (*get_object)(dtype* var);
/**
* @brief Get the direct pointer of variable as bool *
* @brief to directly set the value / use in functions like scanf().
* @brief Also sets the current type to bool.
* @param var The variable to get pointer from.
*/
bool* (*in_bool)(dtype* var);
/**
* @brief Get the direct pointer of variable as short *
* @brief to directly set the value / use in functions like scanf().
* @brief Also sets the current type to short.
* @param var The variable to get pointer from.
*/
short* (*in_short)(dtype* var);
/**
* @brief Get the direct pointer of variable as unsigned short *
* @brief to directly set the value / use in functions like scanf().
* @brief Also sets the current type to unsigned short.
* @param var The variable to get pointer from.
*/
unsigned short* (*in_ushort)(dtype* var);
/**
* @brief Get the direct pointer of variable as int *
* @brief to directly set the value / use in functions like scanf().
* @brief Also sets the current type to integer.
* @param var The variable to get pointer from.
*/
int* (*in_int)(dtype* var);
/**
* @brief Get the direct pointer of variable as unsigned int *
* @brief to directly set the value / use in functions like scanf().
* @brief Also sets the current type to unsigned int.
* @param var The variable to get pointer from.
*/
unsigned int* (*in_uint)(dtype* var);
/**
* @brief Get the direct pointer of variable as long *
* @brief to directly set the value / use in functions like scanf().
* @brief Also sets the current type to long.
* @param var The variable to get pointer from.
*/
long* (*in_long)(dtype* var);
/**
* @brief Get the direct pointer of variable as unsigned long *
* @brief to directly set the value / use in functions like scanf().
* @brief Also sets the current type to unsigned long.
* @param var The variable to get pointer from.
*/
unsigned long* (*in_ulong)(dtype* var);
/**
* @brief Get the direct pointer of variable as float *
* @brief to directly set the value / use in functions like scanf().
* @brief Also sets the current type to float.
* @param var The variable to get pointer from.
*/
float* (*in_float)(dtype* var);
/**
* @brief Get the direct pointer of variable as double *
* @brief to directly set the value / use in functions like scanf().
* @brief Also sets the current type to double.
* @param var The variable to get pointer from.
*/
double* (*in_double)(dtype* var);
/**
* @brief Get the direct pointer of variable as char *
* @brief to directly set the value / use in functions like scanf().
* @brief Also sets the current type to char.
* @param var The variable to get pointer from.
*/
char* (*in_char)(dtype* var);
/**
* @brief Get the direct pointer of variable as char *
* @brief to directly set the value / use in functions like scanf().
* @brief Also sets the current type to string.
* @param var The variable to get pointer from.
*/
char* (*in_str)(dtype* var);
enum DTYPES_TYPES (*print)(dtype* var);
} __dtypes_struct;
__dtypes_struct dtypes;
#endif
/**
* @file dtype.c
*
* @brief contains the actual code for definition in dtype.h
*/
#include "dtype.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/// @brief Current Errorcode
enum DTYPES_ERR DTYPE_CURRENT_ERRCODE = DTYPE_NO_ERR;
/// @brief The function in which current error occured.
const char* DTYPE_CURRENT_ERRFUNC = "none";
/// @brief Current Error description.
const char* DTYPE_CURRENT_ERRDESC = "none";
// function that prints current error and returns the errcode
enum DTYPES_ERR get_error ( void )
{
// print out error
printf ("\n---------- Dtype Error ----------\n");
printf ("in function %s, errcode: %d :\n\tinfo: %s\n",
DTYPE_CURRENT_ERRFUNC, DTYPE_CURRENT_ERRCODE, DTYPE_CURRENT_ERRDESC
);
// store the current errorcode to later return
enum DTYPES_ERR ErrCode = DTYPE_CURRENT_ERRCODE;
// set the current error to null as we have printed it!
DTYPE_CURRENT_ERRFUNC = "none";
DTYPE_CURRENT_ERRCODE = DTYPE_NO_ERR;
DTYPE_CURRENT_ERRDESC = "none";
// return the errcode
return ErrCode;
}
// function that sets error as given.
void set_error ( enum DTYPES_ERR errcode, const char* fname, const char* desc )
{
// set the error
DTYPE_CURRENT_ERRCODE = errcode;
DTYPE_CURRENT_ERRFUNC = fname;
DTYPE_CURRENT_ERRDESC = desc;
// print the error via get_error () if DTYPE_ERROR_OUT is true
if ( DTYPE_ERROR_OUT)
{
get_error ();
// exit if DTYPE_EXIT_ON_ERR is true!
if ( DTYPE_EXIT_ON_ERR ) {
exit (1);
}
}
}
// set_type of the variable as provided.
void set_type ( dtype * var, enum DTYPES_TYPES type )
{
var[0] = ( char ) type;
}
// set the size of the variable as provided
void set_size ( dtype * var, DTYPE_SIZE size )
{
*( (DTYPE_SIZE*) (var+1) ) = size;
}
// get_type of the variable
enum DTYPES_TYPES get_type ( dtype * var )
{
return var[0];
}
// get_type of the the variable but in a readable format, not in typecode.
const char* get_stype ( dtype * var )
{
// self-explanatory.
switch ( get_type ( var ) )
{
case DTYPE_NONE:
return "none ( null value )";
case DTYPE_BOOL:
return "bool";
case DTYPE_SHORT:
return "short";
case DTYPE_USHORT:
return "unsigned short";
case DTYPE_INT:
return "int";
case DTYPE_UINT:
return "unsigned int";
case DTYPE_LONG:
return "long";
case DTYPE_ULONG:
return "unsigned long";
case DTYPE_FLOAT:
return "float";
case DTYPE_DOUBLE:
return "double";
case DTYPE_CHAR:
return "char";
case DTYPE_STR:
return "string ( char *)";
case DTYPE_OBJECT:
return "object ( custom )";
case DTYPE_UNKNOWN:
return "unknown";
default:
return "invalid ( not initialized )";
}
}
// get usable size of the the variable
DTYPE_SIZE get_size ( dtype * var )
{
return *( (DTYPE_SIZE*) (var+1));
}
// initialization of the variable
// this basically sets the type to DTYPE_NONE and sets the size as provided
// also has a check that size must be greater than or equal to 4.
void dt_init ( dtype * var, DTYPE_SIZE size )
{
if ( size < 4) {
set_error (DTYPE_SIZE_LOW, "init", "Size too low, < 4");
}
// store the type
set_type ( var, DTYPE_NONE);
// store the size
set_size ( var, size-DTYPE_MIN_MEM);
}
// clear the data inside the variable
void dt_clear ( dtype * var ) {
// for old c support!
DTYPE_SIZE i;
for ( i = DTYPE_MIN_MEM; i < DTYPE_MIN_MEM + get_size(var); ++i )
{
var[i] = '\0';
}
}
// internal set_object function used for setting the variable's value
bool _dtset_obj ( dtype * var, void *obj, DTYPE_SIZE size )
{
// check for initialization
if ( get_type ( var ) == DTYPE_INVALID || get_type ( var ) > DTYPE_UNKNOWN) {
set_error (
DTYPE_NOT_INIT, "internal set_object()",
"trying to set to non-initialized variable!"
);
// indicating error
return true;
}
// clear previous value before storing
dt_clear ( var );
// if the size to store is greater than
if ( size > get_size ( var ) )
{
// not enough room to store!
// indicating error!
return true;
}
// for old c support
int i;
// hardcopy every byte till given size
for ( i = 0; i < size; ++i )
{
var[i+DTYPE_MIN_MEM] = ( ( char*) obj )[i];
}
// no error
return false;
}
void dtset_none ( dtype * var )
{
// clear the data
dt_clear ( var );
// set type to none
set_type ( var, DTYPE_NONE);
}
// set function for boolean value
void dtset_bool ( dtype * var, bool value )
{
bool val = value;
// use internal set_object function to set the dtype data to value
// if error is not indicated, set the type and return
if ( !_dtset_obj ( var, &val, sizeof ( bool ) ) ) {
set_type ( var, DTYPE_BOOL);
return;
}
// set the error
set_error (DTYPE_SIZE_HIGH, "set_bool", "the variable size is too low to store bool !");
return;
}
// set function for short value
void dtset_short ( dtype * var, short value )
{
short val = value;
// use internal set obj to set data to value
// if error is not indicated, set the type and return
if ( !_dtset_obj ( var, &val, sizeof ( short ) ) ) {
set_type ( var, DTYPE_SHORT);
return;
}
//set the error
set_error (DTYPE_SIZE_HIGH, "set_short", "the variable size is too low to store short !");
return;
}
// set function for unsigned short value
void dtset_ushort ( dtype * var, unsigned short value )
{
unsigned short val = value;
// use internal set_object function to set the dtype data to value
// if error is not indicated, set the type and return
if ( !_dtset_obj ( var, &val, sizeof ( unsigned short ) ) ) {
set_type ( var, DTYPE_USHORT);
return;
}
// set the error
set_error (DTYPE_SIZE_HIGH, "set_ushort", "the variable size is too low to store unsigned short !");
return;
}
// set function for int value
void dtset_int ( dtype * var, int value )
{
int val = value;
// use internal set_object function to set the dtype data to value
// if error is not indicated, set the type and return
if ( !_dtset_obj ( var, &val, sizeof ( int ) ) ) {
set_type ( var, DTYPE_INT);
return;
}
// set the error
set_error (DTYPE_SIZE_HIGH, "set_int", "the variable size is too low to store int !");
return;
}
// set function for unsigned int
void dtset_uint ( dtype * var, unsigned int value )
{
unsigned int val = value;
// use internal set_object function to set the dtype data to value
// if error is not indicated, set the type and return
if ( !_dtset_obj ( var, &val, sizeof ( unsigned int ) ) ) {
set_type ( var, DTYPE_UINT);
return;
}
// set the error
set_error (DTYPE_SIZE_HIGH, "set_uint", "the variable size is too low to store unsigned int !");
return;
}
// set function for long value
void dtset_long ( dtype * var, long value )
{
long val = value;
// use internal set_object function to set the dtype data to value
// if error is not indicated, set the type and return
if ( !_dtset_obj ( var, &val, sizeof ( long ) ) ) {
set_type ( var, DTYPE_LONG);
return;
}
// set the error
set_error (DTYPE_SIZE_HIGH, "set_long", "the variable size is too low to store long !");
return;
}
// set function for unsigned long
void dtset_ulong ( dtype * var, unsigned long value )
{
unsigned long val = value;
// use internal set_object function to set the dtype data to value
// if error is not indicated, set the type and return
if ( !_dtset_obj ( var, &val, sizeof ( unsigned long ) ) ) {
set_type ( var, DTYPE_ULONG);
return;
}
// set the error
set_error (DTYPE_SIZE_HIGH, "set_ulong", "the variable size is too low to store unsigned long !");
return;
}
// set function for float
void dtset_float ( dtype * var, float value )
{
float val = value;
// use internal set_object function to set the dtype data to value
// if error is not indicated, set the type and return
if ( !_dtset_obj ( var, &val, sizeof ( float ) ) ) {
set_type ( var, DTYPE_FLOAT);
return;
}
// set the error
set_error (DTYPE_SIZE_HIGH, "set_float", "the variable size is too low to store float !");
return;
}
// set function for double
void dtset_double ( dtype * var, double value )
{
double val = value;
// use internal set_object function to set the dtype data to value
// if error is not indicated, set the type and return
if ( !_dtset_obj ( var, &val, sizeof ( double ) ) ) {
set_type ( var, DTYPE_DOUBLE);
return;
}
// set the error
set_error (DTYPE_SIZE_HIGH, "set_double", "the variable size is too low to store double !");
return;
}
// set function for char
void dtset_char ( dtype * var, char value )
{
char val = value;
// use internal set_object function to set the dtype data to value
// if error is not indicated, set the type and return
if ( !_dtset_obj ( var, &val, sizeof ( char ) ) ) {
set_type ( var, DTYPE_CHAR);
return;
}
// set the error
set_error (DTYPE_SIZE_HIGH, "set_char", "the variable size is too low to store char !");
}
// set function for strings ( char *)
void dtset_str ( dtype * var, char* value )
{
// use internal set_object function to set the dtype data to value
// if error is not indicated, set the type and return
if ( !_dtset_obj ( var,value,strlen ( value ) +1) ) {
set_type ( var, DTYPE_STR);
return;
}
// set the error
set_error (DTYPE_SIZE_HIGH, "set_str", "the variable size is too low to store string !");
}
// set function for custom objects / custom type variables
void dtset_obj ( dtype * var, void* obj, DTYPE_SIZE size )
{
// use internal set_object function to set the dtype data to value
// if error is not indicated, set the type and return
if ( !_dtset_obj ( var,obj,size ) ) {
set_type ( var, DTYPE_OBJECT);
return;
}
// set the error
set_error (DTYPE_SIZE_HIGH, "set_obj", "the variable size is too low to store the object !");
}
// ------- dtget_type(dtype) : returns the value as type, printing warning if needed ------
// get function to get boolean value
bool dtget_bool ( dtype * var )
{
// type check, if failed and DTYPE_WARN_OUT is set,
// print the warning, that we are trying to get it from another type!
if ( get_type ( var )!=DTYPE_BOOL && DTYPE_WARN_OUT ) {
printf ("\n[ Dtype warn: getting `bool` from another type: `%s` ]\n",get_stype ( var ) );
}
// return the value as a boolean
return *( ( bool*) ( var + DTYPE_MIN_MEM) );
}
// get function to get short value
short dtget_short ( dtype * var )
{
// type check, if failed and DTYPE_WARN_OUT is set,
// print the warning, that we are trying to get it from another type!
if ( get_type ( var )!=DTYPE_SHORT && DTYPE_WARN_OUT ) {
printf ("\n[ Dtype warn: getting `short` from another type: `%s` ]\n",get_stype ( var ) );
}
// return the value as short
return *( ( short*) ( var + DTYPE_MIN_MEM) );
}
// get function to get unsigned short value
unsigned short dtget_ushort ( dtype * var )
{
// type check, if failed and DTYPE_WARN_OUT is set,
// print the warning, that we are trying to get it from another type!
if ( get_type ( var )!=DTYPE_USHORT && DTYPE_WARN_OUT ) {
printf ("\n[ Dtype warn: getting `unsigned short` from another type: `%s` ]\n",get_stype ( var ) );
}
// return the value as unsigned short
return *( ( unsigned short *) ( var + DTYPE_MIN_MEM) );
}
// get function to get int
int dtget_int ( dtype * var )
{
// type check, if failed and DTYPE_WARN_OUT is set,
// print the warning, that we are trying to get it from another type!
if ( get_type ( var )!=DTYPE_INT && DTYPE_WARN_OUT ) {
printf ("\n[ Dtype warn: getting `int` from another type: `%s` ]\n",get_stype ( var ) );
}
// return the value as int
return *( ( int*) ( var + DTYPE_MIN_MEM) );
}
// get function to get unsigned int
unsigned int dtget_uint ( dtype * var )
{
// type check, if failed and DTYPE_WARN_OUT is set,
// print the warning, that we are trying to get it from another type!
if ( get_type ( var )!=DTYPE_UINT && DTYPE_WARN_OUT ) {
printf ("\n[ Dtype warn: getting `unsigned int` from another type: `%s` ]\n",get_stype ( var ) );
}
// return the value as unsigned int
return *( ( unsigned int*) ( var + DTYPE_MIN_MEM) );
}
// get function to get long
long dtget_long ( dtype * var )
{
// type check, if failed and DTYPE_WARN_OUT is set,
// print the warning, that we are trying to get it from another type!
if ( get_type ( var )!=DTYPE_LONG && DTYPE_WARN_OUT ) {
printf ("\n[ Dtype warn: getting `long` from another type: `%s` ]\n", get_stype ( var ) );
}
// return the value as long
return *( ( long*) ( var + DTYPE_MIN_MEM) );
}
// get function to get unsigned long
unsigned long dtget_ulong ( dtype * var )
{
// type check, if failed and DTYPE_WARN_OUT is set,
// print the warning, that we are trying to get it from another type!
if ( get_type ( var )!=DTYPE_ULONG && DTYPE_WARN_OUT ) {
printf ("\n[ Dtype warn: getting `unsigned long` from another type: `%s` ]\n", get_stype ( var ) );
}
// return the value as unsigned long
return *( ( unsigned long*) ( var + DTYPE_MIN_MEM) );
}
// get function to get float
float dtget_float ( dtype * var )
{
// type check, if failed and DTYPE_WARN_OUT is set,
// print the warning, that we are trying to get it from another type!
if ( get_type ( var )!=DTYPE_FLOAT && DTYPE_WARN_OUT ) {
printf ("\n[ Dtype warn: getting `float` from another type: `%s` ]\n", get_stype ( var ) );
}
// return the value as float
return *( ( float*) ( var + DTYPE_MIN_MEM) );
}
// get function to get double
double dtget_double ( dtype * var )
{
// type check, if failed and DTYPE_WARN_OUT is set,
// print the warning, that we are trying to get it from another type!
if ( get_type ( var )!=DTYPE_DOUBLE && DTYPE_WARN_OUT ) {
printf ("\n[ Dtype warn: getting `double` from another type: `%s` ]\n", get_stype ( var ) );
}
// return the value as double
return *( ( double*) ( var + DTYPE_MIN_MEM) );
}
// get function to get char
char dtget_char ( dtype * var )
{
// type check, if failed and DTYPE_WARN_OUT is set,
// print the warning, that we are trying to get it from another type!
if ( get_type ( var )!=DTYPE_CHAR && DTYPE_WARN_OUT ) {
printf ("\n[ Dtype warn: getting `char` from another type: `%s` ]\n", get_stype ( var ) );
}
// return value as char
return *( ( var + DTYPE_MIN_MEM) );
}
// get function to get string ( char *)
char * dtget_str ( dtype * var )
{
// type check, if failed and DTYPE_WARN_OUT is set,
// print the warning, that we are trying to get it from another type!
if ( get_type ( var )!=DTYPE_STR && DTYPE_WARN_OUT ) {
printf ("\n[ Dtype warn: getting `string` from another type: `%s` ]\n", get_stype ( var ) );
}
// return value as string ( char *)
return ( ( var + DTYPE_MIN_MEM) );
}
// get function to get void pointer of custom object ( void *)
void* dtget_object ( dtype * var )
{
// type check, if failed and DTYPE_WARN_OUT is set,
// print the warning, that we are trying to get it from another type!
if ( get_type ( var )!=DTYPE_OBJECT && DTYPE_WARN_OUT ) {
printf (
"\n[ Dtype warn: getting `object ( custom )` from another type: `%s` ]\n",
get_stype ( var )
);
}
// return the value as void pointer that can be changed
// ( void *)
return ( void*) ( var + DTYPE_MIN_MEM);
}
//function to print the value & return it's type
enum DTYPES_TYPES dt_print ( dtype * var )
{
switch ( get_type ( var ) )
{
// switch cases according to the type
// print them as required as their types and return it's type!
case DTYPE_NONE:
printf ("None"); return DTYPE_NONE;
case DTYPE_BOOL:
printf ( dtget_bool ( var ) ? "true" : "false"); return DTYPE_BOOL;
case DTYPE_SHORT:
printf ("%i",dtget_short ( var ) ); return DTYPE_SHORT;
case DTYPE_USHORT:
printf ("%d",( int ) dtget_ushort ( var ) );
return DTYPE_USHORT;
case DTYPE_INT:
printf ("%d", dtget_int ( var ) ); return DTYPE_INT;
case DTYPE_UINT:
printf ("%u", dtget_uint ( var ) ); return DTYPE_UINT;
case DTYPE_LONG:
printf ("%ld", dtget_long ( var ) ); return DTYPE_LONG;
case DTYPE_ULONG:
printf ("%lu", dtget_ulong ( var ) ); return DTYPE_ULONG;
case DTYPE_FLOAT:
printf ("%f", dtget_float ( var ) ); return DTYPE_FLOAT;
case DTYPE_DOUBLE:
printf ("%lf", dtget_double ( var ) ); return DTYPE_DOUBLE;
case DTYPE_CHAR:
printf ("%c", dtget_char ( var ) ); return DTYPE_CHAR;
case DTYPE_STR:
printf ("%s", dtget_str ( var ) ); return DTYPE_STR;
case DTYPE_OBJECT:
printf ("( custom object at %p )", (void*) var); return DTYPE_OBJECT;
case DTYPE_UNKNOWN:
printf ("unknown value"); return DTYPE_UNKNOWN;
default:
printf ("Invalid ( not initialized )"); return DTYPE_INVALID;
}
}
// -- dtin_type(dtype*) : returns the pointer to the data as type* and sets current type to type --
bool * dtin_bool ( dtype * var )
{
// set the type & send the pointer as ( bool * )
set_type ( var, DTYPE_BOOL);
return ( bool *) ( var + DTYPE_MIN_MEM);
}
short * dtin_short ( dtype * var )
{
// set the type & send the pointer as ( short * )
set_type ( var, DTYPE_SHORT);
return ( short *) ( var + DTYPE_MIN_MEM);
}
unsigned short * dtin_ushort ( dtype * var )
{
// set the type & send the pointer as ( unsigned short * )
set_type ( var, DTYPE_USHORT);
return ( unsigned short *) ( var + DTYPE_MIN_MEM);
}
int * dtin_int ( dtype * var )
{
// set the type & send the pointer as ( int * )
set_type ( var, DTYPE_INT);
return ( int*) ( var + DTYPE_MIN_MEM);
}
unsigned int * dtin_uint ( dtype * var )
{
// set the type & send the pointer as ( unsigned int * )
set_type ( var, DTYPE_UINT);
return ( unsigned int *) ( var + DTYPE_MIN_MEM);
}
long * dtin_long ( dtype * var )
{
// set the type & send the pointer as ( long * )
set_type ( var, DTYPE_LONG);
return ( long *) ( var + DTYPE_MIN_MEM);
}
unsigned long * dtin_ulong ( dtype * var )
{
// set the type & send the pointer as ( unsigned long * )
set_type ( var, DTYPE_ULONG);
return ( unsigned long *) ( var + DTYPE_MIN_MEM);
}
float * dtin_float ( dtype * var )
{
// set the type & send the pointer as ( float * )
set_type ( var, DTYPE_FLOAT);
return ( float *) ( var + DTYPE_MIN_MEM);
}
double * dtin_double ( dtype * var )
{
// set the type & send the pointer as ( double * )
set_type ( var, DTYPE_DOUBLE);
return ( double *) ( var + DTYPE_MIN_MEM);
}
char * dtin_char ( dtype * var )
{
// set the type & send the pointer as ( char * )
set_type ( var, DTYPE_CHAR);
return ( char *) ( var + DTYPE_MIN_MEM);
}
char * dtin_str ( dtype * var )
{
// set the type & send the pointer as ( char * )
set_type ( var, DTYPE_STR);
return ( char *) ( var + DTYPE_MIN_MEM);
}
// pack everything into dtypes
__dtypes_struct dtypes = {
// basic functions
dt_init, get_error, get_size, get_type, get_stype, set_type,
// set functions
dtset_none, dtset_bool, dtset_short, dtset_ushort, dtset_int, dtset_uint, dtset_long, dtset_ulong,
dtset_float, dtset_double, dtset_char, dtset_str, dtset_obj,
// get functions
dtget_bool, dtget_short, dtget_ushort, dtget_int, dtget_uint, dtget_long, dtget_ulong, dtget_float,
dtget_double, dtget_char, dtget_str, dtget_object,
// in functions
dtin_bool, dtin_short, dtin_ushort, dtin_int, dtin_uint, dtin_long, dtin_ulong, dtin_float,
dtin_double, dtin_char, dtin_str,
// printing function
dt_print
};
Basic usage example :-
#include "dtype.h"
#include <stdio.h>
int main(void)
{
/*
Note :- printf("%d", dtypes.print(var)) kind of printing causes the variable to
be printed first, and then display the typecode of variable.
*/
// dtype var of 20 bytes
dtype var[20];
// initialize it with 20 bytes! [ it won't use more than size_of_bytes given in init ]
dtypes.init(var, 20);
// Example's of setting value!
// set_str set's the data of var to the string provided
dtypes.set_str(var, "Hello World!\n");
// dtypes.print() prints the content, and returns the typecode of that var!
// get_str_type returns the type in readable format than typecode
printf("Typecode: %d, Type: %s\n\n", dtypes.print(var), dtypes.get_str_type(var));
// store a boolean & print value
// set_bool set's data of the var to the boolean provided
dtypes.set_bool(var, 1);
printf("Value in boolean 1 : ");
dtypes.print(var); // true
printf("\n");
dtypes.set_bool(var, 0); // false
printf("Value in boolean 0 : ");
printf("\nTypecode: %d, Type: %s\n\n", dtypes.print(var), dtypes.get_str_type(var));
// store an int & print value
// set_int set's the data of var to the int provided
dtypes.set_int(var, -9856);
printf("\nTypecode: %d, Type: %s\n\n", dtypes.print(var), dtypes.get_str_type(var));
// set_uint set's the data of var to unsigned int provided
// let's try setting it to negative to see if it unsigned or not
dtypes.set_uint(var, -9856);
printf("\nTypecode: %d, Type: %s\n\n", dtypes.print(var), dtypes.get_str_type(var));
// copying from dtypes to other types!
unsigned int copied = dtypes.get_uint(var);
printf("copied from dtypes.get_uint value: %u\n", copied);
// copying from dtypes type mismatch, causes a warning to appear :) but copies it anyway
// type mismatch here is that we are trying to get integer value but stored value is of type unsigned int
int trytocopy = dtypes.get_int(var);
printf("tried to copy int from unsigned int stored in var, warning should be above ^^ ");
printf("\ntrytocopy value: %d!\n\n", trytocopy);
// to clear the variable
dtypes.set_none(var);
printf("After setting it to none, value: ");
printf("\nTypecode: %d, Type: %s\n\n", dtypes.print(var), dtypes.get_str_type(var));
return 0;
}
Basic usage example : with scanf()
#include <stdio.h>
#include "dtype.h"
void scan_err(int scanf_output, dtype * var)
{
if(!scanf_output) {
printf("\n--- Invalid input or EOF ---\n");
// clear variable if input error
dtypes.set_none(var);
}
}
int main()
{
// dtype var of 20 bytes
dtype var[20];
// initialization
dtypes.init(var, 20);
printf("Enter integer: ");
// in_int returns an integer pointer to store/access value directly
scan_err(scanf("%d", dtypes.in_int(var)), var);
printf("Value: ");
printf("\nTypecode: %d, Type: %s\n\n", dtypes.print(var), dtypes.get_str_type(var));
printf("Enter string: ");
scan_err(scanf("%s", dtypes.in_str(var)), var);
printf("Value: ");
printf("\nTypecode: %d, Type: %s\n\n", dtypes.print(var), dtypes.get_str_type(var));
printf("Enter unsigned long value: ");
scan_err(scanf("%lu", dtypes.in_ulong(var)), var);
printf("Value: ");
printf("\nTypecode: %d, Type: %s\n\n", dtypes.print(var), dtypes.get_str_type(var));
return 0;
}
I will be more than happy to receive suggestions, feedback, bugs and overall code review for this project.
std::variant
was added to C++), but hardly new. \$\endgroup\$dtype
requires you to use function calls to access the variables. \$\endgroup\$