• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aremmell / libsir / 433

05 Sep 2023 12:02AM UTC coverage: 94.671% (-0.2%) from 94.865%
433

Pull #257

gitlab-ci

aremmell
flip ifdef logic for static init
Pull Request #257: General performance enhancements & portability improvements

236 of 236 new or added lines in 13 files covered. (100.0%)

3020 of 3190 relevant lines covered (94.67%)

632992.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.86
/include/sir/helpers.h
1
/*
2
 * helpers.h
3
 *
4
 * Author:    Ryan M. Lederman <lederman@gmail.com>
5
 * Copyright: Copyright (c) 2018-2023
6
 * Version:   2.2.3
7
 * License:   The MIT License (MIT)
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
10
 * this software and associated documentation files (the "Software"), to deal in
11
 * the Software without restriction, including without limitation the rights to
12
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
13
 * the Software, and to permit persons to whom the Software is furnished to do so,
14
 * subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included in all
17
 * copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
21
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
22
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 */
26
#ifndef _SIR_HELPERS_H_INCLUDED
27
# define _SIR_HELPERS_H_INCLUDED
28

29
# include "sir/types.h"
30
# include "sir/errors.h"
31

32
/** Computes the size of an array. */
33
# define _sir_countof(arr) (sizeof(arr) / sizeof(arr[0]))
34

35
/** Evil macro used for _sir_lv wrappers. */
36
# define _SIR_L_START(format) \
37
    bool ret = false; \
38
    va_list args; \
39
    do { \
40
        if (!_sir_validptr(format)) \
41
            return false; \
42
        va_start(args, format); \
43
    } while (false)
44

45
/** Evil macro used for _sir_lv wrappers. */
46
# define _SIR_L_END() \
47
    va_end(args)
48

49
/** Evil macros used to enter/leave locked sections. */
50
# define _SIR_LOCK_SECTION(type, name, mid, ret) \
51
    type* name = _sir_locksection(mid); \
52
    do { \
53
        if (!name) { \
54
            (void)_sir_seterror(_SIR_E_INTERNAL); \
55
            return ret; \
56
        } \
57
    } while (false)
58

59
/** Evil macros used to enter/leave locked sections. */
60
# define _SIR_UNLOCK_SECTION(mid) \
61
    _sir_unlocksection(mid)
62

63
/** Squelches warnings about unreferenced parameters. */
64
# define SIR_UNUSED(param) (void)param
65

66
/** Combines SIR_ASSERT and SIR_UNUSED, which are frequently used together. */
67
# define SIR_ASSERT_UNUSED(assertion, var) SIR_ASSERT(assertion); SIR_UNUSED(var)
68

69
/** Returns a printable string even if NULL. */
70
# define _SIR_PRNSTR(str) (str ? str : "<null>")
71

72
/** Even more evil macros used for binary searching arrays. */
73
# define _SIR_DECLARE_BIN_SEARCH(low, high) \
74
    size_t _low = low, _high = high; \
75
    size_t _mid = (_low + _high) / 2
76

77
# define _SIR_BEGIN_BIN_SEARCH() do {
78

79
# define _SIR_ITERATE_BIN_SEARCH(comparison) \
80
    if (_low == _high) \
81
        break; \
82
    if (0 > comparison && (_mid - 1) >= _low) { \
83
        _high = _mid - 1; \
84
    } else if ((_mid + 1) <= _high) { \
85
        _low = _mid + 1; \
86
    } else { \
87
        break; \
88
    } \
89
    _mid = (_low + _high) / 2
90

91
# define _SIR_END_BIN_SEARCH() \
92
    } while (true)
93

94
/* Validates a pointer and optionally fails if it's invalid. */
95
static inline
96
bool __sir_validptr(const void* restrict p, bool fail) {
82,824,345✔
97
    bool valid = NULL != p;
82,824,345✔
98
    if (fail && !valid) {
82,824,345✔
99
        (void)_sir_seterror(_SIR_E_NULLPTR);
161✔
100
        SIR_ASSERT(!valid && fail);
140✔
101
    }
102
    return valid;
82,825,378✔
103
}
104

105
/** Validates a pointer-to-pointer and optionally fails if it's invalid. */
106
static inline
107
bool __sir_validptrptr(const void* restrict* pp, bool fail) {
260,448✔
108
    bool valid = NULL != pp;
260,448✔
109
    if (fail && !valid) {
260,448✔
110
        (void)_sir_seterror(_SIR_E_NULLPTR);
×
111
        SIR_ASSERT(!valid && fail);
×
112
    }
113
    return valid;
260,448✔
114
}
115

