397 lines
13 KiB
C
397 lines
13 KiB
C
// =====================================================================================================================
|
|
// fennec, a free and open source game engine
|
|
// Copyright © 2025 Medusa Slockbower
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
// =====================================================================================================================
|
|
|
|
///
|
|
/// \file intrinsics.h
|
|
/// \brief \ref fennec_lang_intrinsics
|
|
///
|
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
|
///
|
|
///
|
|
|
|
#ifndef FENNEC_LANG_INTRINSICS_H
|
|
#define FENNEC_LANG_INTRINSICS_H
|
|
|
|
///
|
|
/// \page fennec_lang_intrinsics Intrinsics
|
|
///
|
|
/// \brief This header contains definitions for compiler intrinsics necessary for implementing functions of the
|
|
/// C++ stdlib.
|
|
///
|
|
/// \code{.cpp}#include <fennec/lang/intrinsics.h>\endcode
|
|
///
|
|
///
|
|
/// <table width="100%" class="fieldtable" id="table_fennec_lang_intrinsics">
|
|
/// <tr><th style="vertical-align: top">Syntax
|
|
/// <th style="vertical-align: top">Description
|
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
|
/// `FENNEC_HAS_BUILTIN_BIT_CAST` <br>
|
|
/// `Y FENNEC_BUILTIN_BIT_CAST(X)`
|
|
/// <td width="50%" style="vertical-align: top">
|
|
/// An intrinsic for doing a bitwise cast without using `reinterpret_cast`.
|
|
///
|
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
|
/// `FENNEC_HAS_BUILTIN_ADDRESSOF` <br>
|
|
/// `Y FENNEC_BUILTIN_ADDRESSOF(X)`
|
|
/// <td width="50%" style="vertical-align: top">
|
|
/// Obtains the true address of an object in circumstances where `operator&` is overloaded.
|
|
///
|
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
|
/// `FENNEC_HAS_BUILTIN_IS_CONVERTIBLE` <br>
|
|
/// `B FENNEC_BUILTIN_IS_CONVERTIBLE(X, Y)`
|
|
/// <td width="50%" style="vertical-align: top">
|
|
/// Checks if type `X` can be converted to type `Y`.
|
|
///
|
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
|
/// `FENNEC_HAS_BUILTIN_IS_EMPTY` <br>
|
|
/// `B FENNEC_BUILTIN_IS_EMPTY(X)`
|
|
/// <td width="50%" style="vertical-align: top">
|
|
/// Checks if type `X` stores no data.
|
|
///
|
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
|
/// `FENNEC_HAS_BUILTIN_IS_POLYMORPHIC` <br>
|
|
/// `B FENNEC_BUILTIN_IS_POLYMORPHIC(X)`
|
|
/// <td width="50%" style="vertical-align: top">
|
|
/// Checks if type `X` is polymorphic, this is for classes only thus checks only for subtyping
|
|
///
|
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
|
/// `FENNEC_HAS_BUILTIN_IS_FINAL` <br>
|
|
/// `B FENNEC_BUILTIN_IS_FINAL(X)`
|
|
/// <td width="50%" style="vertical-align: top">
|
|
/// Checks if type `X` is final, meaning a function or class cannot be derived from.
|
|
///
|
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
|
/// `FENNEC_HAS_BUILTIN_IS_ABSTRACT` <br>
|
|
/// `B FENNEC_BUILTIN_IS_ABSTRACT(X)`
|
|
/// <td width="50%" style="vertical-align: top">
|
|
/// Opposite of `FENNEC_BUILTIN_IS_FINAL`, checks if abstract, meaning `X` has at least one pure virtual function.
|
|
///
|
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
|
/// `FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT` <br>
|
|
/// `B FENNEC_BUILTIN_IS_STANDARD_LAYOUT(X)`
|
|
/// <td width="50%" style="vertical-align: top">
|
|
/// Checks if `X` has a standard layout, here is [full criteria](https://www.cppreference.com/w/cpp/language/classes.html#Standard-layout_class)
|
|
/// for this trait
|
|
///
|
|
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
|
/// `FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE` <br>
|
|
/// `B FENNEC_BUILTIN_IS_CONSTRUCTIBLE(X, ...)`
|
|
/// <td width="50%" style="vertical-align: top">
|
|
/// Checks if type `X` is constructible with args `...`, such that `X::X(...)` exists.
|
|
///
|
|
/// </table>
|
|
///
|
|
///
|
|
|
|
|
|
// Most major compilers support __has_builtin, notably GCC, MINGW, and CLANG
|
|
#if defined(__has_builtin)
|
|
|
|
|
|
// UTILITIES ===========================================================================================================
|
|
|
|
// addressof is very difficult to implement without intrinsics.
|
|
#if __has_builtin(__builtin_addressof)
|
|
# define FENNEC_HAS_BUILTIN_ADDRESSOF 1
|
|
# define FENNEC_BUILTIN_ADDRESSOF(arg) __builtin_addressof(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_ADDRESSOF 0
|
|
#endif
|
|
|
|
// bitcast is slightly more efficient for build times than using memcpy
|
|
#if __has_builtin(__builtin_bit_cast)
|
|
# define FENNEC_HAS_BUILTIN_BIT_CAST 1
|
|
# define FENNEC_BUILTIN_BIT_CAST(type, arg) __builtin_bit_cast(type, arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_BIT_CAST 0
|
|
#endif
|
|
|
|
#if __has_builtin(__builtin_LINE)
|
|
# define FENNEC_HAS_BUILTIN_LINE 1
|
|
# define FENNEC_BUILTIN_LINE() __builtin_LINE()
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_LINE 0
|
|
#endif
|
|
|
|
#if __has_builtin(__builtin_COLUMN)
|
|
# define FENNEC_HAS_BUILTIN_COLUMN 1
|
|
# define FENNEC_BUILTIN_COLUMN() __builtin_COLUMN()
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_COLUMN 0
|
|
#endif
|
|
|
|
#if __has_builtin(__builtin_FILE)
|
|
# define FENNEC_HAS_BUILTIN_FILE 1
|
|
# define FENNEC_BUILTIN_FILE() __builtin_FILE()
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_FILE 0
|
|
#endif
|
|
|
|
#if __has_builtin(__builtin_FUNCTION)
|
|
# define FENNEC_HAS_BUILTIN_FUNCTION 1
|
|
# define FENNEC_BUILTIN_FUNCTION() __builtin_FUNCTION()
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_FUNCTION 0
|
|
#endif
|
|
|
|
|
|
// PROPERTIES ==========================================================================================================
|
|
|
|
// Inconsistent without intrinsics
|
|
#if __has_builtin(__is_abstract)
|
|
# define FENNEC_HAS_BUILTIN_IS_ABSTRACT 1
|
|
# define FENNEC_BUILTIN_IS_ABSTRACT(arg) __is_abstract(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_ABSTRACT 0
|
|
#endif
|
|
|
|
// Inconsistent without intrinsics
|
|
#if __has_builtin(__is_array)
|
|
# define FENNEC_HAS_BUILTIN_IS_ARRAY 1
|
|
# define FENNEC_BUILTIN_IS_ARRAY(arg) __is_array(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_ARRAY
|
|
#endif
|
|
|
|
// Inconsistent without intrinsics
|
|
#if __has_builtin(__is_class)
|
|
# define FENNEC_HAS_BUILTIN_IS_CLASS 1
|
|
# define FENNEC_BUILTIN_IS_CLASS(arg) __is_class(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_CLASS
|
|
#endif
|
|
|
|
#if __has_builtin(__is_member_pointer)
|
|
# define FENNEC_HAS_BUILTIN_IS_MEMBER_POINTER 1
|
|
# define FENNEC_BUILTIN_IS_MEMBER_POINTER(arg) __is_member_pointer(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_MEMBER_POINTER 0
|
|
#endif
|
|
|
|
#if __has_builtin(__is_member_function_pointer)
|
|
# define FENNEC_HAS_BUILTIN_IS_MEMBER_FUNCTION_POINTER 1
|
|
# define FENNEC_BUILTIN_IS_MEMBER_FUNCTION_POINTER(arg) __is_member_function_pointer(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_MEMBER_FUNCTION_POINTER 0
|
|
#endif
|
|
|
|
#if __has_builtin(__is_member_object_pointer)
|
|
# define FENNEC_HAS_BUILTIN_IS_MEMBER_OBJECT_POINTER 1
|
|
# define FENNEC_BUILTIN_IS_MEMBER_OBJECT_POINTER(arg) __is_member_object_pointer(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_MEMBER_OBJECT_POINTER 0
|
|
#endif
|
|
|
|
|
|
// CONSTRUCTORS ========================================================================================================
|
|
|
|
// Difficult and Inconsistent without intrinsics
|
|
#if __has_builtin(__is_constructible)
|
|
# define FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE 1
|
|
# define FENNEC_BUILTIN_IS_CONSTRUCTIBLE(type, ...) __is_constructible(type __VA_OPT__(,) __VA_ARGS__)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE 0
|
|
#endif
|
|
|
|
// Difficult and Inconsistent without intrinsics
|
|
#if __has_builtin(__is_trivially_constructible)
|
|
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 1
|
|
# define FENNEC_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE(type) __is_trivially_constructible(type)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 0
|
|
#endif
|
|
|
|
// Difficult and Inconsistent without intrinsics
|
|
#if __has_builtin(__has_trivial_destructor)
|
|
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 1
|
|
# define FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(type) __has_trivial_destructor(type)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 0
|
|
#endif
|
|
|
|
|
|
// ASSIGNMENTS =========================================================================================================
|
|
|
|
// Difficult and Inconsistent without intrinsics
|
|
#if __has_builtin(__is_assignable)
|
|
# define FENNEC_HAS_BUILTIN_IS_ASSIGNABLE 1
|
|
# define FENNEC_BUILTIN_IS_ASSIGNABLE(a, b) __is_assignable(a, b)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_ASSIGNABLE 0
|
|
#endif
|
|
|
|
// Inconsistent without intrinsics
|
|
#if __has_builtin(__is_trivial)
|
|
# define FENNEC_HAS_BUILTIN_IS_TRIVIAL 1
|
|
# define FENNEC_BUILTIN_IS_TRIVIAL(a) __is_trivial(a)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_TRIVIAL 0
|
|
#endif
|
|
|
|
// Difficult and Inconsistent without intrinsics
|
|
#if __has_builtin(__is_trivially_copyable)
|
|
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_COPYABLE 1
|
|
# define FENNEC_BUILTIN_IS_TRIVIALLY_COPYABLE(a) __is_trivially_copyable(a)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_COPYABLE 0
|
|
#endif
|
|
|
|
// Impossible without instrinsics
|
|
#if __has_builtin(__is_standard_layout)
|
|
# define FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT 1
|
|
# define FENNEC_BUILTIN_IS_STANDARD_LAYOUT(arg) __is_standard_layout(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT 0
|
|
#endif
|
|
|
|
// Impossible without instrinsics
|
|
#if __has_builtin(__has_unique_object_representations)
|
|
# define FENNEC_HAS_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS 1
|
|
# define FENNEC_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS(arg) __has_unique_object_representations(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS 0
|
|
#endif
|
|
|
|
|
|
// Type Traits
|
|
// can_convert is also very difficult to implement without intrinsics
|
|
#if __has_builtin(__is_convertible)
|
|
# define FENNEC_HAS_BUILTIN_IS_CONVERTIBLE 1
|
|
# define FENNEC_BUILTIN_IS_CONVERTIBLE(arg0, arg1) __is_convertible(arg0, arg1)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_CONVERTIBLE 0
|
|
#endif
|
|
|
|
// Inconsistent without intrinsics.
|
|
#if __has_builtin(__is_empty)
|
|
# define FENNEC_HAS_BUILTIN_IS_EMPTY 1
|
|
# define FENNEC_BUILTIN_IS_EMPTY(arg) __is_empty(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_EMPTY 0
|
|
|
|
// Inconsistent without intrinsics
|
|
#if __has_builtin(__is_final)
|
|
# define FENNEC_HAS_BUILTIN_IS_FINAL 1
|
|
# define FENNEC_BUILTIN_IS_FINAL(arg) __is_final(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_FINAL 0
|
|
#endif
|
|
#endif
|
|
|
|
// Inconsistent without intrinsics.
|
|
#if __has_builtin(__is_enum)
|
|
# define FENNEC_HAS_BUILTIN_IS_ENUM 1
|
|
# define FENNEC_BUILTIN_IS_ENUM(arg) __is_enum(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_ENUM 0
|
|
#endif
|
|
|
|
// Inconsistent without intrinsics.
|
|
#if __has_builtin(__is_union)
|
|
# define FENNEC_HAS_BUILTIN_IS_UNION 1
|
|
# define FENNEC_BUILTIN_IS_UNION(arg) __is_union(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_UNION 0
|
|
#endif
|
|
|
|
// Inconsistent without intrinsics
|
|
#if __has_builtin(__is_final)
|
|
# define FENNEC_HAS_BUILTIN_IS_FINAL 1
|
|
# define FENNEC_BUILTIN_IS_FINAL(arg) __is_final(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_FINAL 0
|
|
#endif
|
|
|
|
// Inconsistent without intrinsics
|
|
#if __has_builtin(__is_aggregate)
|
|
# define FENNEC_HAS_BUILTIN_IS_AGGREGATE 1
|
|
# define FENNEC_BUILTIN_IS_AGGREGATE(arg) __is_aggregate(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_AGGREGATE 0
|
|
#endif
|
|
|
|
// Inconsistent without intrinsics
|
|
#if __has_builtin(__builtin_is_implicit_lifetime)
|
|
# define FENNEC_HAS_BUILTIN_IS_IMPLICIT_LIFETIME 1
|
|
# define FENNEC_BUILTIN_IS_IMPLICIT_LIFETIME(arg) __builtin_is_implicit_lifetime(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_IMPLICIT_LIFETIME 0
|
|
#endif
|
|
|
|
// Inconsistent without intrinsics
|
|
#if __has_builtin(__is_function)
|
|
# define FENNEC_HAS_BUILTIN_IS_FUNCTION 1
|
|
# define FENNEC_BUILTIN_IS_FUNCTION(arg) __is_function(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_FUNCTION 0
|
|
#endif
|
|
|
|
// Inconsistent without intrinsics
|
|
#if __has_builtin(__is_object)
|
|
# define FENNEC_HAS_BUILTIN_IS_OBJECT 1
|
|
# define FENNEC_BUILTIN_IS_OBJECT(arg) __is_object(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_FUNCTION 0
|
|
#endif
|
|
|
|
// Inconsistent without intrinsics
|
|
#if __has_builtin(__is_polymorphic)
|
|
# define FENNEC_HAS_BUILTIN_IS_POLYMORPHIC 1
|
|
# define FENNEC_BUILTIN_IS_POLYMORPHIC(arg) __is_polymorphic(arg)
|
|
#else
|
|
# define FENNEC_HAS_BUILTIN_IS_POLYMORPHIC 0
|
|
#endif
|
|
|
|
|
|
// For compilers without or differently named builtins
|
|
#else
|
|
|
|
// TODO: More compiler support
|
|
|
|
#if FENNEC_COMPILER_MSVC
|
|
|
|
# define FENNEC_HAS_BUILTIN_ADDRESS_OF 1
|
|
# define FENNEC_BUILTIN_ADDRESS_OF(arg) __builtin_addressof(arg)
|
|
|
|
# define FENNEC_HAS_BUILTIN_BIT_CAST 1
|
|
# define FENNEC_BUILTIN_BIT_CAST(type, arg) __builtin_bit_cast(type, arg)
|
|
|
|
# define FENNEC_HAS_BUILTIN_IS_CONVERTIBLE 1
|
|
# define FENNEC_BUILTIN_IS_CONVERTIBLE(arg0, arg1) __is_convertible_to(arg0, arg1)
|
|
|
|
# define FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE 1
|
|
# define FENNEC_BUILTIN_IS_CONSTRUCTIBLE(...) __is_constructible(__VA_ARGS__)
|
|
|
|
# define FENNEC_HAS_BUILTIN_IS_EMPTY 1
|
|
# define FENNEC_BUILTIN_IS_EMPTY(arg) __is_empty(arg)
|
|
|
|
# define FENNEC_HAS_BUILTIN_IS_FINAL 1
|
|
# define FENNEC_BUILTIN_IS_FINAL(arg) __is_final(arg)
|
|
|
|
# define FENNEC_HAS_BUILTIN_IS_POLYMORPHIC 1
|
|
# define FENNEC_BUILTIN_IS_POLYMORPHIC(arg) __is_polymorphic(arg)
|
|
|
|
# define FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT 1
|
|
# define FENNEC_BUILTIN_IS_STANDARD_LAYOUT(arg) __is_standard_layout(arg)
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#endif // FENNEC_LANG_INTRINSICS_H
|