Skip to content

Commit

Permalink
Bugfix: Fix attribute availability detection
Browse files Browse the repository at this point in the history
  • Loading branch information
dr8co committed Apr 24, 2024
1 parent 8c4022d commit 32f28e8
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 61 deletions.
55 changes: 27 additions & 28 deletions lite_string.c
Original file line number Diff line number Diff line change
@@ -1,58 +1,58 @@
#include "lite_string.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "lite_string.h"

#ifndef __has_include
#define __has_include(x) 0
#endif
#define __has_include(x) 0 // Compatibility with non-GNU compilers
#endif // !__has_include

#ifndef __has_builtin
#define __has_builtin(x) 0 // For compilers that do not support __has_builtin
#endif
#endif // !__has_builtin

#define HAVE_STRNCASECMP 1
#define HAS_STRNCASECMP 1
#if _MSC_VER || _WIN32 || _WIN64 || WIN32
#define strncasecmp _strnicmp // Windows equivalent
#elif _GNU_SOURCE || _DEFAULT_SOURCE
// strncasecmp is available
// strncasecmp is available as a GNU extension
#elif __has_include(<strings.h>) || _POSIX_C_SOURCE >= 200112L
#include <strings.h> // POSIX strncasecmp is available
#else
// strncasecmp is not available, use a custom implementation
#undef HAVE_STRNCASECMP
#define HAVE_STRNCASECMP 0
#undef HAS_STRNCASECMP
#define HAS_STRNCASECMP 0
#include <ctype.h> // For tolower()
#endif
#endif // _MSC_VER || _WIN32 || _WIN64 || WIN32

#if __STDC_VERSION__ >= 202311L
#if __has_c_attribute(gnu::always_inline)
#if __STDC_VERSION__ >= 202311L // C23 or later, use the new attributes if available
#if HAS_ATTRIBUTE(always_inline)
#define LITE_ATTR_ALWAYS_INLINE [[gnu::always_inline]]
#else
#define LITE_ATTR_ALWAYS_INLINE
#endif
#endif // HAS_ATTRIBUTE(gnu::always_inline)

#if __has_c_attribute(maybe_unused)
#if HAS_C_ATTRIBUTE(maybe_unused)
#define LITE_ATTR_MAYBE_UNUSED [[__maybe_unused__]]
#elif __has_c_attribute(gnu::unused)
#elif HAS_ATTRIBUTE(unused)
#define LITE_ATTR_MAYBE_UNUSED [[gnu::unused]]
#else
#define LITE_ATTR_MAYBE_UNUSED
#endif
#endif // HAS_C_ATTRIBUTE(maybe_unused)

#else
#if __has_c_attribute(__always_inline__)
#if HAS_ATTRIBUTE(__always_inline__)
#define LITE_ATTR_ALWAYS_INLINE __attribute__((__always_inline__))
#else
#define LITE_ATTR_ALWAYS_INLINE
#endif
#endif // HAS_ATTRIBUTE(__always_inline__)

#if __has_c_attribute(__unused__)
#if HAS_ATTRIBUTE(__unused__)
#define LITE_ATTR_MAYBE_UNUSED __attribute__((__unused__))
#else
#define LITE_ATTR_MAYBE_UNUSED
#endif
#endif
#endif // HAS_ATTRIBUTE(__unused__)
#endif // __STDC_VERSION__ >= 202311L