116
/** Validates a pointer but ignores whether it's invalid. */
117
# define _sir_validptrnofail(p) __sir_validptr(p, false)
118

119
/** Validates a pointer and fails if it's invalid. */
120
# define _sir_validptr(p) __sir_validptr((const void* restrict)p, true)
121

122
/** Validates a pointer-to-function and fails if it's invalid. */
123
# define _sir_validfnptr(fnp) __sir_validptrptr((const void* restrict*)&fnp, true)
124

125
/** Validates a pointer-to-pointer and fails if it's invalid. */
126
# define _sir_validptrptr(pp) __sir_validptrptr((const void* restrict*)pp, true)
127

128
/** Checks a bitmask for a specific set of bits. */
129
static inline
130
bool _sir_bittest(uint32_t flags, uint32_t test) {
24,383,570✔
131
    return (flags & test) == test;
24,383,570✔
132
}
133

134
/** Sets a specific set of bits high in a bitmask. */
135
static inline
136
bool _sir_setbitshigh(uint32_t* flags, uint32_t set) {
615✔
137
    if (!flags)
615✔
138
        return false;
×
139

140
    *flags |= set;
615✔
141
    return true;
615✔
142
}
143

144
/** Sets a specific set of bits low in a bitmask. */
145
static inline
146
bool _sir_setbitslow(uint32_t* flags, uint32_t set) {
376✔
147
    if (!flags)
376✔
148
        return false;
×
149

150
    *flags &= ~set;
376✔
151
    return true;
376✔
152
}
153

154
/** Calls free and sets the pointer to NULL. */
155
void __sir_safefree(void** pp);
156

157
/** Wraps __sir_safefree with a cast to void**. */
158
# define _sir_safefree(pp) __sir_safefree((void**)pp)
159

160
/** Calls close and sets the descriptor to -1. */
161
void _sir_safeclose(int* restrict fd);
162

163
/** Calls fclose and sets the stream pointer to NULL. */
164
void _sir_safefclose(FILE* restrict* restrict f);
165

166
/** Validates a log file descriptor. */
167
bool _sir_validfd(int fd);
168

169
/** Validates a file identifier */
170
static inline
171
bool _sir_validfileid(sirfileid id) {
4,298,846✔
172
    return 0U != id;
4,298,846✔
173
}
174

175
/** Validates a plugin identifier */
176
static inline
177
bool _sir_validpluginid(sirpluginid id) {
178
    return 0U != id;
179
}
180

181
/** Validates a sir_update_config_data structure. */
182
bool _sir_validupdatedata(sir_update_config_data* data);
183

184
/** Validates a set of ::sir_level flags. */
185
bool _sir_validlevels(sir_levels levels);
186

187
/** Validates a single ::sir_level. */
188
bool _sir_validlevel(sir_level level);
189

190
/** Applies default ::sir_level flags if applicable. */
191
static inline
192
void _sir_defaultlevels(sir_levels* levels, sir_levels def) {
40,308✔
193
    if (levels && SIRL_DEFAULT == *levels)
40,308✔
194
        *levels = def;
660✔
195
}
40,308✔
196

197
/** Applies default ::sir_options flags if applicable. */
198
static inline
199
void _sir_defaultopts(sir_options* opts, sir_options def) {
147,960✔
200
    if (opts && SIRO_DEFAULT == *opts)
147,960✔
201
        *opts = def;
2,018✔
202
}
147,960✔
203

204
/** Validates a set of ::sir_option flags. */
205
bool _sir_validopts(sir_options opts);
206

207
/** Validates a ::sir_textattr. */
208
bool _sir_validtextattr(sir_textattr attr);
209

210
/** Validates a ::sir_textcolor based on color mode. */
211
bool _sir_validtextcolor(sir_colormode mode, sir_textcolor color);
212

213
/** Validates a ::sir_colormode. */
214
bool _sir_validcolormode(sir_colormode mode);
215

216
/** Converts a SIRTC_* value to a 16-color mode ANSI foreground color. */
217
static inline
218
sir_textcolor _sir_mkansifgcolor(sir_textcolor fg) {
313,477✔
219
    return SIRTC_DEFAULT == fg ? 39 : fg < 8 ? fg + 30 : fg + 82;
313,477✔
220
}
221

222
/** Converts a SIRTC_* value to a 16-color mode ANSI background color. */
223
static inline
224
sir_textcolor _sir_mkansibgcolor(sir_textcolor bg) {
313,477✔
225
    return SIRTC_DEFAULT == bg ? 49 : bg < 8 ? bg + 40 : bg + 92;
313,477✔
226
}
227

