Move everything out of src folder
This commit is contained in:
1 parent
2c1eb41280
commit
47ece66520
135 files changed
+13
-7
No files matched your search
+2638
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* utl_foreach.h
|
||||
*
|
||||
* Creation Date: 25/02/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* For-Each macros that work with all Collections within the library.
|
||||
*
|
||||
* PFX - Functions prefix
|
||||
* SNAME - Struct name
|
||||
* ITERNAME - Iterator variable name
|
||||
* TARGET - Target data structure variable name
|
||||
*/
|
||||
|
||||
#ifndef CMC_UTL_FOREACH_H
|
||||
#define CMC_UTL_FOREACH_H
|
||||
|
||||
#include "../cor/core.h"
|
||||
|
||||
#define CMC_FOREACH(PFX, SNAME, ITERNAME, TARGET) \
|
||||
for (struct CMC_DEF_ITER(SNAME) ITERNAME = CMC_(PFX, _iter_start)(TARGET); !CMC_(PFX, _iter_at_end)(&ITERNAME); \
|
||||
CMC_(PFX, _iter_next)(&ITERNAME))
|
||||
|
||||
#define CMC_FOREACH_REV(PFX, SNAME, ITERNAME, TARGET) \
|
||||
for (struct CMC_DEF_ITER(SNAME) ITERNAME = CMC_(PFX, _iter_end)(TARGET); !CMC_(PFX, _iter_at_start)(&ITERNAME); \
|
||||
CMC_(PFX, _iter_prev)(&ITERNAME))
|
||||
|
||||
#endif /* CMC_UTL_FOREACH_H */
|
||||
@@ -0,0 +1,516 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* utl_futils.h
|
||||
*
|
||||
* Creation Date: 15/04/2020
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Common functions that can be used by Functions Table, instead of writing
|
||||
* another one every time.
|
||||
*/
|
||||
|
||||
#ifndef CMC_UTL_FUTILS_H
|
||||
#define CMC_UTL_FUTILS_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* cmp
|
||||
*/
|
||||
|
||||
// Signed Integers
|
||||
|
||||
static inline int cmc_i64_cmp(int64_t x1, int64_t x2)
|
||||
{
|
||||
return (x1 > x2) - (x1 < x2);
|
||||
}
|
||||
|
||||
static inline int cmc_i32_cmp(int32_t x1, int32_t x2)
|
||||
{
|
||||
return cmc_i64_cmp((int64_t)x1, (int64_t)x2);
|
||||
}
|
||||
|
||||
static inline int cmc_i16_cmp(int16_t x1, int16_t x2)
|
||||
{
|
||||
return cmc_i64_cmp((int64_t)x1, (int64_t)x2);
|
||||
}
|
||||
|
||||
static inline int cmc_i8_cmp(int8_t x1, int8_t x2)
|
||||
{
|
||||
return cmc_i64_cmp((int64_t)x1, (int64_t)x2);
|
||||
}
|
||||
|
||||
// Unsigned Integers
|
||||
|
||||
static inline int cmc_u64_cmp(uint64_t x1, uint64_t x2)
|
||||
{
|
||||
return (x1 > x2) - (x1 < x2);
|
||||
}
|
||||
|
||||
static inline int cmc_u32_cmp(uint32_t x1, uint32_t x2)
|
||||
{
|
||||
return cmc_u64_cmp((uint64_t)x1, (uint64_t)x2);
|
||||
}
|
||||
|
||||
static inline int cmc_u16_cmp(uint16_t x1, uint16_t x2)
|
||||
{
|
||||
return cmc_u64_cmp((uint64_t)x1, (uint64_t)x2);
|
||||
}
|
||||
|
||||
static inline int cmc_u8_cmp(uint8_t x1, uint8_t x2)
|
||||
{
|
||||
return cmc_u64_cmp((uint64_t)x1, (uint64_t)x2);
|
||||
}
|
||||
|
||||
// Other Integers
|
||||
|
||||
static inline int cmc_size_cmp(size_t x1, size_t x2)
|
||||
{
|
||||
return (x1 > x2) - (x1 < x2);
|
||||
}
|
||||
|
||||
static inline int cmc_imax_cmp(intmax_t x1, intmax_t x2)
|
||||
{
|
||||
return (x1 > x2) - (x1 < x2);
|
||||
}
|
||||
|
||||
static inline int cmc_umax_cmp(uintmax_t x1, uintmax_t x2)
|
||||
{
|
||||
return (x1 > x2) - (x1 < x2);
|
||||
}
|
||||
|
||||
// Floating Point
|
||||
|
||||
static inline int cmc_float_cmp(float x1, float x2)
|
||||
{
|
||||
return (x1 > x2) - (x1 < x2);
|
||||
}
|
||||
|
||||
static inline int cmc_double_cmp(double x1, double x2)
|
||||
{
|
||||
return (x1 > x2) - (x1 < x2);
|
||||
}
|
||||
|
||||
static inline int cmc_double_long_cmp(long double x1, long double x2)
|
||||
{
|
||||
return (x1 > x2) - (x1 < x2);
|
||||
}
|
||||
|
||||
// String
|
||||
|
||||
static inline int cmc_chr_cmp(char ch1, char ch2)
|
||||
{
|
||||
return (ch1 > ch2) - (ch1 < ch2);
|
||||
}
|
||||
|
||||
static inline int cmc_str_cmp(char *ch1, char *ch2)
|
||||
{
|
||||
// Assuming ch1 and ch2 are both null terminated character sequences
|
||||
return strcmp(ch1, ch2);
|
||||
}
|
||||
|
||||
/**
|
||||
* cpy
|
||||
*/
|
||||
|
||||
/* For basic data types a simple assignment is usually enough */
|
||||
|
||||
static inline char *cmc_str_cpy(char *str)
|
||||
{
|
||||
size_t len = strlen(str) + 1;
|
||||
|
||||
char *result = malloc(len);
|
||||
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
return memcpy(result, str, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* str
|
||||
*/
|
||||
|
||||
// Signed Integers
|
||||
|
||||
static inline bool cmc_i8_str(FILE *file, int8_t element)
|
||||
{
|
||||
return fprintf(file, "%" PRIi8 "", element) > 0;
|
||||
}
|
||||
|
||||
static inline bool cmc_i16_str(FILE *file, int16_t element)
|
||||
{
|
||||
return fprintf(file, "%" PRIi16 "", element) > 0;
|
||||
}
|
||||
|
||||
static inline bool cmc_i32_str(FILE *file, int32_t element)
|
||||
{
|
||||
return fprintf(file, "%" PRIi32 "", element) > 0;
|
||||
}
|
||||
|
||||
static inline bool cmc_i64_str(FILE *file, int64_t element)
|
||||
{
|
||||
return fprintf(file, "%" PRIi64 "", element) > 0;
|
||||
}
|
||||
|
||||
// Unsigned Integers
|
||||
|
||||
static inline bool cmc_u8_str(FILE *file, uint8_t element)
|
||||
{
|
||||
return fprintf(file, "%" PRIu8 "", element) > 0;
|
||||
}
|
||||
|
||||
static inline bool cmc_u16_str(FILE *file, uint16_t element)
|
||||
{
|
||||
return fprintf(file, "%" PRIu16 "", element) > 0;
|
||||
}
|
||||
|
||||
static inline bool cmc_u32_str(FILE *file, uint32_t element)
|
||||
{
|
||||
return fprintf(file, "%" PRIu32 "", element) > 0;
|
||||
}
|
||||
|
||||
static inline bool cmc_u64_str(FILE *file, uint64_t element)
|
||||
{
|
||||
return fprintf(file, "%" PRIu64 "", element) > 0;
|
||||
}
|
||||
|
||||
// Other Integers
|
||||
|
||||
static inline bool cmc_size_str(FILE *file, size_t element)
|
||||
{
|
||||
return fprintf(file, "%" PRIuMAX "", (uintmax_t)element) > 0;
|
||||
}
|
||||
|
||||
static inline bool cmc_imax_str(FILE *file, intmax_t element)
|
||||
{
|
||||
return fprintf(file, "%" PRIiMAX "", element) > 0;
|
||||
}
|
||||
|
||||
static inline bool cmc_umax_str(FILE *file, uintmax_t element)
|
||||
{
|
||||
return fprintf(file, "%" PRIu64 "", element) > 0;
|
||||
}
|
||||
|
||||
// Floating Point
|
||||
|
||||
static inline bool cmc_float_str(FILE *file, float element)
|
||||
{
|
||||
return fprintf(file, "%f", element) > 0;
|
||||
}
|
||||
|
||||
static inline bool cmc_double_str(FILE *file, double element)
|
||||
{
|
||||
return fprintf(file, "%lf", element) > 0;
|
||||
}
|
||||
|
||||
static inline int cmc_double_long_str(FILE *file, long double element)
|
||||
{
|
||||
return fprintf(file, "%LF", element);
|
||||
}
|
||||
|
||||
// String
|
||||
|
||||
static inline bool cmc_chr_chr(FILE *file, char element)
|
||||
{
|
||||
return fprintf(file, "%c", element) > 0;
|
||||
}
|
||||
|
||||
static inline bool cmc_str_str(FILE *file, char *element)
|
||||
{
|
||||
return fprintf(file, "\"%s\"", element) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* free
|
||||
*/
|
||||
|
||||
/* For most data types a simple free() is enough */
|
||||
|
||||
/**
|
||||
* hash
|
||||
*/
|
||||
|
||||
// These integer hashing functions are based on splitmix64
|
||||
// http://web.archive.org/web/20190929030557/http://xorshift.di.unimi.it/splitmix64.c
|
||||
|
||||
// Integers
|
||||
|
||||
static inline size_t cmc_i64_hash(int64_t e)
|
||||
{
|
||||
size_t x = (size_t)e;
|
||||
|
||||
x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
|
||||
x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
|
||||
x = x ^ (x >> 31);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline size_t cmc_i32_hash(int32_t e)
|
||||
{
|
||||
return cmc_i64_hash((int64_t)e);
|
||||
}
|
||||
|
||||
static inline size_t cmc_i16_hash(int16_t e)
|
||||
{
|
||||
return cmc_i64_hash((int64_t)e);
|
||||
}
|
||||
|
||||
static inline size_t cmc_i8_hash(int8_t e)
|
||||
{
|
||||
return cmc_i64_hash((int64_t)e);
|
||||
}
|
||||
|
||||
// Unsigned Integers
|
||||
|
||||
static inline size_t cmc_u64_hash(uint64_t e)
|
||||
{
|
||||
size_t x = (size_t)e;
|
||||
|
||||
x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
|
||||
x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
|
||||
x = x ^ (x >> 31);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline size_t cmc_u32_hash(uint32_t e)
|
||||
{
|
||||
return cmc_u64_hash((uint64_t)e);
|
||||
}
|
||||
|
||||
static inline size_t cmc_u16_hash(uint16_t e)
|
||||
{
|
||||
return cmc_u64_hash((uint64_t)e);
|
||||
}
|
||||
|
||||
static inline size_t cmc_u8_hash(uint8_t e)
|
||||
{
|
||||
return cmc_u64_hash((uint64_t)e);
|
||||
}
|
||||
|
||||
// Other Integers
|
||||
|
||||
static inline size_t cmc_size_hash(size_t e)
|
||||
{
|
||||
size_t x = (size_t)e;
|
||||
|
||||
x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
|
||||
x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
|
||||
x = x ^ (x >> 31);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline size_t cmc_imax_hash(intmax_t e)
|
||||
{
|
||||
size_t x = (size_t)e;
|
||||
|
||||
x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
|
||||
x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
|
||||
x = x ^ (x >> 31);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline size_t cmc_umax_hash(uintmax_t e)
|
||||
{
|
||||
size_t x = (size_t)e;
|
||||
|
||||
x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
|
||||
x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
|
||||
x = x ^ (x >> 31);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// Floating Point
|
||||
|
||||
static inline size_t cmc_float_hash(float e)
|
||||
{
|
||||
// Make both representations of 0.0 hash to the same value
|
||||
// 0.0 and -0.0
|
||||
// Since -0.0 has a different binary representation than 0.0
|
||||
// And 0.0 == -0.0 is always true
|
||||
if (e == 0.0)
|
||||
e = 0.0; // if e == -0.0, now it is 0.0
|
||||
|
||||
union
|
||||
{
|
||||
float a;
|
||||
size_t b;
|
||||
} x;
|
||||
|
||||
x.a = e;
|
||||
|
||||
return x.b & 0xFFFFFFF8;
|
||||
}
|
||||
|
||||
static inline size_t cmc_double_hash(double e)
|
||||
{
|
||||
// Make both representations of 0.0 hash to the same value
|
||||
// 0.0 and -0.0
|
||||
// Since -0.0 has a different binary representation than 0.0
|
||||
// And 0.0 == -0.0 is always true
|
||||
if (e == 0.0)
|
||||
e = 0.0; // if e == -0.0, now it is 0.0
|
||||
|
||||
union
|
||||
{
|
||||
double a;
|
||||
size_t b;
|
||||
} x;
|
||||
|
||||
x.a = e;
|
||||
|
||||
return x.b & 0xFFFFFFFFFFFFFFF0;
|
||||
}
|
||||
|
||||
// String
|
||||
|
||||
static inline size_t cmc_chr_hash(char e)
|
||||
{
|
||||
return cmc_u8_hash((uint8_t)e);
|
||||
}
|
||||
|
||||
// Both djb2 and java are based on a Linear Congruential Generator
|
||||
// https://en.wikipedia.org/wiki/Linear_congruential_generator
|
||||
|
||||
// http://www.cse.yorku.ca/~oz/hash.html
|
||||
static inline size_t cmc_str_hash_djb2(char *str)
|
||||
{
|
||||
size_t hash = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = *str++))
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
// http://www.cse.yorku.ca/~oz/hash.html
|
||||
static inline size_t cmc_str_hash_sdbm(char *str)
|
||||
{
|
||||
size_t hash = 0;
|
||||
int c;
|
||||
|
||||
while ((c = *str++))
|
||||
hash = c + (hash << 6) + (hash << 16) - hash;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
// Based on Java's String.hashCode()
|
||||
static inline size_t cmc_str_hash_java(char *str)
|
||||
{
|
||||
size_t hash = UINT64_C(1125899906842597); // prime
|
||||
int c;
|
||||
|
||||
while ((c = *str++))
|
||||
hash = 31 * hash + c;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/MurmurHash
|
||||
// https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash3.cpp#L81
|
||||
static inline size_t cmc_str_hash_murmur3(uint64_t e)
|
||||
{
|
||||
size_t x = (size_t)e;
|
||||
|
||||
x ^= (x >> 33);
|
||||
x *= 0xff51afd7ed558ccd;
|
||||
x ^= (x >> 33);
|
||||
x *= 0xc4ceb9fe1a85ec53;
|
||||
x ^= (x >> 33);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// A variant or murmurhash3 from
|
||||
// http://web.archive.org/web/20200310023308/http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
|
||||
static inline size_t cmc_str_hash_murmur3_variant(uint64_t e)
|
||||
{
|
||||
size_t x = (size_t)e;
|
||||
|
||||
x ^= (x >> 31);
|
||||
x *= 0x7fb5d329728ea185;
|
||||
x ^= (x >> 27);
|
||||
x *= 0x81dadef4bc2dd44d;
|
||||
x ^= (x >> 33);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// Others
|
||||
|
||||
// These two originally come from
|
||||
// http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
|
||||
static inline size_t cmc_i64_hash_mix(int64_t element)
|
||||
{
|
||||
size_t e = (size_t)element;
|
||||
|
||||
e = (~e) + (e << 21);
|
||||
e = e ^ (e >> 24);
|
||||
e = (e + (e << 3)) + (e << 8);
|
||||
e = e ^ (e >> 14);
|
||||
e = (e + (e << 2)) + (e << 4);
|
||||
e = e ^ (e >> 28);
|
||||
e = e + (e << 31);
|
||||
return e;
|
||||
}
|
||||
|
||||
static inline size_t cmc_u64_hash_mix(uint64_t element)
|
||||
{
|
||||
size_t e = (size_t)element;
|
||||
|
||||
e = (~e) + (e << 21);
|
||||
e = e ^ (e >> 24);
|
||||
e = (e + (e << 3)) + (e << 8);
|
||||
e = e ^ (e >> 14);
|
||||
e = (e + (e << 2)) + (e << 4);
|
||||
e = e ^ (e >> 28);
|
||||
e = e + (e << 31);
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* pri
|
||||
*/
|
||||
|
||||
/* Can simply use cmp for basic data types */
|
||||
|
||||
#endif /* CMC_UTL_FUTILS_H */
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* utl_log.h
|
||||
*
|
||||
* Creation Date: 21/06/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simple logging macros
|
||||
* You can toggle colors defining the macro CMC_LOG_COLOR but be sure that
|
||||
* your terminal supports ANSI color escape codes.
|
||||
*
|
||||
* You can customize the logging utility by accessing cmc_log_config and
|
||||
* directly modifying its values to better suit your needs.
|
||||
*/
|
||||
|
||||
/**
|
||||
* What each error code means inside the DEV Collections
|
||||
*
|
||||
* TRACE - Trace is used to describe the inner workings of the function or an
|
||||
* algorithm. It can be useful when trying to find for an error in the
|
||||
* algorithm or corner cases.
|
||||
* DEBUG - Mainly used for debugging, tracking certain variables or anything
|
||||
* useful to help visualizing what your program is doing.
|
||||
* INFO - Info can be used as a heads up. It is also used to track the main
|
||||
* collection's allocation and deallocation.
|
||||
* WARN - Warnings are attributed to all cases where the function can recover
|
||||
* from and they are usually treated by it. In most cases the user can
|
||||
* treat these warnings himself.
|
||||
* ERROR - Something really bad happened. Your program will not crash yet but
|
||||
* depending on what comes next, it will.
|
||||
* FATAL - This will probably be the last logging message before your program
|
||||
* crashes or goes into madness. Fatal errors are commonly attributed
|
||||
* to dereferencing NULL pointers.
|
||||
*
|
||||
* Log Level
|
||||
*
|
||||
* TRACE - 1
|
||||
* DEBUG - 2
|
||||
* INFO - 3
|
||||
* WARN - 4
|
||||
* ERROR - 5
|
||||
* FATAL - 6
|
||||
*
|
||||
* How the Log Level is calculated for tlevel and flevel
|
||||
*
|
||||
* - If the log level is 0 all logs are enabled.
|
||||
* - If the log level (X) is positive:
|
||||
* - All levels less than X will be disabled
|
||||
* - If X is greater than the level of FATAL, all logs are disabled
|
||||
* - If the log level (X) is negative:
|
||||
* - All levels greater than X are enabled
|
||||
* - If X is less than the level of FATAL, all logs are enabled
|
||||
*/
|
||||
|
||||
#ifndef CMC_UTL_LOG_H
|
||||
#define CMC_UTL_LOG_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../cor/core.h"
|
||||
|
||||
static const char *cmc_log_names[] = { "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" };
|
||||
|
||||
#ifdef CMC_LOG_COLOR
|
||||
static const char *cmc_log_color[] = { "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" };
|
||||
#endif
|
||||
|
||||
enum cmc_log_type
|
||||
{
|
||||
CMC_LOG_TRACE = 1,
|
||||
CMC_LOG_DEBUG = 2,
|
||||
CMC_LOG_INFO = 3,
|
||||
CMC_LOG_WARN = 4,
|
||||
CMC_LOG_ERROR = 5,
|
||||
CMC_LOG_FATAL = 6
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
int tlevel; /* Terminal Level */
|
||||
int flevel; /* File Level */
|
||||
bool tenabled; /* Terminal Output Enabled */
|
||||
bool fenabled; /* File Output Enabled */
|
||||
bool enabled; /* Logging enabled */
|
||||
FILE *file; /* File for Output */
|
||||
|
||||
} cmc_log_config = { 0, 0, true, true, true, NULL };
|
||||
|
||||
#define cmc_log_trace(fmt, ...) cmc_log(CMC_LOG_TRACE, __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
#define cmc_log_debug(fmt, ...) cmc_log(CMC_LOG_DEBUG, __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
#define cmc_log_info(fmt, ...) cmc_log(CMC_LOG_INFO, __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
#define cmc_log_warn(fmt, ...) cmc_log(CMC_LOG_WARN, __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
#define cmc_log_error(fmt, ...) cmc_log(CMC_LOG_ERROR, __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
#define cmc_log_fatal(fmt, ...) cmc_log(CMC_LOG_FATAL, __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
|
||||
CMC_UNUSED static void cmc_log(enum cmc_log_type log, const char *filename, const char *funcname, unsigned line,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
if (!cmc_log_config.enabled)
|
||||
return;
|
||||
|
||||
if (cmc_log_config.tenabled)
|
||||
{
|
||||
int tl = cmc_log_config.tlevel;
|
||||
|
||||
if (tl > 0 && (int)log < tl)
|
||||
goto skip;
|
||||
if (tl < 0 && ((int)log * -1) < tl)
|
||||
goto skip;
|
||||
|
||||
int i = (int)log - 1;
|
||||
|
||||
time_t t = time(NULL);
|
||||
struct tm *lt = localtime(&t);
|
||||
|
||||
char time[32];
|
||||
time[strftime(time, sizeof(time), "%Y-%m-%d %H:%M:%S", lt)] = '\0';
|
||||
|
||||
#ifdef CMC_LOG_COLOR
|
||||
fprintf(stderr, "%s %s%5s\x1b[0m at\x1b[90m %s:%s:%u\x1b[0m | ", time, cmc_log_color[i], cmc_log_names[i],
|
||||
filename, funcname, line);
|
||||
#else
|
||||
fprintf(stderr, "%s %5s at %s:%s:%u | ", time, cmc_log_names[i], filename, funcname, line);
|
||||
#endif
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
skip:
|
||||
|
||||
if (cmc_log_config.file && cmc_log_config.fenabled)
|
||||
{
|
||||
int fl = cmc_log_config.flevel;
|
||||
|
||||
if (fl > 0 && (int)log < fl)
|
||||
return;
|
||||
if (fl < 0 && ((int)log * -1) < fl)
|
||||
return;
|
||||
|
||||
int i = (int)log - 1;
|
||||
|
||||
time_t t = time(NULL);
|
||||
struct tm *lt = localtime(&t);
|
||||
|
||||
char time[32];
|
||||
time[strftime(time, sizeof(time), "%Y-%m-%d %H:%M:%S", lt)] = '\0';
|
||||
|
||||
fprintf(cmc_log_config.file, "%s %5s at %s:%s:%u | ", time, cmc_log_names[i], filename, funcname, line);
|
||||
|
||||
va_list file_args;
|
||||
va_start(file_args, fmt);
|
||||
vfprintf(cmc_log_config.file, fmt, file_args);
|
||||
va_end(file_args);
|
||||
|
||||
fprintf(cmc_log_config.file, "\n");
|
||||
fflush(cmc_log_config.file);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CMC_UTL_LOG_H */
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* utl_mutex.h
|
||||
*
|
||||
* Creation Date: 14/05/2020
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* A very simple, header-only and minimalistic cross-platform mutex
|
||||
*
|
||||
* Types
|
||||
* - cmc_mutex
|
||||
*
|
||||
* Functions
|
||||
* - cmc_mtx_init
|
||||
* - cmc_mtx_destroy
|
||||
* - cmc_mtx_lock
|
||||
* - cmc_mtx_unlock
|
||||
* - cmc_mtx_trylock
|
||||
*/
|
||||
|
||||
#ifndef CMC_UTL_MUTEX_H
|
||||
#define CMC_UTL_MUTEX_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "../cor/flags.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define CMC_MUTEX_WINDOWS
|
||||
#elif defined(__unix__)
|
||||
#define CMC_MUTEX_UNIX
|
||||
#else
|
||||
#error "Unknown platform for CMC Mutex"
|
||||
#endif
|
||||
|
||||
/* Platform specific includes */
|
||||
#if defined(CMC_MUTEX_WINDOWS)
|
||||
#include <windows.h>
|
||||
#elif defined(CMC_MUTEX_UNIX)
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* struct cmc_mutex
|
||||
*
|
||||
* A mutex wrapper.
|
||||
*/
|
||||
struct cmc_mutex
|
||||
{
|
||||
#if defined(CMC_MUTEX_WINDOWS)
|
||||
HANDLE mutex;
|
||||
#elif defined(CMC_MUTEX_UNIX)
|
||||
pthread_mutex_t mutex;
|
||||
#endif
|
||||
int flag;
|
||||
};
|
||||
|
||||
/**
|
||||
* Acquire resources for a mutex.
|
||||
*
|
||||
* \param mtx An uninitialized mutex wrapper.
|
||||
* \return True or false if the mutex was successfully initialized.
|
||||
*/
|
||||
static inline bool cmc_mtx_init(struct cmc_mutex *mtx)
|
||||
{
|
||||
#if defined(CMC_MUTEX_WINDOWS)
|
||||
mtx->mutex = CreateMutex(NULL, FALSE, NULL);
|
||||
|
||||
if (mtx->mutex == NULL)
|
||||
mtx->flag = CMC_FLAG_MUTEX;
|
||||
else
|
||||
mtx->flag = CMC_FLAG_OK;
|
||||
|
||||
return mtx->mutex != NULL;
|
||||
|
||||
#elif defined(CMC_MUTEX_UNIX)
|
||||
int err = pthread_mutex_init(&(mtx->mutex), NULL);
|
||||
|
||||
if (err != 0)
|
||||
mtx->flag = CMC_FLAG_MUTEX;
|
||||
else
|
||||
mtx->flag = CMC_FLAG_OK;
|
||||
|
||||
return err == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Release all resources from a mutex. Calling this function on a locked mutex
|
||||
* causes undefined behavior.
|
||||
*
|
||||
* \param mtx A mutex to be destroyed.
|
||||
* \return True or false if the mutex was successfully destroyed.
|
||||
*/
|
||||
static inline bool cmc_mtx_destroy(struct cmc_mutex *mtx)
|
||||
{
|
||||
#if defined(CMC_MUTEX_WINDOWS)
|
||||
if (!CloseHandle(mtx->mutex))
|
||||
{
|
||||
mtx->flag = CMC_FLAG_MUTEX;
|
||||
return false;
|
||||
}
|
||||
|
||||
mtx->flag = CMC_FLAG_OK;
|
||||
return true;
|
||||
|
||||
#elif defined(CMC_MUTEX_UNIX)
|
||||
if (pthread_mutex_destroy(&(mtx->mutex)) != 0)
|
||||
{
|
||||
mtx->flag = CMC_FLAG_MUTEX;
|
||||
return false;
|
||||
}
|
||||
|
||||
mtx->flag = CMC_FLAG_OK;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks a mutex. If the mutex is already locked, the thread is blocked until
|
||||
* the mutex can be acquired.
|
||||
*
|
||||
* \param mtx A mutex to be locked.
|
||||
* \return True or false if the lock on the mutex was successfully acquired.
|
||||
*/
|
||||
static inline bool cmc_mtx_lock(struct cmc_mutex *mtx)
|
||||
{
|
||||
#if defined(CMC_MUTEX_WINDOWS)
|
||||
DWORD result = WaitForSingleObject(mtx->mutex, INFINITE);
|
||||
|
||||
if (result == WAIT_FAILED || result == WAIT_ABANDONED)
|
||||
{
|
||||
mtx->flag = CMC_FLAG_MUTEX;
|
||||
return false;
|
||||
}
|
||||
|
||||
mtx->flag = CMC_FLAG_OK;
|
||||
return true;
|
||||
|
||||
#elif defined(CMC_MUTEX_UNIX)
|
||||
if (pthread_mutex_lock(&mtx->mutex) != 0)
|
||||
{
|
||||
mtx->flag = CMC_FLAG_MUTEX;
|
||||
return false;
|
||||
}
|
||||
|
||||
mtx->flag = CMC_FLAG_OK;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks a mutex. If the mutex is already locked, the thread is blocked until
|
||||
* the mutex can be acquired.
|
||||
*
|
||||
* \param mtx A mutex to be unlocked.
|
||||
* \return True or false if the mutex was successfully unlocked.
|
||||
*/
|
||||
static inline bool cmc_mtx_unlock(struct cmc_mutex *mtx)
|
||||
{
|
||||
#if defined(CMC_MUTEX_WINDOWS)
|
||||
if (!ReleaseMutex(mtx->mutex))
|
||||
mtx->flag = CMC_FLAG_MUTEX;
|
||||
else
|
||||
mtx->flag = CMC_FLAG_OK;
|
||||
|
||||
return mtx->flag == CMC_FLAG_OK;
|
||||
|
||||
#elif defined(CMC_MUTEX_UNIX)
|
||||
if (pthread_mutex_unlock(&mtx->mutex) != 0)
|
||||
mtx->flag = CMC_FLAG_MUTEX;
|
||||
else
|
||||
mtx->flag = CMC_FLAG_OK;
|
||||
|
||||
return mtx->flag == CMC_FLAG_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to lock a mutex. If the mutex is already locked, the thread is not
|
||||
* blocked and the function returns false.
|
||||
*
|
||||
* \param mtx A mutex to try to lock.
|
||||
* \return True or false if the lock on the mutex was successfully acquired.
|
||||
*/
|
||||
static inline bool cmc_mtx_trylock(struct cmc_mutex *mtx)
|
||||
{
|
||||
#if defined(CMC_MUTEX_WINDOWS)
|
||||
DWORD result = WaitForSingleObject(mtx->mutex, 0);
|
||||
|
||||
if (result == WAIT_FAILED || result == WAIT_ABANDONED)
|
||||
{
|
||||
mtx->flag = CMC_FLAG_MUTEX;
|
||||
return false;
|
||||
}
|
||||
|
||||
mtx->flag = CMC_FLAG_OK;
|
||||
return result != WAIT_TIMEOUT;
|
||||
|
||||
#elif defined(CMC_MUTEX_UNIX)
|
||||
int err = pthread_mutex_trylock(&mtx->mutex);
|
||||
|
||||
if (err == EINVAL || err == EFAULT)
|
||||
mtx->flag = CMC_FLAG_MUTEX;
|
||||
else
|
||||
mtx->flag = CMC_FLAG_OK;
|
||||
|
||||
return err == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* CMC_UTL_MUTEX_H */
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* utl_test.h
|
||||
*
|
||||
* Creation Date: 26/06/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simple Unit Test Utility
|
||||
*
|
||||
* Required imports:
|
||||
* - assert.h (to integrate with the cmc_assert_state variable)
|
||||
* - timer.h (to calculate the execution time for the unit test)
|
||||
*
|
||||
* CMC_CREATE_UNIT
|
||||
* Create a UnitTest
|
||||
* Parameters:
|
||||
* - UNAME : UnitTest name (const char *)
|
||||
* - VERBOSE : Print PASSED / FAILED messages if true (bool)
|
||||
* - BODY : Body containing all tests related to this UnitTest
|
||||
*
|
||||
* CMC_CREATE_TEST
|
||||
* Create a Test inside a UnitTest.
|
||||
* Parameters:
|
||||
* - TNAME : Test name (const char *)
|
||||
* - BODY : Block of code containing a specific test
|
||||
* Inside the BODY use the macros in ./utl/assert.h. The unit test will keep
|
||||
* track of cmc_assert_state and automatically pass or fail tests.
|
||||
*
|
||||
* CMC_TEST_COLOR
|
||||
* Define this macro to allow colored output.
|
||||
*/
|
||||
|
||||
#ifndef CMC_UTL_TEST_H
|
||||
#define CMC_UTL_TEST_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../cor/core.h"
|
||||
#include "assert.h"
|
||||
#include "timer.h"
|
||||
|
||||
struct cmc_test_info
|
||||
{
|
||||
uintmax_t total;
|
||||
uintmax_t passed;
|
||||
uintmax_t failed;
|
||||
uintmax_t assert_total;
|
||||
uintmax_t assert_failed;
|
||||
bool aborted;
|
||||
bool verbose;
|
||||
};
|
||||
|
||||
#ifdef CMC_TEST_COLOR
|
||||
static inline const char *cmc_test_color(int i)
|
||||
{
|
||||
// 0 - Default, all off
|
||||
// 1 - Failed (red)
|
||||
// 2 - Passed (green)
|
||||
// 3 - Box (gray)
|
||||
// 4 - Name (cyan)
|
||||
// 5 - Total (yellow)
|
||||
static const char *cmc_test_colors[] = { "\x1b[0m", "\x1b[31m", "\x1b[32m", "\x1b[90m", "\x1b[36m", "\x1b[33m" };
|
||||
return cmc_test_colors[i];
|
||||
#else
|
||||
static inline const char *cmc_test_color(int i)
|
||||
{
|
||||
(void)i;
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Logging function */
|
||||
CMC_UNUSED static void cmc_test_log(const char *unit_name, const char *current_test, bool aborted, bool passed)
|
||||
{
|
||||
if (aborted)
|
||||
{
|
||||
printf(" X UNIT TEST");
|
||||
printf("%s", cmc_test_color(4));
|
||||
printf(" %s ", unit_name);
|
||||
printf("%sABORTED%s", cmc_test_color(5), cmc_test_color(0));
|
||||
printf(" at %s\n", current_test);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s", passed ? cmc_test_color(2) : cmc_test_color(1));
|
||||
printf(" |");
|
||||
printf("%s", cmc_test_color(0));
|
||||
printf(" %s", current_test);
|
||||
size_t str_len = strlen(current_test);
|
||||
if (str_len < 53)
|
||||
{
|
||||
printf("%s", cmc_test_color(3));
|
||||
for (size_t i = 0; i < 53 - str_len; i++)
|
||||
putchar('.');
|
||||
}
|
||||
printf("%s", passed ? cmc_test_color(2) : cmc_test_color(1));
|
||||
printf("%s", passed ? "PASSED" : "FAILED");
|
||||
printf("%s\n", cmc_test_color(0));
|
||||
}
|
||||
}
|
||||
|
||||
#define CMC_CREATE_UNIT(UNAME, VERBOSE, BODY) \
|
||||
uintmax_t UNAME(void) \
|
||||
{ \
|
||||
const char *unit_name = #UNAME; \
|
||||
const char *current_test = NULL; \
|
||||
\
|
||||
struct cmc_test_info tinfo = { 0 }; \
|
||||
struct cmc_timer timer = { 0 }; \
|
||||
\
|
||||
tinfo.verbose = VERBOSE; \
|
||||
tinfo.assert_total = cmc_assert_total; \
|
||||
tinfo.assert_failed = cmc_assert_failed; \
|
||||
\
|
||||
printf("%s", cmc_test_color(3)); \
|
||||
printf(" +---------------------------------------------------------------+\n"); \
|
||||
printf(" | "); \
|
||||
printf("%s", cmc_test_color(0)); \
|
||||
printf("Unit "); \
|
||||
printf("%s", cmc_test_color(4)); \
|
||||
printf("%-56s", unit_name); \
|
||||
printf("%s", cmc_test_color(3)); \
|
||||
printf(" |\n +---------------------------------------------------------------+"); \
|
||||
printf("%s\n", cmc_test_color(0)); \
|
||||
\
|
||||
/* Tests */ \
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
BODY; \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
tinfo.assert_total = cmc_assert_total - tinfo.assert_total; \
|
||||
tinfo.assert_failed = cmc_assert_failed - tinfo.assert_failed; \
|
||||
\
|
||||
printf("%s", cmc_test_color(3)); \
|
||||
printf(" +---------------------------------------------------------------+\n | "); \
|
||||
printf("%s", cmc_test_color(0)); \
|
||||
printf("Summary : "); \
|
||||
printf("%s", cmc_test_color(4)); \
|
||||
printf("%-52s", unit_name); \
|
||||
printf("%s|\n", cmc_test_color(3)); \
|
||||
printf(" +---------++----------------+-----------------+-----------------+\n | "); \
|
||||
printf("%s", cmc_test_color(0)); \
|
||||
printf("Tests "); \
|
||||
printf("%s", cmc_test_color(3)); \
|
||||
printf("||"); \
|
||||
printf("%s", cmc_test_color(5)); \
|
||||
printf(" Total %8" PRIuMAX "", tinfo.total); \
|
||||
printf("%s", cmc_test_color(3)); \
|
||||
printf(" | "); \
|
||||
printf("%s", cmc_test_color(2)); \
|
||||
printf("Passed %8" PRIuMAX "", tinfo.passed); \
|
||||
printf("%s", cmc_test_color(3)); \
|
||||
printf(" | "); \
|
||||
printf("%s", cmc_test_color(1)); \
|
||||
printf("Failed %8" PRIuMAX "", tinfo.failed); \
|
||||
printf("%s", cmc_test_color(3)); \
|
||||
printf(" |\n | "); \
|
||||
printf("%s", cmc_test_color(0)); \
|
||||
printf("Asserts "); \
|
||||
printf("%s", cmc_test_color(3)); \
|
||||
printf("||"); \
|
||||
printf("%s", cmc_test_color(5)); \
|
||||
printf(" Total %8" PRIuMAX "", tinfo.assert_total); \
|
||||
printf("%s", cmc_test_color(3)); \
|
||||
printf(" | "); \
|
||||
printf("%s", cmc_test_color(2)); \
|
||||
printf("Passed %8" PRIuMAX "", tinfo.assert_total - tinfo.assert_failed); \
|
||||
printf("%s", cmc_test_color(3)); \
|
||||
printf(" | "); \
|
||||
printf("%s", cmc_test_color(1)); \
|
||||
printf("Failed %8" PRIuMAX "", tinfo.assert_failed); \
|
||||
printf("%s", cmc_test_color(3)); \
|
||||
printf(" |\n"); \
|
||||
printf(" +---------++----------------+-----------------+-----------------+\n | "); \
|
||||
printf("%s", cmc_test_color(0)); \
|
||||
printf("Total Runtime : %32.0f milliseconds", timer.result); \
|
||||
printf(" %s|\n", cmc_test_color(3)); \
|
||||
printf(" +---------------------------------------------------------------+\n"); \
|
||||
printf("%s", cmc_test_color(0)); \
|
||||
printf("\n"); \
|
||||
\
|
||||
return tinfo.failed; \
|
||||
}
|
||||
|
||||
#define CMC_CREATE_TEST(TNAME, BODY) \
|
||||
do \
|
||||
{ \
|
||||
current_test = #TNAME; \
|
||||
\
|
||||
tinfo.total += 1; \
|
||||
\
|
||||
/* Provided by assert.h */ \
|
||||
cmc_assert_state = true; \
|
||||
\
|
||||
BODY; \
|
||||
\
|
||||
if (tinfo.verbose) \
|
||||
{ \
|
||||
if (!cmc_assert_state) \
|
||||
{ \
|
||||
tinfo.failed += 1; \
|
||||
cmc_test_log(unit_name, current_test, false, false); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
tinfo.passed += 1; \
|
||||
cmc_test_log(unit_name, current_test, false, true); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#endif /* CMC_UTL_TEST_H */
|
||||
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* utl_thread.h
|
||||
*
|
||||
* Creation Date: 14/05/2020
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* A very simple, header-only utility for spawning and joining threads
|
||||
*
|
||||
* Types
|
||||
* - cmc_thread
|
||||
* - cmc_thread_proc
|
||||
*
|
||||
* Functions
|
||||
* - cmc_thrd_create
|
||||
* - cmc_thrd_join
|
||||
*/
|
||||
|
||||
#ifndef CMC_UTL_THREAD_H
|
||||
#define CMC_UTL_THREAD_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "../cor/flags.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define CMC_THREAD_WINDOWS
|
||||
#elif defined(__unix__)
|
||||
#define CMC_THREAD_UNIX
|
||||
#else
|
||||
#error "Unknown platform for CMC Threads"
|
||||
#endif
|
||||
|
||||
#if defined(CMC_THREAD_WINDOWS)
|
||||
#include <windows.h>
|
||||
#elif defined(CMC_THREAD_UNIX)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
/* The type of a process run by a thread */
|
||||
typedef int (*cmc_thread_proc)(void *);
|
||||
|
||||
/**
|
||||
* struct cmc_thread
|
||||
*
|
||||
* A thread wrapper.
|
||||
*/
|
||||
struct cmc_thread
|
||||
{
|
||||
#if defined(CMC_THREAD_WINDOWS)
|
||||
HANDLE thread;
|
||||
#elif defined(CMC_THREAD_UNIX)
|
||||
pthread_t thread;
|
||||
#endif
|
||||
int flag;
|
||||
void *args;
|
||||
cmc_thread_proc process;
|
||||
};
|
||||
|
||||
/* A thread wrapper */
|
||||
#if defined(CMC_THREAD_WINDOWS)
|
||||
static DWORD cmc_thread_wrapper(void *arg)
|
||||
#elif defined(CMC_THREAD_UNIX)
|
||||
static void *cmc_thread_wrapper(void *arg)
|
||||
#endif
|
||||
{
|
||||
struct cmc_thread *thr = (struct cmc_thread *)arg;
|
||||
|
||||
int result = thr->process(thr->args);
|
||||
|
||||
#if defined(CMC_THREAD_WINDOWS)
|
||||
return result;
|
||||
#elif defined(CMC_THREAD_UNIX)
|
||||
return (void *)(intptr_t)result;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and spawns a new thread.
|
||||
*
|
||||
* \param thr An uninitialized thread wrapper.
|
||||
* \param proc Pointer to a function that will run in a new thread.
|
||||
* \param args The arguments passed to the proc function.
|
||||
* \return True or false if the thread creation was successfull.
|
||||
*/
|
||||
static inline bool cmc_thrd_create(struct cmc_thread *thr, cmc_thread_proc proc, void *args)
|
||||
{
|
||||
#if defined(CMC_THREAD_WINDOWS)
|
||||
thr->args = args;
|
||||
thr->process = proc;
|
||||
thr->thread = CreateThread(NULL, 0, cmc_thread_wrapper, thr, 0, NULL);
|
||||
|
||||
if (!thr->thread)
|
||||
thr->flag = CMC_FLAG_THREAD;
|
||||
else
|
||||
thr->flag = CMC_FLAG_OK;
|
||||
|
||||
return thr->flag == CMC_FLAG_OK;
|
||||
|
||||
#elif defined(CMC_THREAD_UNIX)
|
||||
thr->args = args;
|
||||
thr->process = proc;
|
||||
if (pthread_create(&(thr->thread), NULL, cmc_thread_wrapper, thr) != 0)
|
||||
thr->flag = CMC_FLAG_THREAD;
|
||||
else
|
||||
thr->flag = CMC_FLAG_OK;
|
||||
|
||||
return thr->flag == CMC_FLAG_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks the current thread until the target thread terminates.
|
||||
*
|
||||
* \param thr The target thread to wait on.
|
||||
* \param result The value returned by the target thread. Optional.
|
||||
* \return True or false if the join was successfull.
|
||||
*/
|
||||
static inline bool cmc_thrd_join(struct cmc_thread *thr, int *result)
|
||||
{
|
||||
#if defined(CMC_THREAD_WINDOWS)
|
||||
if (WaitForSingleObject(thr->thread, INFINITE) == WAIT_FAILED)
|
||||
{
|
||||
thr->flag = CMC_FLAG_THREAD;
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD exit_code;
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (GetExitCodeThread(thr->thread, &exit_code) == 0)
|
||||
{
|
||||
thr->flag = CMC_FLAG_THREAD;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
*result = (int)exit_code;
|
||||
}
|
||||
|
||||
thr->flag = CMC_FLAG_OK;
|
||||
|
||||
if (CloseHandle(thr->thread) == 0)
|
||||
{
|
||||
thr->flag = CMC_FLAG_THREAD;
|
||||
return false;
|
||||
}
|
||||
|
||||
thr->flag = CMC_FLAG_OK;
|
||||
return true;
|
||||
|
||||
#elif defined(CMC_THREAD_UNIX)
|
||||
void *exit_value;
|
||||
|
||||
if (pthread_join(thr->thread, &exit_value) != 0)
|
||||
{
|
||||
thr->flag = CMC_FLAG_THREAD;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
*result = (int)(intptr_t)exit_value;
|
||||
}
|
||||
|
||||
thr->flag = CMC_FLAG_OK;
|
||||
return true;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* CMC_UTL_THREAD_H */
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* utl_timer.h
|
||||
*
|
||||
* Creation Date: 12/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simple timer macros utility for timing code execution.
|
||||
*/
|
||||
|
||||
#ifndef CMC_UTL_TIMER_H
|
||||
#define CMC_UTL_TIMER_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
struct cmc_timer
|
||||
{
|
||||
clock_t start;
|
||||
clock_t stop;
|
||||
double result; /* The result is given in milliseconds */
|
||||
};
|
||||
|
||||
#define cmc_timer_start(timer) \
|
||||
do \
|
||||
{ \
|
||||
struct cmc_timer *t__ = &(timer); \
|
||||
t__->start = clock(); \
|
||||
} while (0)
|
||||
|
||||
#define cmc_timer_stop(timer) \
|
||||
do \
|
||||
{ \
|
||||
struct cmc_timer *t__ = &(timer); \
|
||||
t__->stop = clock(); \
|
||||
t__->result = (double)(t__->stop - t__->start) * 1000.0 / CLOCKS_PER_SEC; \
|
||||
} while (0)
|
||||
|
||||
#endif /* CMC_UTL_TIMER_H */
|
||||
Reference in new issue
Block a user