/**
* @brief A simple emulation of a C++ string in C.
Expand Down Expand Up @@ -324,9 +324,9 @@ bool string_erase_range(lite_string *const restrict s, const size_t start, const
if (s && start < s->size) {
if (count == 0) return true;
// Check if the range is within the bounds of the string
#if __has_builtin(__builtin_uaddll_overflow)
#if __has_builtin(__builtin_add_overflow)
size_t end;
if (!__builtin_uaddll_overflow(start, count, &end) && end <= s->size)
if (!__builtin_add_overflow(start, count, &end) && end <= s->size)
#else
if (count < s->size && start + count <= s->size)
#endif
Expand Down Expand Up @@ -713,7 +713,7 @@ bool string_compare_cstr(const lite_string *const restrict s, const char *const
bool string_case_compare_cstr(const lite_string *const restrict s, const char *const restrict cstr) {
if (s && cstr) {
if (s->size == strlen(cstr)) {
#if HAVE_STRNCASECMP
#if HAS_STRNCASECMP
return strncasecmp(s->data, cstr, s->size) == 0;
#else
for (size_t i = 0; i < s->size; ++i) {
Expand Down Expand Up @@ -1072,7 +1072,6 @@ LITE_ATTR_MAYBE_UNUSED static size_t kmp_search(const char *const restrict s, co
#endif
return i - j;
}

// Mismatch after j matches
if (i < s_size && sub[j] != s[i]) {
if (j)
Expand Down Expand Up @@ -1394,7 +1393,7 @@ void string_to_lower(const lite_string *const restrict s) {
if (s) {
for (size_t i = 0; i < s->size; ++i) {
if (s->data[i] >= 'A' && s->data[i] <= 'Z')
s->data[i] |= 32;
s->data[i] += 32;
}
}
}
Expand All @@ -1408,7 +1407,7 @@ void string_to_upper(const lite_string *const restrict s) {
if (s) {
for (size_t i = 0; i < s->size; ++i) {
if (s->data[i] >= 'a' && s->data[i] <= 'z')
s->data[i] &= ~32;
s->data[i] -= 32;
}
}
}
Expand All @@ -1421,12 +1420,12 @@ void string_to_upper(const lite_string *const restrict s) {
void string_to_title(const lite_string *const restrict s) {
if (s) {
if (s->data[0] >= 'a' && s->data[0] <= 'z')
s->data[0] &= ~32;
s->data[0] -= 32;

// Iterate over the rest of the string
for (size_t i = 1; i < s->size; ++i) {
if (s->data[i] == ' ' && s->data[i + 1] >= 'a' && s->data[i + 1] <= 'z')
s->data[i + 1] &= ~32;
s->data[i + 1] -= 32;
}
}
}
Expand Down
69 changes: 36 additions & 33 deletions lite_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// Check version compatibility requirements
#ifdef LITE_STRING_REQUIRE_MIN_VERSION
#if (LITE_STRING_REQUIRE_MIN_VERSION + 0) == 0
#if _MSC_VER && !defined(__clang__)
#if _MSC_VER && !defined(__clang__) // MSVC does not have '#warning', but clang-cl does
#pragma message ("WARNING: Lite String version requirement is enabled, but the version is not specified!")
#else
#warning "Lite String version requirement is enabled, but the version is not specified!"
Expand Down Expand Up @@ -54,7 +54,7 @@
#endif // __clang__

#define restrict __restrict // Use '__restrict' in C++ for GCC, Clang, and MSVC
#else // Support for '__restrict' in C++ is unknown
#else // Support for C++ '__restrict' is unknown on this compiler
#define restrict
#endif // __GNUC__ || __clang__ || _MSC_VER

Expand All @@ -72,52 +72,56 @@ extern "C" {

#define lite_string_npos ((size_t) -1)

#if !defined(__has_c_attribute)
#if defined(__has_attribute)
#define __has_c_attribute __has_attribute
#ifdef __has_attribute
#define HAS_ATTRIBUTE(x) __has_attribute(x)
#else
#define __has_c_attribute(x) 0 // Compatibility with non-gnu compilers
#endif
#endif
#define HAS_ATTRIBUTE(x) 0
#endif // __has_attribute

#ifdef __has_c_attribute
#define HAS_C_ATTRIBUTE(x) __has_c_attribute(x)
#else
#define HAS_C_ATTRIBUTE(x) HAS_ATTRIBUTE(x)
#endif // __has_c_attribute

#if __STDC_VERSION__ >= 202311L // C23 is supported
#if __has_c_attribute(nodiscard) // C23 'nodiscard' attribute
#if HAS_C_ATTRIBUTE(nodiscard) // C23 'nodiscard' attribute
#define LITE_ATTR_NODISCARD [[__nodiscard__]]
#elif __has_c_attribute(gnu::warn_unused_result) // GNU 'warn_unused_result' attribute
#elif HAS_ATTRIBUTE(warn_unused_result) // GNU 'warn_unused_result' attribute
#define LITE_ATTR_NODISCARD [[gnu::warn_unused_result]]
#else
#define LITE_ATTR_NODISCARD
#endif // __has_c_attribute(nodiscard)
#endif // HAS_C_ATTRIBUTE(nodiscard)

#if __has_c_attribute(gnu::hot) // GNU 'hot' attribute
#if HAS_ATTRIBUTE(hot) // GNU 'hot' attribute
#define LITE_ATTR_HOT [[gnu::hot]]
#else
#define LITE_ATTR_HOT
#endif // __has_c_attribute(gnu::hot)
#endif // HAS_ATTRIBUTE(hot)

#if __has_c_attribute(reproducible) // C23 'reproducible' attribute
#if HAS_C_ATTRIBUTE(reproducible) // C23 'reproducible' attribute
#define LITE_ATTR_REPRODUCIBLE [[__reproducible__]]
#elif __has_c_attribute(gnu::pure) // GNU 'pure' attribute as a substitute
#elif HAS_ATTRIBUTE(pure) // GNU 'pure' attribute as a substitute
#define LITE_ATTR_REPRODUCIBLE [[gnu::pure]]
#else
#define LITE_ATTR_REPRODUCIBLE
#endif // __has_c_attribute(reproducible)
#endif // HAS_C_ATTRIBUTE(reproducible)

#if __has_c_attribute(unsequenced) // C23 'unsequenced' attribute
#if HAS_C_ATTRIBUTE(unsequenced) // C23 'unsequenced' attribute
#define LITE_ATTR_UNSEQUENCED [[__unsequenced__]]
#elif __has_c_attribute(gnu::const) // GNU 'const' attribute as a substitute
#elif HAS_ATTRIBUTE(__const__) // GNU 'const' attribute as a substitute
#define LITE_ATTR_UNSEQUENCED [[gnu::const]]
#else
#define LITE_ATTR_UNSEQUENCED
#endif // __has_c_attribute(unsequenced)
#endif // HAS_C_ATTRIBUTE(unsequenced)

#if __has_c_attribute(gnu::nothrow) // GNU 'nothrow' attribute
#if HAS_ATTRIBUTE(nothrow) // GNU 'nothrow' attribute
#define LITE_ATTR_NOEXCEPT [[gnu::nothrow]]
#elif _MSC_VER
#define LITE_ATTR_NOEXCEPT __declspec(nothrow) // MSVC equivalent
#else
#define LITE_ATTR_NOEXCEPT
#endif // __has_c_attribute(gnu::nothrow)
#endif // HAS_ATTRIBUTE(nothrow)

#else // C23 is not supported
#ifndef __cplusplus
Expand All @@ -129,38 +133,37 @@ extern "C" {
#endif // _MSC_VER
#endif // __cplusplus


#if __has_c_attribute(__warn_unused_result__) // GNU 'warn_unused_result' attribute, pre-C23 syntax
#if HAS_ATTRIBUTE(__warn_unused_result__) // GNU 'warn_unused_result' attribute, pre-C23 syntax
#define LITE_ATTR_NODISCARD __attribute__((__warn_unused_result__))
#else
#define LITE_ATTR_NODISCARD
#endif // __has_c_attribute(__warn_unused_result__)
#endif // HAS_ATTRIBUTE(__warn_unused_result__)

#if __has_c_attribute(__hot__) // GNU 'hot' attribute
#if HAS_ATTRIBUTE(__hot__) // GNU 'hot' attribute
#define LITE_ATTR_HOT __attribute__((__hot__))
#else
#define LITE_ATTR_HOT
#endif // __has_c_attribute(__hot__)
#endif // HAS_ATTRIBUTE(__hot__)

#if __has_c_attribute(__pure__) // GNU 'pure' attribute
#if HAS_ATTRIBUTE(__pure__) // GNU 'pure' attribute
#define LITE_ATTR_REPRODUCIBLE __attribute__((__pure__))
#else
#define LITE_ATTR_REPRODUCIBLE
#endif // __has_c_attribute(__pure__)
#endif // HAS_ATTRIBUTE(__pure__)

#if __has_c_attribute(__const__) // GNU 'const' attribute
#if HAS_ATTRIBUTE(__const__) // GNU 'const' attribute
#define LITE_ATTR_UNSEQUENCED __attribute__((__const__))
#else
#define LITE_ATTR_UNSEQUENCED
#endif // __has_c_attribute(__const__)
#endif // HAS_ATTRIBUTE(__const__)

#if __has_c_attribute(nothrow) // GNU 'nothrow' attribute
#define LITE_ATTR_NOEXCEPT __attribute__((nothrow))
#if HAS_ATTRIBUTE(__nothrow__) // GNU 'nothrow' attribute
#define LITE_ATTR_NOEXCEPT __attribute__((__nothrow__))
#elif _MSC_VER
#define LITE_ATTR_NOEXCEPT __declspec(nothrow) // MSVC equivalent
#else
#define LITE_ATTR_NOEXCEPT
#endif // __has_c_attribute(nothrow)
#endif // HAS_ATTRIBUTE(nothrow)

#endif // __STDC_VERSION__ >= 202311L

Expand Down

0 comments on commit 32f28e8

Please sign in to comment.