228
/** Returns the appropriate ANSI command for the specified foreground color. */
229
static inline
230
sir_textcolor _sir_getansifgcmd(sir_textcolor fg) {
12,144✔
231
    return SIRTC_DEFAULT == fg ? 39 : 38;
12,144✔
232
}
233

234
/** Returns the appropriate ANSI command for the specified background color. */
235
static inline
236
sir_textcolor _sir_getansibgcmd(sir_textcolor bg) {
12,144✔
237
    return SIRTC_DEFAULT == bg ? 49 : 48;
12,144✔
238
}
239

240
/** Extracts the red component out of an RGB color mode ::sir_textcolor. */
241
# define _sir_getredfromcolor(color) (uint8_t)(((color) >> 16) & 0x000000ffU)
242

243
/** Sets the red component in an RGB color mode ::sir_textcolor. */
244
# define _sir_setredincolor(color, red) (color |= (((red) << 16) & 0x00ff0000U))
245

246
/** Extracts the green component out of an RGB color mode ::sir_textcolor. */
247
# define _sir_getgreenfromcolor(color) (uint8_t)(((color) >> 8) & 0x000000ffU)
248

249
/** Sets the green component in an RGB color mode ::sir_textcolor. */
250
# define _sir_setgreenincolor(color, green) ((color) |= (((green) << 8) & 0x0000ff00U))
251

252
/** Extracts the blue component out of an RGB color mode ::sir_textcolor. */
253
# define _sir_getbluefromcolor(color) (uint8_t)((color) & 0x000000ffU)
254

255
/** Sets the blue component in an RGB color mode ::sir_textcolor. */
256
# define _sir_setblueincolor(color, blue) ((color) |= ((blue) & 0x000000ffU))
257

258
/** Sets the red, blue, and green components in an RGB color mode ::sir_textcolor. */
259
static inline
260
sir_textcolor _sir_makergb(sir_textcolor r, sir_textcolor g, sir_textcolor b) {
11,822✔
261
    sir_textcolor retval = 0;
10,280✔
262
    _sir_setredincolor(retval, r);
11,822✔
263
    _sir_setgreenincolor(retval, g);
11,822✔
264
    _sir_setblueincolor(retval, b);
11,822✔
265
    return retval;
11,822✔
266
}
267

268
/** Validates a string pointer and optionally fails if it's invalid. */
269
static inline
270
bool __sir_validstr(const char* restrict str, bool fail) {
51,843,931✔
271
    bool valid = str && *str != '\0';
51,843,931✔
272
    if (fail && !valid) {
51,843,931✔
273
        (void)_sir_seterror(_SIR_E_STRING);
14,197✔
274
        SIR_ASSERT(!valid && fail);
14,174✔
275
    }
276
    return valid;
51,843,943✔
277
}
278

279
/** Validates a string pointer and fails if it's invalid. */
280
# define _sir_validstr(str) __sir_validstr(str, true)
281

282
/** Validates a string pointer but ignores whether it's invalid. */
283
# define _sir_validstrnofail(str) __sir_validstr(str, false)
284

285
/** Places a null terminator at the first index in a string buffer. */
286
static inline
287
void _sir_resetstr(char* str) {
2,737,604✔
288
    if (NULL != str)
2,737,604✔
289
        *str = '\0';
2,737,608✔
290
}
2,737,604✔
291

292
/**
293
 * Wrapper for strncmp. Just easier to read and use if you only wish to
294
 * test for equality. Not case-sensitive.
295
 */
296
static inline
297
bool _sir_strsame(const char* lhs, const char* rhs, size_t count) {
84✔
298
    return 0 == strncmp(lhs, rhs, count);
84✔
299
}
300

301
/**
302
 * Wrapper for str[n,l]cpy/strncpy_s. Determines which one to use
303
 * based on preprocessor macros.
304
 */
305
int _sir_strncpy(char* restrict dest, size_t destsz,
306
    const char* restrict src, size_t count);
307

308
/**
309
 * Wrapper for str[n,l]cat/strncat_s. Determines which one to use
310
 * based on preprocessor macros.
311
 */
312
int _sir_strncat(char* restrict dest, size_t destsz,
313
    const char* restrict src, size_t count);
314

315
/**
316
 * Wrapper for fopen/fopen_s. Determines which one to use
317
 * based on preprocessor macros.
318
 */
319
int _sir_fopen(FILE* restrict* restrict streamptr, const char* restrict filename,
320
    const char* restrict mode);
321

322
/**
323
 * Wrapper for localtime[_s,_r]. Determines which one to use
324
 * based on preprocessor macros.
325
 */
326
static inline
327
struct tm* _sir_localtime(const time_t* timer, struct tm* buf) {
2,197,674✔
328
    if (!timer || !buf)
2,197,674✔
329
        return NULL;
×
330
# if defined(__HAVE_STDC_SECURE_OR_EXT1__) && !defined(__EMBARCADEROC__)
331
#  if !defined(__WIN__)
332
        struct tm* ret = localtime_s(timer, buf);
333
        if (!ret) {
334
            (void)_sir_handleerr(errno);
335
            return NULL;
336
        }
337
#  else /* __WIN__ */
338
        errno_t ret = localtime_s(buf, timer);
339
        if (0 != ret) {
340
            (void)_sir_handleerr(ret);
341
            return NULL;
342
        }
343
#  endif
344
        return buf;
345
# else /* !__HAVE_STDC_SECURE_OR_EXT1__ */
346
#  if !defined(__WIN__) || defined(__EMBARCADEROC__)
347
        struct tm* ret = localtime_r(timer, buf);
2,197,674✔
348
#  else
349
        struct tm* ret = localtime(timer);
350
#  endif
351
        if (!ret)
2,197,674✔
352
            (void)_sir_handleerr(errno);
10,019✔
353
        return ret;
2,167,771✔
354
# endif
355
}
356

357
/** Formats the current time as a string. */
358
# if defined(__GNUC__)
359
__attribute__ ((format (strftime, 3, 0)))
360
# endif
361
static inline
362
bool _sir_formattime(time_t now, char* buffer, const char* format) {
2,197,674✔
363
    if (!buffer || !format)
2,197,674✔
364
        return false;
×
365
# if defined(__GNUC__) && !defined(__clang__) && \
366
    !(defined(__OPEN64__) || defined(__OPENCC__))
367
#  pragma GCC diagnostic push
368
#  pragma GCC diagnostic ignored "-Wformat-nonliteral"
369
# endif
370
    struct tm timebuf;
371
    struct tm* ptb = _sir_localtime(&now, &timebuf);
2,197,674✔
372
    return NULL != ptb && 0 != strftime(buffer, SIR_MAXTIME, format, ptb);
2,197,674✔
373
# if defined(__GNUC__) && !defined(__clang__) && \
374
    !(defined(__OPEN64__) || defined(__OPENCC__))
375
#  pragma GCC diagnostic pop
376
# endif
377
}
378

379
/**
380
 * A portable "press any key to continue" implementation; On Windows, uses _getch().
381
 * otherwise, uses tcgetattr()/tcsetattr() and getchar().
382
 */
383
bool _sir_getchar(char* input);
384

385
/**
386
 * Wrapper for snprintf when truncation is intended.
387
 */
388
# define _sir_snprintf_trunc(dst, size, ...) \
389
    do { \
390
      volatile size_t _n = size; \
391
      if (!snprintf(dst, _n, __VA_ARGS__)) { (void)_n; }; \
392
    } while (false)
393

394
/**
395
 * Implementation of the 32-bit FNV-1a OWHF (http://isthe.com/chongo/tech/comp/fnv/)
396
 */
397
static inline
398
uint32_t FNV32_1a(const uint8_t* data, size_t len) {
36,913✔
399
    uint32_t hash = 2166136261U;
30,728✔
400
    for (size_t n = 0; n < len; n++) {
1,065,301✔
401
        hash ^= (uint32_t)data[n];
1,028,388✔
402
        hash = (uint32_t)(hash * 16777619ULL);
1,028,388✔
403
    }
404
    return hash;
36,913✔
405
}
406

407
/**
408
 * Implementation of the 64-bit FNV-1a OWHF (http://isthe.com/chongo/tech/comp/fnv/)
409
 * watered down to only handle null-terminated strings.
410
 */
411
# if defined(__clang__) /* only Clang has unsigned-integer-overflow; GCC BZ#96829 */
412
SANITIZE_SUPPRESS("unsigned-integer-overflow")
413
# endif
414
static inline
415
uint64_t FNV64_1a(const char* str) {
2,123,049✔
416
    uint64_t hash = 14695981039346656037ULL;
2,104,236✔
417
    for (const char* c = str; *c; c++) {
74,708,704✔
418
        hash ^= (uint64_t)(unsigned char)(*c);
72,585,655✔
419
        hash *= 1099511628211ULL; /* unsigned-integer-overflow */
72,585,655✔
420
    }
421
    return hash;
2,123,049✔
422
}
423

424
#endif /* !_SIR_HELPERS_H_INCLUDED */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc