From fbde9e60d92b7dd2e51c8235575625f6bb5f843b Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Tue, 3 Mar 2026 15:06:43 -0400 Subject: [PATCH 1/4] Add a `SOURCEMETA_FORCEINLINE` helper macro Signed-off-by: Juan Cruz Viotti --- .github/workflows/website-build.yml | 1 + .github/workflows/website-deploy.yml | 1 + CMakeLists.txt | 5 + config.cmake.in | 7 +- src/core/json/CMakeLists.txt | 1 + src/core/json/include/sourcemeta/core/json.h | 6 +- .../json/include/sourcemeta/core/json_value.h | 110 ++++++++++-------- src/lang/numeric/CMakeLists.txt | 1 + .../include/sourcemeta/core/numeric_decimal.h | 25 ++-- src/lang/preprocessor/CMakeLists.txt | 5 + .../include/sourcemeta/core/preprocessor.h | 12 ++ test/packaging/find_package/CMakeLists.txt | 1 + test/packaging/find_package/hello.cc | 1 + 13 files changed, 113 insertions(+), 63 deletions(-) create mode 100644 src/lang/preprocessor/CMakeLists.txt create mode 100644 src/lang/preprocessor/include/sourcemeta/core/preprocessor.h diff --git a/.github/workflows/website-build.yml b/.github/workflows/website-build.yml index 7c8b82417..9ef45fbc6 100644 --- a/.github/workflows/website-build.yml +++ b/.github/workflows/website-build.yml @@ -16,6 +16,7 @@ jobs: - run: > cmake -S . -B ./build -DCMAKE_BUILD_TYPE:STRING=Release + -DSOURCEMETA_CORE_LANG_PREPROCESSOR:BOOL=OFF -DSOURCEMETA_CORE_LANG_IO:BOOL=OFF -DSOURCEMETA_CORE_LANG_PROCESS:BOOL=OFF -DSOURCEMETA_CORE_LANG_PARALLEL:BOOL=OFF diff --git a/.github/workflows/website-deploy.yml b/.github/workflows/website-deploy.yml index 136f5ce1b..ade171179 100644 --- a/.github/workflows/website-deploy.yml +++ b/.github/workflows/website-deploy.yml @@ -26,6 +26,7 @@ jobs: - run: > cmake -S . -B ./build -DCMAKE_BUILD_TYPE:STRING=Release + -DSOURCEMETA_CORE_LANG_PREPROCESSOR:BOOL=OFF -DSOURCEMETA_CORE_LANG_IO:BOOL=OFF -DSOURCEMETA_CORE_LANG_PROCESS:BOOL=OFF -DSOURCEMETA_CORE_LANG_PARALLEL:BOOL=OFF diff --git a/CMakeLists.txt b/CMakeLists.txt index bb9d77ad4..19f9ba906 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ project(core VERSION 0.0.0 LANGUAGES C CXX ASM_MASM DESCRIPTION "Sourcemeta Core list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") # Options +option(SOURCEMETA_CORE_LANG_PREPROCESSOR "Build the Sourcemeta Core language preprocessor library" ON) option(SOURCEMETA_CORE_LANG_IO "Build the Sourcemeta Core language I/O library" ON) option(SOURCEMETA_CORE_LANG_PROCESS "Build the Sourcemeta Core language Process library" ON) option(SOURCEMETA_CORE_LANG_PARALLEL "Build the Sourcemeta Core language parallel library" ON) @@ -58,6 +59,10 @@ if(SOURCEMETA_CORE_INSTALL) COMPONENT sourcemeta_${PROJECT_NAME}_dev) endif() +if(SOURCEMETA_CORE_LANG_PREPROCESSOR) + add_subdirectory(src/lang/preprocessor) +endif() + if(SOURCEMETA_CORE_LANG_IO) add_subdirectory(src/lang/io) endif() diff --git a/config.cmake.in b/config.cmake.in index 9c5babb64..8bb3991ae 100644 --- a/config.cmake.in +++ b/config.cmake.in @@ -4,6 +4,7 @@ list(APPEND SOURCEMETA_CORE_COMPONENTS ${Core_FIND_COMPONENTS}) list(APPEND SOURCEMETA_CORE_COMPONENTS ${core_FIND_COMPONENTS}) if(NOT SOURCEMETA_CORE_COMPONENTS) + list(APPEND SOURCEMETA_CORE_COMPONENTS preprocessor) list(APPEND SOURCEMETA_CORE_COMPONENTS io) list(APPEND SOURCEMETA_CORE_COMPONENTS process) list(APPEND SOURCEMETA_CORE_COMPONENTS parallel) @@ -29,7 +30,9 @@ endif() include(CMakeFindDependencyMacro) foreach(component ${SOURCEMETA_CORE_COMPONENTS}) - if(component STREQUAL "io") + if(component STREQUAL "preprocessor") + include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_preprocessor.cmake") + elseif(component STREQUAL "io") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_io.cmake") elseif(component STREQUAL "process") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_process.cmake") @@ -37,6 +40,7 @@ foreach(component ${SOURCEMETA_CORE_COMPONENTS}) find_dependency(Threads) include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_parallel.cmake") elseif(component STREQUAL "numeric") + include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_preprocessor.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_numeric.cmake") elseif(component STREQUAL "unicode") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_unicode.cmake") @@ -59,6 +63,7 @@ foreach(component ${SOURCEMETA_CORE_COMPONENTS}) include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_io.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_uritemplate.cmake") elseif(component STREQUAL "json") + include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_preprocessor.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_numeric.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_io.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_unicode.cmake") diff --git a/src/core/json/CMakeLists.txt b/src/core/json/CMakeLists.txt index ff9466787..a9c059067 100644 --- a/src/core/json/CMakeLists.txt +++ b/src/core/json/CMakeLists.txt @@ -9,3 +9,4 @@ endif() target_link_libraries(sourcemeta_core_json PRIVATE sourcemeta::core::io) target_link_libraries(sourcemeta_core_json PRIVATE sourcemeta::core::unicode) target_link_libraries(sourcemeta_core_json PUBLIC sourcemeta::core::numeric) +target_link_libraries(sourcemeta_core_json PUBLIC sourcemeta::core::preprocessor) diff --git a/src/core/json/include/sourcemeta/core/json.h b/src/core/json/include/sourcemeta/core/json.h index 1052e7ca1..160afa0b3 100644 --- a/src/core/json/include/sourcemeta/core/json.h +++ b/src/core/json/include/sourcemeta/core/json.h @@ -11,6 +11,8 @@ #include // NOLINTEND(misc-include-cleaner) +#include + #include // std::uint64_t #include // std::filesystem #include // std::basic_ifstream @@ -228,8 +230,8 @@ auto operator<<(std::basic_ostream &stream, /// {sourcemeta::core::JSON::Type::Object, /// sourcemeta::core::JSON::Type::Array}); /// ``` -SOURCEMETA_CORE_JSON_EXPORT -auto make_set(std::initializer_list types) -> JSON::TypeSet; +SOURCEMETA_CORE_JSON_EXPORT SOURCEMETA_FORCEINLINE auto +make_set(std::initializer_list types) -> JSON::TypeSet; } // namespace sourcemeta::core diff --git a/src/core/json/include/sourcemeta/core/json_value.h b/src/core/json/include/sourcemeta/core/json_value.h index 95aa47086..b4fe44883 100644 --- a/src/core/json/include/sourcemeta/core/json_value.h +++ b/src/core/json/include/sourcemeta/core/json_value.h @@ -10,6 +10,7 @@ #include #include +#include #include // std::any_of #include // std::bitset @@ -372,7 +373,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{true}; /// assert(document.is_boolean()); /// ``` - [[nodiscard]] auto is_boolean() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_boolean() const noexcept -> bool; /// Check if the input JSON document is null. For example: /// @@ -383,7 +384,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{nullptr}; /// assert(document.is_null()); /// ``` - [[nodiscard]] auto is_null() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_null() const noexcept -> bool; /// Check if the input JSON document is an integer. For example: /// @@ -394,7 +395,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{5}; /// assert(document.is_integer()); /// ``` - [[nodiscard]] auto is_integer() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_integer() const noexcept -> bool; /// Check if the input JSON document is a real type. For example: /// @@ -405,7 +406,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{3.14}; /// assert(document.is_real()); /// ``` - [[nodiscard]] auto is_real() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_real() const noexcept -> bool; /// Check if the input JSON document is an integer, a real number that /// represents an integer, or an integer decimal. For example: @@ -417,7 +418,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{5.0}; /// assert(document.is_integral()); /// ``` - [[nodiscard]] auto is_integral() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_integral() const noexcept + -> bool; /// Check if the input JSON document is either an integer or a real type. For /// example: @@ -431,7 +433,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(real.is_number()); /// assert(integer.is_number()); /// ``` - [[nodiscard]] auto is_number() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_number() const noexcept -> bool; /// Check if the input JSON document is either a positive integer or a /// positive real number. Zero is considered to be positive. For example: @@ -456,7 +458,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{"foo"}; /// assert(document.is_string()); /// ``` - [[nodiscard]] auto is_string() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_string() const noexcept -> bool; /// Check if the input JSON document is an array. For example: /// @@ -468,7 +470,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// document=sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.is_array()); /// ``` - [[nodiscard]] auto is_array() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_array() const noexcept -> bool; /// Check if the input JSON document is an object. For example: /// @@ -480,7 +482,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// document=sourcemeta::core::parse_json("{ \"foo\": 1 }"); /// assert(document.is_object()); /// ``` - [[nodiscard]] auto is_object() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_object() const noexcept -> bool; /// Check if the input JSON document is an arbitrary precision decimal value. /// For example: @@ -493,7 +495,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{value}; /// assert(document.is_decimal()); /// ``` - [[nodiscard]] auto is_decimal() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_decimal() const noexcept -> bool; /// Get the type of the JSON document. For example: /// @@ -504,7 +506,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{true}; /// assert(document.type() == sourcemeta::core::JSON::Type::Boolean); /// ``` - [[nodiscard]] auto type() const noexcept -> Type; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto type() const noexcept -> Type; /* * Type conversion @@ -521,7 +523,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.is_boolean()); /// assert(document.to_boolean()); /// ``` - [[nodiscard]] auto to_boolean() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_boolean() const noexcept -> bool; /// Convert a JSON instance into a signed integer value. The result of this /// method is undefined unless the JSON instance holds an integer value. For @@ -535,7 +537,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.is_integer()); /// assert(document.to_integer() == 5); /// ``` - [[nodiscard]] auto to_integer() const noexcept -> Integer; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_integer() const noexcept + -> Integer; /// Convert a JSON instance into an IEEE 64-bit floating-point value. The /// result of this method is undefined unless the JSON instance holds a real @@ -549,7 +552,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.is_real()); /// assert(document.to_real() == 3.14); /// ``` - [[nodiscard]] auto to_real() const noexcept -> Real; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_real() const noexcept -> Real; /// Convert a JSON instance into a decimal value. The result of this method /// is undefined unless the JSON instance holds a decimal value. For example: @@ -563,7 +566,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.is_decimal()); /// assert(document.to_decimal().to_int64() == 1234567890); /// ``` - [[nodiscard]] auto to_decimal() const noexcept -> const Decimal &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_decimal() const noexcept + -> const Decimal &; /// Convert a JSON instance into a standard string value. The result of this /// method is undefined unless the JSON instance holds a string value. For @@ -577,7 +581,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.is_string()); /// assert(document.to_string() == "foo"); /// ``` - [[nodiscard]] auto to_string() const noexcept -> const String &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_string() const noexcept + -> const String &; /// Get a standard input string stream from a JSON string. The result of this /// method is undefined unless the JSON instance holds a string value. For @@ -613,7 +618,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// << "\n"; /// }); /// ``` - [[nodiscard]] auto as_array() const noexcept -> const Array &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_array() const noexcept + -> const Array &; /// Get the JSON document as an array instance. This is convenient /// for using mutable iterators on the array. For example: @@ -627,7 +633,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// std::sort(document.as_array().begin(), document.as_array().end()); /// ``` - [[nodiscard]] auto as_array() noexcept -> Array &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_array() noexcept -> Array &; /// Get the JSON document as an object instance. This is convenient /// for using constant iterators on the object. For example: @@ -651,7 +657,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// << "\n"; /// }); /// ``` - [[nodiscard]] auto as_object() noexcept -> Object &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_object() noexcept -> Object &; /// Get the JSON document as an object instance. This is convenient /// for using mutable iterators on the object. For example: @@ -671,7 +677,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// value += sourcemeta::core::JSON{1}; /// } /// ``` - [[nodiscard]] auto as_object() const noexcept -> const Object &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_object() const noexcept + -> const Object &; /// Get the JSON numeric document as a real number if it is not one already. /// For example: @@ -683,7 +690,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{5}; /// assert(document.as_real() == 5.0); /// ``` - [[nodiscard]] auto as_real() const noexcept -> Real; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_real() const noexcept -> Real; /// Get the JSON numeric document as an integer number if it is not one /// already. If the number is a real number, truncation will take place. For @@ -696,7 +703,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{5.3}; /// assert(document.as_integer() == 5); /// ``` - [[nodiscard]] auto as_integer() const noexcept -> Integer; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_integer() const noexcept + -> Integer; /* * Getters @@ -720,8 +728,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("{ \"1\": "foo" }"); /// assert(my_array.at(1).to_string() == "foo"); /// ``` - [[nodiscard]] auto at(const typename Array::size_type index) const - -> const JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto + at(const typename Array::size_type index) const -> const JSON &; /// This method retrieves a element by its index. If the input JSON instance /// is an object, a property that corresponds to the stringified integer will @@ -741,7 +749,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("{ \"1\": "foo" }"); /// assert(my_array.at(1).to_string() == "foo"); /// ``` - [[nodiscard]] auto at(const typename Array::size_type index) -> JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto + at(const typename Array::size_type index) -> JSON &; /// This method retrieves an object element. /// @@ -755,7 +764,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("{ \"foo\": 1, \"bar\": 2 }"); /// assert(my_object.at("bar").to_integer() == 2); /// ``` - [[nodiscard]] auto at(const String &key) const -> const JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto at(const String &key) const + -> const JSON &; /// This method retrieves an object element given a pre-calculated property /// hash. @@ -771,8 +781,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(my_object.at("bar", /// my_object.as_object().hash("bar")).to_integer() == 2); /// ``` - [[nodiscard]] auto at(const String &key, - const typename Object::hash_type hash) const + [[nodiscard]] SOURCEMETA_FORCEINLINE auto + at(const String &key, const typename Object::hash_type hash) const -> const JSON &; /// This method retrieves an object element. @@ -787,7 +797,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("{ \"foo\": 1, \"bar\": 2 }"); /// assert(my_object.at("bar").to_integer() == 2); /// ``` - [[nodiscard]] auto at(const String &key) -> JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto at(const String &key) -> JSON &; /// This method retrieves an object element given a pre-calculated property /// hash. @@ -803,8 +813,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(my_object.at("bar", /// my_object.as_object().hash("bar")).to_integer() == 2); /// ``` - [[nodiscard]] auto at(const String &key, - const typename Object::hash_type hash) -> JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto + at(const String &key, const typename Object::hash_type hash) -> JSON &; /// This method retrieves an object property or a user provided value if such /// property is not defined. @@ -866,7 +876,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.front().to_integer() == 1); /// ``` - [[nodiscard]] auto front() -> JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto front() -> JSON &; /// This method retrieves a reference to the first element of a JSON array. /// This method is undefined if the input JSON instance is an empty array. For @@ -880,7 +890,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.front().to_integer() == 1); /// ``` - [[nodiscard]] auto front() const -> const JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto front() const -> const JSON &; /// This method retrieves a reference to the last element of a JSON array. /// This method is undefined if the input JSON instance is an empty array. For @@ -894,7 +904,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.back().to_integer() == 3); /// ``` - [[nodiscard]] auto back() -> JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto back() -> JSON &; /// This method retrieves a reference to the last element of a JSON array. /// This method is undefined if the input JSON instance is an empty array. For @@ -908,7 +918,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.back().to_integer() == 3); /// ``` - [[nodiscard]] auto back() const -> const JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto back() const -> const JSON &; /* * Read operations @@ -934,7 +944,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(my_array.size() == 2); /// assert(my_string.size() == 3); /// ``` - [[nodiscard]] auto size() const -> std::size_t; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto size() const -> std::size_t; /// If the input JSON instance is a string, return its logical length. /// @@ -947,7 +957,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON my_string{"foo"}; /// assert(my_string.string_size() == 3); /// ``` - [[nodiscard]] auto string_size() const -> std::size_t; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto string_size() const -> std::size_t; /// If the input JSON instance is an array, return its number of elements. /// @@ -961,7 +971,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2 ]"); /// assert(my_array.array_size() == 2); /// ``` - [[nodiscard]] auto array_size() const -> std::size_t; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto array_size() const -> std::size_t; /// If the input JSON instance is an object, return its number of pairs. /// @@ -975,7 +985,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("{ \"foo\": 1 }"); /// assert(my_object.object_size() == 1); /// ``` - [[nodiscard]] auto object_size() const -> std::size_t; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto object_size() const -> std::size_t; /// If the input JSON instance is string, input JSON instance is a string, /// return its number of bytes. For example: @@ -988,7 +998,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("\"\\uD83D\\uDCA9\"")}; /// assert(my_string.size() == 2); /// ``` - [[nodiscard]] auto byte_size() const -> std::size_t; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto byte_size() const -> std::size_t; /// Estimate the byte size occupied by the given parsed JSON instance (not its /// stringified representation). Keep in mind that as the method name implies, @@ -1056,7 +1066,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(my_array.empty()); /// assert(my_string.empty()); /// ``` - [[nodiscard]] auto empty() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto empty() const -> bool; /// This method checks whether an input JSON object defines a specific key /// and returns the value if it does. For example: @@ -1071,7 +1081,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const auto result = document.try_at("foo"); /// EXPECT_TRUE(result); /// EXPECT_EQ(result->to_integer(), 1); - [[nodiscard]] auto try_at(const String &key) const -> const JSON *; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto try_at(const String &key) const + -> const JSON *; /// This method checks, given a pre-calculated hash, whether an input JSON /// object defines a specific key and returns the value if it does. For @@ -1088,8 +1099,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// document.as_object().hash("foo")); /// EXPECT_TRUE(result); /// EXPECT_EQ(result->to_integer(), 1); - [[nodiscard]] auto try_at(const String &key, - const typename Object::hash_type hash) const + [[nodiscard]] SOURCEMETA_FORCEINLINE auto + try_at(const String &key, const typename Object::hash_type hash) const -> const JSON *; /// This method checks whether an input JSON object defines a specific key. @@ -1104,7 +1115,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.defines("foo")); /// assert(!document.defines("bar")); /// ``` - [[nodiscard]] auto defines(const String &key) const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto defines(const String &key) const + -> bool; /// This method checks whether an input JSON object defines a specific key /// given a pre-calculated property hash. For example: @@ -1120,8 +1132,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.defines("bar", /// document.as_object().hash("bar"))); /// ``` - [[nodiscard]] auto defines(const String &key, - const typename Object::hash_type hash) const + [[nodiscard]] SOURCEMETA_FORCEINLINE auto + defines(const String &key, const typename Object::hash_type hash) const -> bool; /// This method checks whether an input JSON object defines a specific integer @@ -1136,8 +1148,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.defines(0)); /// assert(!document.defines(1)); /// ``` - [[nodiscard]] auto defines(const typename Array::size_type index) const - -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto + defines(const typename Array::size_type index) const -> bool; /// This method checks whether an input JSON object defines at least one given /// key. diff --git a/src/lang/numeric/CMakeLists.txt b/src/lang/numeric/CMakeLists.txt index af9fdaeb5..14ac639f5 100644 --- a/src/lang/numeric/CMakeLists.txt +++ b/src/lang/numeric/CMakeLists.txt @@ -6,3 +6,4 @@ if(SOURCEMETA_CORE_INSTALL) sourcemeta_library_install(NAMESPACE sourcemeta PROJECT core NAME numeric) endif() +target_link_libraries(sourcemeta_core_numeric PUBLIC sourcemeta::core::preprocessor) diff --git a/src/lang/numeric/include/sourcemeta/core/numeric_decimal.h b/src/lang/numeric/include/sourcemeta/core/numeric_decimal.h index a55f02e0d..58c470f6b 100644 --- a/src/lang/numeric/include/sourcemeta/core/numeric_decimal.h +++ b/src/lang/numeric/include/sourcemeta/core/numeric_decimal.h @@ -5,6 +5,8 @@ #include #endif +#include + #include // std::integral #include // std::int32_t, std::int64_t, std::uint32_t, std::uint64_t #include // std::string @@ -105,21 +107,21 @@ class SOURCEMETA_CORE_NUMERIC_EXPORT Decimal { [[nodiscard]] auto to_double() const -> double; /// Check if the decimal number is zero - [[nodiscard]] auto is_zero() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_zero() const -> bool; /// Check if the decimal number represents an integer value, which includes a /// number like `3.0` - [[nodiscard]] auto is_integral() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_integral() const -> bool; /// Check if the decimal number represents an integer value _without_ a /// decimal component in its original representation. - [[nodiscard]] auto is_integer() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_integer() const -> bool; /// Check if the decimal number is finite - [[nodiscard]] auto is_finite() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_finite() const -> bool; /// Check if the decimal number is a real number (finite and not NaN) - [[nodiscard]] auto is_real() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_real() const -> bool; /// Check if the decimal number can be represented as a 32-bit float without /// precision loss @@ -143,22 +145,23 @@ class SOURCEMETA_CORE_NUMERIC_EXPORT Decimal { /// Check if the decimal number is NaN (Not a Number), either quiet or /// signaling - [[nodiscard]] auto is_nan() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_nan() const -> bool; /// Check if the decimal number is a signaling NaN - [[nodiscard]] auto is_snan() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_snan() const -> bool; /// Check if the decimal number is a quiet NaN - [[nodiscard]] auto is_qnan() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_qnan() const -> bool; /// Get the payload of a NaN value (0 if no payload) - [[nodiscard]] auto nan_payload() const -> std::uint64_t; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto nan_payload() const + -> std::uint64_t; /// Check if the decimal number is infinite - [[nodiscard]] auto is_infinite() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_infinite() const -> bool; /// Check if the decimal number is signed (negative, including -0) - [[nodiscard]] auto is_signed() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_signed() const -> bool; /// Round the decimal number to an integral value [[nodiscard]] auto to_integral() const -> Decimal; diff --git a/src/lang/preprocessor/CMakeLists.txt b/src/lang/preprocessor/CMakeLists.txt new file mode 100644 index 000000000..70215b344 --- /dev/null +++ b/src/lang/preprocessor/CMakeLists.txt @@ -0,0 +1,5 @@ +sourcemeta_library(NAMESPACE sourcemeta PROJECT core NAME preprocessor) + +if(SOURCEMETA_CORE_INSTALL) + sourcemeta_library_install(NAMESPACE sourcemeta PROJECT core NAME preprocessor) +endif() diff --git a/src/lang/preprocessor/include/sourcemeta/core/preprocessor.h b/src/lang/preprocessor/include/sourcemeta/core/preprocessor.h new file mode 100644 index 000000000..550921249 --- /dev/null +++ b/src/lang/preprocessor/include/sourcemeta/core/preprocessor.h @@ -0,0 +1,12 @@ +#ifndef SOURCEMETA_CORE_PREPROCESSOR_H_ +#define SOURCEMETA_CORE_PREPROCESSOR_H_ + +#if defined(__GNUC__) || defined(__clang__) +#define SOURCEMETA_FORCEINLINE [[gnu::always_inline]] +#elif defined(_MSC_VER) +#define SOURCEMETA_FORCEINLINE [[msvc::forceinline]] +#else +#define SOURCEMETA_FORCEINLINE +#endif + +#endif diff --git a/test/packaging/find_package/CMakeLists.txt b/test/packaging/find_package/CMakeLists.txt index 9f65a6d59..0d19bc4ec 100644 --- a/test/packaging/find_package/CMakeLists.txt +++ b/test/packaging/find_package/CMakeLists.txt @@ -23,3 +23,4 @@ target_link_libraries(core_hello PRIVATE sourcemeta::core::html) target_link_libraries(core_hello PRIVATE sourcemeta::core::alterschema) target_link_libraries(core_hello PRIVATE sourcemeta::core::editorschema) target_link_libraries(core_hello PRIVATE sourcemeta::core::options) +target_link_libraries(core_hello PRIVATE sourcemeta::core::preprocessor) diff --git a/test/packaging/find_package/hello.cc b/test/packaging/find_package/hello.cc index 1b96457bb..effdb812e 100644 --- a/test/packaging/find_package/hello.cc +++ b/test/packaging/find_package/hello.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include From c985867d7bd4cf7aefdb870108bbbf6fc4365b54 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Tue, 3 Mar 2026 15:26:00 -0400 Subject: [PATCH 2/4] More Signed-off-by: Juan Cruz Viotti --- .../sourcemeta/core/jsonpointer_pointer.h | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_pointer.h b/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_pointer.h index 413b549ac..69baf5f48 100644 --- a/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_pointer.h +++ b/src/core/jsonpointer/include/sourcemeta/core/jsonpointer_pointer.h @@ -13,6 +13,8 @@ #include // std::move #include // std::vector +#include + namespace sourcemeta::core { /// @ingroup jsonpointer @@ -131,7 +133,7 @@ template class GenericPointer { /// assert(pointer.back().is_property()); /// assert(pointer.back().to_property() == "bar"); /// ``` - [[nodiscard]] auto back() const -> const_reference { + [[nodiscard]] SOURCEMETA_FORCEINLINE auto back() const -> const_reference { assert(!this->empty()); return this->data.back(); } @@ -146,7 +148,7 @@ template class GenericPointer { /// const sourcemeta::core::Pointer pointer{"foo", "bar"}; /// assert(pointer.size() == 2); /// ``` - [[nodiscard]] auto size() const noexcept -> size_type { + [[nodiscard]] SOURCEMETA_FORCEINLINE auto size() const noexcept -> size_type { return this->data.size(); } @@ -162,7 +164,7 @@ template class GenericPointer { /// assert(empty_pointer.empty()); /// assert(!non_empty_pointer.empty()); /// ``` - [[nodiscard]] auto empty() const noexcept -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE auto empty() const noexcept -> bool { return this->data.empty(); } @@ -179,7 +181,8 @@ template class GenericPointer { /// assert(!pointer.empty()); /// assert(token.is_property()); /// ``` - template auto emplace_back(Args &&...args) -> reference { + template + SOURCEMETA_FORCEINLINE auto emplace_back(Args &&...args) -> reference { return this->data.emplace_back(std::forward(args)...); } @@ -215,7 +218,8 @@ template class GenericPointer { /// assert(pointer.at(1).to_property() == "bar"); /// assert(pointer.at(2).to_property() == "baz"); /// ``` - auto push_back(const GenericPointer &other) -> void { + SOURCEMETA_FORCEINLINE auto + push_back(const GenericPointer &other) -> void { if (other.empty()) { return; } else if (other.size() == 1) { @@ -248,7 +252,8 @@ template class GenericPointer { /// assert(pointer.at(1).to_property() == "bar"); /// assert(pointer.at(2).to_property() == "baz"); /// ``` - auto push_back(GenericPointer &&other) -> void { + SOURCEMETA_FORCEINLINE auto push_back(GenericPointer &&other) + -> void { if (other.empty()) { return; } else if (other.size() == 1) { @@ -284,7 +289,8 @@ template class GenericPointer { /// assert(pointer.at(2).to_property() == "baz"); /// ``` template - auto push_back(const GenericPointer &other) -> void + SOURCEMETA_FORCEINLINE auto + push_back(const GenericPointer &other) -> void requires std::is_same_v> { if (other.empty()) { @@ -328,7 +334,8 @@ template class GenericPointer { /// assert(pointer.at(0).to_property() == "foo"); /// assert(pointer.at(1).to_property() == "bar"); /// ``` - auto push_back(const typename Token::Property &property) -> void { + SOURCEMETA_FORCEINLINE auto + push_back(const typename Token::Property &property) -> void { this->data.emplace_back(property); } @@ -349,7 +356,8 @@ template class GenericPointer { /// assert(pointer.at(0).to_property() == "foo"); /// assert(pointer.at(1).to_property() == "bar"); /// ``` - auto push_back(typename Token::Property &&property) -> void { + SOURCEMETA_FORCEINLINE auto push_back(typename Token::Property &&property) + -> void { this->data.emplace_back(std::move(property)); } @@ -371,7 +379,8 @@ template class GenericPointer { /// assert(pointer.at(0).to_property() == "foo"); /// assert(pointer.at(1).to_index() == 0); /// ``` - auto push_back(const typename Token::Index &index) -> void { + SOURCEMETA_FORCEINLINE auto push_back(const typename Token::Index &index) + -> void { this->data.emplace_back(index); } From 6186a7be5251a8803ea108a0a422eb45b95dcf0e Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Tue, 3 Mar 2026 15:46:59 -0400 Subject: [PATCH 3/4] More Signed-off-by: Juan Cruz Viotti --- src/core/json/include/sourcemeta/core/json.h | 10 +- .../json/include/sourcemeta/core/json_value.h | 253 ++++++++++++++--- src/core/json/json.cc | 8 - src/core/json/json_value.cc | 262 +----------------- src/lang/numeric/decimal.cc | 35 --- .../include/sourcemeta/core/numeric_decimal.h | 47 +++- 6 files changed, 255 insertions(+), 360 deletions(-) diff --git a/src/core/json/include/sourcemeta/core/json.h b/src/core/json/include/sourcemeta/core/json.h index 160afa0b3..239299f60 100644 --- a/src/core/json/include/sourcemeta/core/json.h +++ b/src/core/json/include/sourcemeta/core/json.h @@ -230,8 +230,14 @@ auto operator<<(std::basic_ostream &stream, /// {sourcemeta::core::JSON::Type::Object, /// sourcemeta::core::JSON::Type::Array}); /// ``` -SOURCEMETA_CORE_JSON_EXPORT SOURCEMETA_FORCEINLINE auto -make_set(std::initializer_list types) -> JSON::TypeSet; +SOURCEMETA_FORCEINLINE inline auto +make_set(std::initializer_list types) -> JSON::TypeSet { + JSON::TypeSet result; + for (const auto type : types) { + result.set(static_cast(type)); + } + return result; +} } // namespace sourcemeta::core diff --git a/src/core/json/include/sourcemeta/core/json_value.h b/src/core/json/include/sourcemeta/core/json_value.h index b4fe44883..69027a2a7 100644 --- a/src/core/json/include/sourcemeta/core/json_value.h +++ b/src/core/json/include/sourcemeta/core/json_value.h @@ -15,6 +15,7 @@ #include // std::any_of #include // std::bitset #include // assert +#include // std::modf, std::trunc, std::isinf, std::isnan #include // std::size_t #include // std::int64_t, std::uint8_t #include // std::less, std::reference_wrapper, std::function @@ -373,7 +374,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{true}; /// assert(document.is_boolean()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_boolean() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_boolean() const noexcept + -> bool { + return this->current_type == Type::Boolean; + } /// Check if the input JSON document is null. For example: /// @@ -384,7 +388,9 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{nullptr}; /// assert(document.is_null()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_null() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_null() const noexcept -> bool { + return this->current_type == Type::Null; + } /// Check if the input JSON document is an integer. For example: /// @@ -395,7 +401,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{5}; /// assert(document.is_integer()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_integer() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_integer() const noexcept + -> bool { + return this->current_type == Type::Integer; + } /// Check if the input JSON document is a real type. For example: /// @@ -406,7 +415,9 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{3.14}; /// assert(document.is_real()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_real() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_real() const noexcept -> bool { + return this->current_type == Type::Real; + } /// Check if the input JSON document is an integer, a real number that /// represents an integer, or an integer decimal. For example: @@ -419,7 +430,20 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.is_integral()); /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_integral() const noexcept - -> bool; + -> bool { + switch (this->type()) { + case Type::Integer: + return true; + case Type::Real: { + Real integral_part = 0.0; + return std::modf(this->to_real(), &integral_part) == 0.0; + } + case Type::Decimal: + return this->to_decimal().is_integral(); + default: + return false; + } + } /// Check if the input JSON document is either an integer or a real type. For /// example: @@ -433,7 +457,9 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(real.is_number()); /// assert(integer.is_number()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_number() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_number() const noexcept -> bool { + return this->is_integer() || this->is_real() || this->is_decimal(); + } /// Check if the input JSON document is either a positive integer or a /// positive real number. Zero is considered to be positive. For example: @@ -458,7 +484,9 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{"foo"}; /// assert(document.is_string()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_string() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_string() const noexcept -> bool { + return this->current_type == Type::String; + } /// Check if the input JSON document is an array. For example: /// @@ -470,7 +498,9 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// document=sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.is_array()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_array() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_array() const noexcept -> bool { + return this->current_type == Type::Array; + } /// Check if the input JSON document is an object. For example: /// @@ -482,7 +512,9 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// document=sourcemeta::core::parse_json("{ \"foo\": 1 }"); /// assert(document.is_object()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_object() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_object() const noexcept -> bool { + return this->current_type == Type::Object; + } /// Check if the input JSON document is an arbitrary precision decimal value. /// For example: @@ -495,7 +527,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{value}; /// assert(document.is_decimal()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_decimal() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_decimal() const noexcept + -> bool { + return this->current_type == Type::Decimal; + } /// Get the type of the JSON document. For example: /// @@ -506,7 +541,9 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{true}; /// assert(document.type() == sourcemeta::core::JSON::Type::Boolean); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto type() const noexcept -> Type; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto type() const noexcept -> Type { + return this->current_type; + } /* * Type conversion @@ -523,7 +560,11 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.is_boolean()); /// assert(document.to_boolean()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_boolean() const noexcept -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_boolean() const noexcept + -> bool { + assert(this->is_boolean()); + return this->data_boolean; + } /// Convert a JSON instance into a signed integer value. The result of this /// method is undefined unless the JSON instance holds an integer value. For @@ -538,7 +579,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.to_integer() == 5); /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_integer() const noexcept - -> Integer; + -> Integer { + assert(this->is_integer()); + return this->data_integer; + } /// Convert a JSON instance into an IEEE 64-bit floating-point value. The /// result of this method is undefined unless the JSON instance holds a real @@ -552,7 +596,12 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.is_real()); /// assert(document.to_real() == 3.14); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_real() const noexcept -> Real; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_real() const noexcept -> Real { + assert(this->is_real()); + assert(!std::isinf(this->data_real)); + assert(!std::isnan(this->data_real)); + return this->data_real; + } /// Convert a JSON instance into a decimal value. The result of this method /// is undefined unless the JSON instance holds a decimal value. For example: @@ -567,7 +616,12 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.to_decimal().to_int64() == 1234567890); /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_decimal() const noexcept - -> const Decimal &; + -> const Decimal & { + assert(this->is_decimal()); + assert(this->data_decimal->is_finite()); + assert(!this->data_decimal->is_nan()); + return *this->data_decimal; + } /// Convert a JSON instance into a standard string value. The result of this /// method is undefined unless the JSON instance holds a string value. For @@ -582,7 +636,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.to_string() == "foo"); /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_string() const noexcept - -> const String &; + -> const String & { + assert(this->is_string()); + return this->data_string; + } /// Get a standard input string stream from a JSON string. The result of this /// method is undefined unless the JSON instance holds a string value. For @@ -619,7 +676,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// }); /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_array() const noexcept - -> const Array &; + -> const Array & { + assert(this->is_array()); + return this->data_array; + } /// Get the JSON document as an array instance. This is convenient /// for using mutable iterators on the array. For example: @@ -633,7 +693,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// std::sort(document.as_array().begin(), document.as_array().end()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_array() noexcept -> Array &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_array() noexcept -> Array & { + assert(this->is_array()); + return this->data_array; + } /// Get the JSON document as an object instance. This is convenient /// for using constant iterators on the object. For example: @@ -657,7 +720,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// << "\n"; /// }); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_object() noexcept -> Object &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_object() noexcept -> Object & { + assert(this->is_object()); + return this->data_object; + } /// Get the JSON document as an object instance. This is convenient /// for using mutable iterators on the object. For example: @@ -678,7 +744,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// } /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_object() const noexcept - -> const Object &; + -> const Object & { + assert(this->is_object()); + return this->data_object; + } /// Get the JSON numeric document as a real number if it is not one already. /// For example: @@ -690,7 +759,11 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{5}; /// assert(document.as_real() == 5.0); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_real() const noexcept -> Real; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_real() const noexcept -> Real { + assert(this->is_number()); + return this->is_real() ? this->to_real() + : static_cast(this->to_integer()); + } /// Get the JSON numeric document as an integer number if it is not one /// already. If the number is a real number, truncation will take place. For @@ -704,7 +777,14 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.as_integer() == 5); /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_integer() const noexcept - -> Integer; + -> Integer { + assert(this->is_number()); + if (this->is_integer()) { + return this->to_integer(); + } else { + return static_cast(std::trunc(this->to_real())); + } + } /* * Getters @@ -729,7 +809,11 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(my_array.at(1).to_string() == "foo"); /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto - at(const typename Array::size_type index) const -> const JSON &; + at(const typename Array::size_type index) const -> const JSON & { + assert(this->is_array()); + assert(index < this->size()); + return this->data_array.data.at(index); + } /// This method retrieves a element by its index. If the input JSON instance /// is an object, a property that corresponds to the stringified integer will @@ -750,7 +834,11 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(my_array.at(1).to_string() == "foo"); /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto - at(const typename Array::size_type index) -> JSON &; + at(const typename Array::size_type index) -> JSON & { + assert(this->is_array()); + assert(index < this->size()); + return this->data_array.data.at(index); + } /// This method retrieves an object element. /// @@ -765,7 +853,12 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(my_object.at("bar").to_integer() == 2); /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto at(const String &key) const - -> const JSON &; + -> const JSON & { + assert(this->is_object()); + assert(this->defines(key)); + const auto &object{this->data_object}; + return object.at(key, object.hash(key)); + } /// This method retrieves an object element given a pre-calculated property /// hash. @@ -783,7 +876,11 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto at(const String &key, const typename Object::hash_type hash) const - -> const JSON &; + -> const JSON & { + assert(this->is_object()); + assert(this->defines(key)); + return this->data_object.at(key, hash); + } /// This method retrieves an object element. /// @@ -797,7 +894,12 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("{ \"foo\": 1, \"bar\": 2 }"); /// assert(my_object.at("bar").to_integer() == 2); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto at(const String &key) -> JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto at(const String &key) -> JSON & { + assert(this->is_object()); + assert(this->defines(key)); + auto &object{this->data_object}; + return object.at(key, object.hash(key)); + } /// This method retrieves an object element given a pre-calculated property /// hash. @@ -814,7 +916,11 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// my_object.as_object().hash("bar")).to_integer() == 2); /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto - at(const String &key, const typename Object::hash_type hash) -> JSON &; + at(const String &key, const typename Object::hash_type hash) -> JSON & { + assert(this->is_object()); + assert(this->defines(key)); + return this->data_object.at(key, hash); + } /// This method retrieves an object property or a user provided value if such /// property is not defined. @@ -876,7 +982,11 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.front().to_integer() == 1); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto front() -> JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto front() -> JSON & { + assert(this->is_array()); + assert(!this->empty()); + return this->data_array.data.front(); + } /// This method retrieves a reference to the first element of a JSON array. /// This method is undefined if the input JSON instance is an empty array. For @@ -890,7 +1000,11 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.front().to_integer() == 1); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto front() const -> const JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto front() const -> const JSON & { + assert(this->is_array()); + assert(!this->empty()); + return this->data_array.data.front(); + } /// This method retrieves a reference to the last element of a JSON array. /// This method is undefined if the input JSON instance is an empty array. For @@ -904,7 +1018,11 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.back().to_integer() == 3); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto back() -> JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto back() -> JSON & { + assert(this->is_array()); + assert(!this->empty()); + return this->data_array.data.back(); + } /// This method retrieves a reference to the last element of a JSON array. /// This method is undefined if the input JSON instance is an empty array. For @@ -918,7 +1036,11 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.back().to_integer() == 3); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto back() const -> const JSON &; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto back() const -> const JSON & { + assert(this->is_array()); + assert(!this->empty()); + return this->data_array.data.back(); + } /* * Read operations @@ -944,7 +1066,15 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(my_array.size() == 2); /// assert(my_string.size() == 3); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto size() const -> std::size_t; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto size() const -> std::size_t { + if (this->is_object()) { + return this->object_size(); + } else if (this->is_array()) { + return this->array_size(); + } else { + return this->string_size(); + } + } /// If the input JSON instance is a string, return its logical length. /// @@ -957,7 +1087,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON my_string{"foo"}; /// assert(my_string.string_size() == 3); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto string_size() const -> std::size_t; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto string_size() const -> std::size_t { + assert(this->is_string()); + return JSON::size(this->data_string); + } /// If the input JSON instance is an array, return its number of elements. /// @@ -971,7 +1104,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2 ]"); /// assert(my_array.array_size() == 2); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto array_size() const -> std::size_t; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto array_size() const -> std::size_t { + assert(this->is_array()); + return this->data_array.data.size(); + } /// If the input JSON instance is an object, return its number of pairs. /// @@ -985,7 +1121,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("{ \"foo\": 1 }"); /// assert(my_object.object_size() == 1); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto object_size() const -> std::size_t; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto object_size() const -> std::size_t { + assert(this->is_object()); + return this->data_object.size(); + } /// If the input JSON instance is string, input JSON instance is a string, /// return its number of bytes. For example: @@ -998,7 +1137,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("\"\\uD83D\\uDCA9\"")}; /// assert(my_string.size() == 2); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto byte_size() const -> std::size_t; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto byte_size() const -> std::size_t { + assert(this->is_string()); + return this->data_string.size(); + } /// Estimate the byte size occupied by the given parsed JSON instance (not its /// stringified representation). Keep in mind that as the method name implies, @@ -1066,7 +1208,15 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(my_array.empty()); /// assert(my_string.empty()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto empty() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto empty() const -> bool { + if (this->is_object()) { + return this->data_object.empty(); + } else if (this->is_array()) { + return this->data_array.data.empty(); + } else { + return this->data_string.empty(); + } + } /// This method checks whether an input JSON object defines a specific key /// and returns the value if it does. For example: @@ -1082,7 +1232,11 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// EXPECT_TRUE(result); /// EXPECT_EQ(result->to_integer(), 1); [[nodiscard]] SOURCEMETA_FORCEINLINE auto try_at(const String &key) const - -> const JSON *; + -> const JSON * { + assert(this->is_object()); + const auto &object{this->data_object}; + return object.try_at(key, object.hash(key)); + } /// This method checks, given a pre-calculated hash, whether an input JSON /// object defines a specific key and returns the value if it does. For @@ -1101,7 +1255,11 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// EXPECT_EQ(result->to_integer(), 1); [[nodiscard]] SOURCEMETA_FORCEINLINE auto try_at(const String &key, const typename Object::hash_type hash) const - -> const JSON *; + -> const JSON * { + assert(this->is_object()); + const auto &object{this->data_object}; + return object.try_at(key, hash); + } /// This method checks whether an input JSON object defines a specific key. /// For example: @@ -1116,7 +1274,11 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(!document.defines("bar")); /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto defines(const String &key) const - -> bool; + -> bool { + assert(this->is_object()); + const auto &object{this->data_object}; + return object.defines(key, object.hash(key)); + } /// This method checks whether an input JSON object defines a specific key /// given a pre-calculated property hash. For example: @@ -1134,7 +1296,10 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto defines(const String &key, const typename Object::hash_type hash) const - -> bool; + -> bool { + assert(this->is_object()); + return this->data_object.defines(key, hash); + } /// This method checks whether an input JSON object defines a specific integer /// key. For example: @@ -1149,7 +1314,9 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(!document.defines(1)); /// ``` [[nodiscard]] SOURCEMETA_FORCEINLINE auto - defines(const typename Array::size_type index) const -> bool; + defines(const typename Array::size_type index) const -> bool { + return this->defines(std::to_string(index)); + } /// This method checks whether an input JSON object defines at least one given /// key. diff --git a/src/core/json/json.cc b/src/core/json/json.cc index 39f0a4095..81abcdd8d 100644 --- a/src/core/json/json.cc +++ b/src/core/json/json.cc @@ -161,12 +161,4 @@ auto operator<<(std::basic_ostream &stream, } } -auto make_set(std::initializer_list types) -> JSON::TypeSet { - JSON::TypeSet result; - for (const auto type : types) { - result.set(static_cast(type)); - } - return result; -} - } // namespace sourcemeta::core diff --git a/src/core/json/json_value.cc b/src/core/json/json_value.cc index e127ae252..1d5bf2a9c 100644 --- a/src/core/json/json_value.cc +++ b/src/core/json/json_value.cc @@ -3,7 +3,7 @@ #include // std::find #include // assert -#include // std::isinf, std::isnan, std::modf, std::trunc +#include // std::isinf, std::isnan, std::modf #include // std::size_t #include // std::int64_t #include // std::reference_wrapper @@ -417,41 +417,6 @@ auto JSON::operator-=(const JSON &substractive) -> JSON & { return *this = *this - substractive; } -[[nodiscard]] auto JSON::is_boolean() const noexcept -> bool { - return this->current_type == Type::Boolean; -} - -[[nodiscard]] auto JSON::is_null() const noexcept -> bool { - return this->current_type == Type::Null; -} - -[[nodiscard]] auto JSON::is_integer() const noexcept -> bool { - return this->current_type == Type::Integer; -} - -[[nodiscard]] auto JSON::is_real() const noexcept -> bool { - return this->current_type == Type::Real; -} - -[[nodiscard]] auto JSON::is_integral() const noexcept -> bool { - switch (this->type()) { - case Type::Integer: - return true; - case Type::Real: { - Real integral = 0.0; - return std::modf(this->to_real(), &integral) == 0.0; - } - case Type::Decimal: - return this->to_decimal().is_integral(); - default: - return false; - } -} - -[[nodiscard]] auto JSON::is_number() const noexcept -> bool { - return this->is_integer() || this->is_real() || this->is_decimal(); -} - [[nodiscard]] auto JSON::is_positive() const noexcept -> bool { switch (this->type()) { case Type::Integer: @@ -465,141 +430,12 @@ auto JSON::operator-=(const JSON &substractive) -> JSON & { } } -[[nodiscard]] auto JSON::is_string() const noexcept -> bool { - return this->current_type == Type::String; -} - -[[nodiscard]] auto JSON::is_array() const noexcept -> bool { - return this->current_type == Type::Array; -} - -[[nodiscard]] auto JSON::is_object() const noexcept -> bool { - return this->current_type == Type::Object; -} - -[[nodiscard]] auto JSON::is_decimal() const noexcept -> bool { - return this->current_type == Type::Decimal; -} - -[[nodiscard]] auto JSON::type() const noexcept -> Type { - return this->current_type; -} - -[[nodiscard]] auto JSON::to_boolean() const noexcept -> bool { - assert(this->is_boolean()); - return this->data_boolean; -} - -[[nodiscard]] auto JSON::to_integer() const noexcept -> Integer { - assert(this->is_integer()); - return this->data_integer; -} - -[[nodiscard]] auto JSON::to_real() const noexcept -> Real { - assert(this->is_real()); - // This MUST not happen - assert(!std::isinf(this->data_real)); - assert(!std::isnan(this->data_real)); - return this->data_real; -} - -[[nodiscard]] auto JSON::to_decimal() const noexcept -> const Decimal & { - assert(this->is_decimal()); - // This MUST not happen - assert(this->data_decimal->is_finite()); - assert(!this->data_decimal->is_nan()); - return *this->data_decimal; -} - -[[nodiscard]] auto JSON::to_string() const noexcept -> const JSON::String & { - assert(this->is_string()); - return this->data_string; -} - [[nodiscard]] auto JSON::to_stringstream() const -> std::basic_istringstream> { return std::basic_istringstream>{ this->data_string}; } -[[nodiscard]] auto JSON::as_array() const noexcept -> const JSON::Array & { - assert(this->is_array()); - return this->data_array; -} - -[[nodiscard]] auto JSON::as_array() noexcept -> JSON::Array & { - assert(this->is_array()); - return this->data_array; -} - -[[nodiscard]] auto JSON::as_object() noexcept -> Object & { - assert(this->is_object()); - return this->data_object; -} - -[[nodiscard]] auto JSON::as_object() const noexcept -> const Object & { - assert(this->is_object()); - return this->data_object; -} - -[[nodiscard]] auto JSON::as_real() const noexcept -> Real { - assert(this->is_number()); - return this->is_real() ? this->to_real() - : static_cast(this->to_integer()); -} - -[[nodiscard]] auto JSON::as_integer() const noexcept -> Integer { - assert(this->is_number()); - if (this->is_integer()) { - return this->to_integer(); - } else { - return static_cast(std::trunc(this->to_real())); - } -} - -[[nodiscard]] auto JSON::at(const typename JSON::Array::size_type index) const - -> const JSON & { - assert(this->is_array()); - assert(index < this->size()); - return data_array.data.at(index); -} - -[[nodiscard]] auto JSON::at(const typename JSON::Array::size_type index) - -> JSON & { - assert(this->is_array()); - assert(index < this->size()); - return this->data_array.data.at(index); -} - -[[nodiscard]] auto JSON::at(const JSON::String &key) const -> const JSON & { - assert(this->is_object()); - assert(this->defines(key)); - const auto &object{this->data_object}; - return object.at(key, object.hash(key)); -} - -[[nodiscard]] auto JSON::at(const String &key, - const typename Object::hash_type hash) const - -> const JSON & { - assert(this->is_object()); - assert(this->defines(key)); - return this->data_object.at(key, hash); -} - -[[nodiscard]] auto JSON::at(const JSON::String &key) -> JSON & { - assert(this->is_object()); - assert(this->defines(key)); - auto &object{this->data_object}; - return object.at(key, object.hash(key)); -} - -[[nodiscard]] auto JSON::at(const String &key, - const typename Object::hash_type hash) -> JSON & { - assert(this->is_object()); - assert(this->defines(key)); - return this->data_object.at(key, hash); -} - [[nodiscard]] auto JSON::at_or(const String &key, const typename Object::hash_type hash, const JSON &otherwise) const -> const JSON & { @@ -614,60 +450,6 @@ auto JSON::operator-=(const JSON &substractive) -> JSON & { return this->at_or(key, this->data_object.hash(key), otherwise); } -[[nodiscard]] auto JSON::front() -> JSON & { - assert(this->is_array()); - assert(!this->empty()); - return this->data_array.data.front(); -} - -[[nodiscard]] auto JSON::front() const -> const JSON & { - assert(this->is_array()); - assert(!this->empty()); - return this->data_array.data.front(); -} - -[[nodiscard]] auto JSON::back() -> JSON & { - assert(this->is_array()); - assert(!this->empty()); - return this->data_array.data.back(); -} - -[[nodiscard]] auto JSON::back() const -> const JSON & { - assert(this->is_array()); - assert(!this->empty()); - return this->data_array.data.back(); -} - -[[nodiscard]] auto JSON::size() const -> std::size_t { - if (this->is_object()) { - return this->object_size(); - } else if (this->is_array()) { - return this->array_size(); - } else { - return this->string_size(); - } -} - -[[nodiscard]] auto JSON::string_size() const -> std::size_t { - assert(this->is_string()); - return JSON::size(this->data_string); -} - -[[nodiscard]] auto JSON::array_size() const -> std::size_t { - assert(this->is_array()); - return this->data_array.data.size(); -} - -[[nodiscard]] auto JSON::object_size() const -> std::size_t { - assert(this->is_object()); - return this->data_object.size(); -} - -[[nodiscard]] auto JSON::byte_size() const -> std::size_t { - assert(this->is_string()); - return this->data_string.size(); -} - [[nodiscard]] auto JSON::estimated_byte_size() const -> std::uint64_t { // Of course, container have some overhead of their own // which we are not taking into account here, as its typically @@ -793,48 +575,6 @@ auto JSON::operator-=(const JSON &substractive) -> JSON & { return dividend_decimal.divisible_by(divisor.to_decimal()); } -[[nodiscard]] auto JSON::empty() const -> bool { - if (this->is_object()) { - return this->data_object.empty(); - } else if (this->is_array()) { - return this->data_array.data.empty(); - } else { - return this->data_string.empty(); - } -} - -[[nodiscard]] auto JSON::try_at(const JSON::String &key) const -> const JSON * { - assert(this->is_object()); - const auto &object{this->data_object}; - return object.try_at(key, object.hash(key)); -} - -[[nodiscard]] auto JSON::try_at(const String &key, - const typename Object::hash_type hash) const - -> const JSON * { - assert(this->is_object()); - const auto &object{this->data_object}; - return object.try_at(key, hash); -} - -[[nodiscard]] auto JSON::defines(const JSON::String &key) const -> bool { - assert(this->is_object()); - const auto &object{this->data_object}; - return object.defines(key, object.hash(key)); -} - -[[nodiscard]] auto -JSON::defines(const JSON::String &key, - const typename JSON::Object::hash_type hash) const -> bool { - assert(this->is_object()); - return this->data_object.defines(key, hash); -} - -[[nodiscard]] auto -JSON::defines(const typename JSON::Array::size_type index) const -> bool { - return this->defines(std::to_string(index)); -} - [[nodiscard]] auto JSON::defines_any(std::initializer_list keys) const -> bool { return this->defines_any(keys.begin(), keys.end()); diff --git a/src/lang/numeric/decimal.cc b/src/lang/numeric/decimal.cc index 5c941751e..2eeb8cf20 100644 --- a/src/lang/numeric/decimal.cc +++ b/src/lang/numeric/decimal.cc @@ -714,18 +714,6 @@ auto Decimal::is_integral() const -> bool { return exponent >= 0; } -auto Decimal::is_integer() const -> bool { - return this->is_integral() && this->exponent_ >= 0; -} - -auto Decimal::is_finite() const -> bool { - return !(this->flags_ & (FLAG_NAN | FLAG_SNAN | FLAG_INFINITE)); -} - -auto Decimal::is_real() const -> bool { - return this->is_finite() && !this->is_integral(); -} - auto Decimal::is_float() const -> bool { return is_representable_as_floating_point(*this); } @@ -758,29 +746,6 @@ auto Decimal::is_uint64() const -> bool { *this <= Decimal{std::numeric_limits::max()}; } -auto Decimal::is_nan() const -> bool { return (this->flags_ & FLAG_NAN) != 0; } - -auto Decimal::is_snan() const -> bool { - return (this->flags_ & FLAG_SNAN) != 0; -} - -auto Decimal::is_qnan() const -> bool { - return (this->flags_ & FLAG_NAN) != 0 && !(this->flags_ & FLAG_SNAN); -} - -auto Decimal::nan_payload() const -> std::uint64_t { - assert(this->is_nan()); - return static_cast(this->coefficient_); -} - -auto Decimal::is_infinite() const -> bool { - return (this->flags_ & FLAG_INFINITE) != 0; -} - -auto Decimal::is_signed() const -> bool { - return (this->flags_ & FLAG_SIGN) != 0; -} - auto Decimal::to_integral() const -> Decimal { if (!this->is_finite()) { return *this; diff --git a/src/lang/numeric/include/sourcemeta/core/numeric_decimal.h b/src/lang/numeric/include/sourcemeta/core/numeric_decimal.h index 58c470f6b..51f4d79b4 100644 --- a/src/lang/numeric/include/sourcemeta/core/numeric_decimal.h +++ b/src/lang/numeric/include/sourcemeta/core/numeric_decimal.h @@ -7,6 +7,7 @@ #include +#include // assert #include // std::integral #include // std::int32_t, std::int64_t, std::uint32_t, std::uint64_t #include // std::string @@ -107,21 +108,27 @@ class SOURCEMETA_CORE_NUMERIC_EXPORT Decimal { [[nodiscard]] auto to_double() const -> double; /// Check if the decimal number is zero - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_zero() const -> bool; + [[nodiscard]] auto is_zero() const -> bool; /// Check if the decimal number represents an integer value, which includes a /// number like `3.0` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_integral() const -> bool; + [[nodiscard]] auto is_integral() const -> bool; /// Check if the decimal number represents an integer value _without_ a /// decimal component in its original representation. - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_integer() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_integer() const -> bool { + return this->is_integral() && this->exponent_ >= 0; + } /// Check if the decimal number is finite - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_finite() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_finite() const -> bool { + return !(this->flags_ & (FLAG_NAN | FLAG_SNAN | FLAG_INFINITE)); + } /// Check if the decimal number is a real number (finite and not NaN) - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_real() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_real() const -> bool { + return this->is_finite() && !this->is_integral(); + } /// Check if the decimal number can be represented as a 32-bit float without /// precision loss @@ -145,23 +152,36 @@ class SOURCEMETA_CORE_NUMERIC_EXPORT Decimal { /// Check if the decimal number is NaN (Not a Number), either quiet or /// signaling - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_nan() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_nan() const -> bool { + return (this->flags_ & FLAG_NAN) != 0; + } /// Check if the decimal number is a signaling NaN - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_snan() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_snan() const -> bool { + return (this->flags_ & FLAG_SNAN) != 0; + } /// Check if the decimal number is a quiet NaN - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_qnan() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_qnan() const -> bool { + return (this->flags_ & FLAG_NAN) != 0 && !(this->flags_ & FLAG_SNAN); + } /// Get the payload of a NaN value (0 if no payload) [[nodiscard]] SOURCEMETA_FORCEINLINE auto nan_payload() const - -> std::uint64_t; + -> std::uint64_t { + assert(this->is_nan()); + return static_cast(this->coefficient_); + } /// Check if the decimal number is infinite - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_infinite() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_infinite() const -> bool { + return (this->flags_ & FLAG_INFINITE) != 0; + } /// Check if the decimal number is signed (negative, including -0) - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_signed() const -> bool; + [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_signed() const -> bool { + return (this->flags_ & FLAG_SIGN) != 0; + } /// Round the decimal number to an integral value [[nodiscard]] auto to_integral() const -> Decimal; @@ -254,6 +274,11 @@ class SOURCEMETA_CORE_NUMERIC_EXPORT Decimal { [[nodiscard]] auto operator>=(const Decimal &other) const -> bool; private: + static constexpr std::uint8_t FLAG_SIGN = 0x01; + static constexpr std::uint8_t FLAG_NAN = 0x02; + static constexpr std::uint8_t FLAG_SNAN = 0x04; + static constexpr std::uint8_t FLAG_INFINITE = 0x08; + std::int64_t coefficient_{0}; std::uint64_t coefficient_high_{0}; std::int32_t exponent_{0}; From e0511d56655fa792498574c2eb26a4d4c1938e54 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Tue, 3 Mar 2026 15:49:01 -0400 Subject: [PATCH 4/4] More inline Signed-off-by: Juan Cruz Viotti --- .../json/include/sourcemeta/core/json_value.h | 108 ++++++++++-------- .../include/sourcemeta/core/numeric_decimal.h | 18 +-- 2 files changed, 72 insertions(+), 54 deletions(-) diff --git a/src/core/json/include/sourcemeta/core/json_value.h b/src/core/json/include/sourcemeta/core/json_value.h index 69027a2a7..315b1378c 100644 --- a/src/core/json/include/sourcemeta/core/json_value.h +++ b/src/core/json/include/sourcemeta/core/json_value.h @@ -374,7 +374,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{true}; /// assert(document.is_boolean()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_boolean() const noexcept + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_boolean() const noexcept -> bool { return this->current_type == Type::Boolean; } @@ -388,7 +388,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{nullptr}; /// assert(document.is_null()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_null() const noexcept -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_null() const noexcept + -> bool { return this->current_type == Type::Null; } @@ -401,7 +402,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{5}; /// assert(document.is_integer()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_integer() const noexcept + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_integer() const noexcept -> bool { return this->current_type == Type::Integer; } @@ -415,7 +416,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{3.14}; /// assert(document.is_real()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_real() const noexcept -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_real() const noexcept + -> bool { return this->current_type == Type::Real; } @@ -429,7 +431,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{5.0}; /// assert(document.is_integral()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_integral() const noexcept + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_integral() const noexcept -> bool { switch (this->type()) { case Type::Integer: @@ -457,7 +459,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(real.is_number()); /// assert(integer.is_number()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_number() const noexcept -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_number() const noexcept + -> bool { return this->is_integer() || this->is_real() || this->is_decimal(); } @@ -484,7 +487,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{"foo"}; /// assert(document.is_string()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_string() const noexcept -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_string() const noexcept + -> bool { return this->current_type == Type::String; } @@ -498,7 +502,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// document=sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.is_array()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_array() const noexcept -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_array() const noexcept + -> bool { return this->current_type == Type::Array; } @@ -512,7 +517,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// document=sourcemeta::core::parse_json("{ \"foo\": 1 }"); /// assert(document.is_object()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_object() const noexcept -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_object() const noexcept + -> bool { return this->current_type == Type::Object; } @@ -527,7 +533,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{value}; /// assert(document.is_decimal()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_decimal() const noexcept + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_decimal() const noexcept -> bool { return this->current_type == Type::Decimal; } @@ -541,7 +547,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{true}; /// assert(document.type() == sourcemeta::core::JSON::Type::Boolean); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto type() const noexcept -> Type { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto type() const noexcept + -> Type { return this->current_type; } @@ -560,7 +567,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.is_boolean()); /// assert(document.to_boolean()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_boolean() const noexcept + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto to_boolean() const noexcept -> bool { assert(this->is_boolean()); return this->data_boolean; @@ -578,7 +585,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.is_integer()); /// assert(document.to_integer() == 5); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_integer() const noexcept + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto to_integer() const noexcept -> Integer { assert(this->is_integer()); return this->data_integer; @@ -596,7 +603,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.is_real()); /// assert(document.to_real() == 3.14); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_real() const noexcept -> Real { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto to_real() const noexcept + -> Real { assert(this->is_real()); assert(!std::isinf(this->data_real)); assert(!std::isnan(this->data_real)); @@ -615,7 +623,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.is_decimal()); /// assert(document.to_decimal().to_int64() == 1234567890); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_decimal() const noexcept + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto to_decimal() const noexcept -> const Decimal & { assert(this->is_decimal()); assert(this->data_decimal->is_finite()); @@ -635,7 +643,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.is_string()); /// assert(document.to_string() == "foo"); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto to_string() const noexcept + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto to_string() const noexcept -> const String & { assert(this->is_string()); return this->data_string; @@ -675,7 +683,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// << "\n"; /// }); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_array() const noexcept + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto as_array() const noexcept -> const Array & { assert(this->is_array()); return this->data_array; @@ -693,7 +701,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// std::sort(document.as_array().begin(), document.as_array().end()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_array() noexcept -> Array & { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto as_array() noexcept + -> Array & { assert(this->is_array()); return this->data_array; } @@ -720,7 +729,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// << "\n"; /// }); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_object() noexcept -> Object & { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto as_object() noexcept + -> Object & { assert(this->is_object()); return this->data_object; } @@ -743,7 +753,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// value += sourcemeta::core::JSON{1}; /// } /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_object() const noexcept + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto as_object() const noexcept -> const Object & { assert(this->is_object()); return this->data_object; @@ -759,7 +769,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{5}; /// assert(document.as_real() == 5.0); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_real() const noexcept -> Real { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto as_real() const noexcept + -> Real { assert(this->is_number()); return this->is_real() ? this->to_real() : static_cast(this->to_integer()); @@ -776,7 +787,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON document{5.3}; /// assert(document.as_integer() == 5); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto as_integer() const noexcept + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto as_integer() const noexcept -> Integer { assert(this->is_number()); if (this->is_integer()) { @@ -808,7 +819,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("{ \"1\": "foo" }"); /// assert(my_array.at(1).to_string() == "foo"); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto at(const typename Array::size_type index) const -> const JSON & { assert(this->is_array()); assert(index < this->size()); @@ -833,7 +844,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("{ \"1\": "foo" }"); /// assert(my_array.at(1).to_string() == "foo"); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto at(const typename Array::size_type index) -> JSON & { assert(this->is_array()); assert(index < this->size()); @@ -852,7 +863,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("{ \"foo\": 1, \"bar\": 2 }"); /// assert(my_object.at("bar").to_integer() == 2); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto at(const String &key) const + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto at(const String &key) const -> const JSON & { assert(this->is_object()); assert(this->defines(key)); @@ -874,7 +885,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(my_object.at("bar", /// my_object.as_object().hash("bar")).to_integer() == 2); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto at(const String &key, const typename Object::hash_type hash) const -> const JSON & { assert(this->is_object()); @@ -894,7 +905,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("{ \"foo\": 1, \"bar\": 2 }"); /// assert(my_object.at("bar").to_integer() == 2); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto at(const String &key) -> JSON & { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto at(const String &key) + -> JSON & { assert(this->is_object()); assert(this->defines(key)); auto &object{this->data_object}; @@ -915,7 +927,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(my_object.at("bar", /// my_object.as_object().hash("bar")).to_integer() == 2); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto at(const String &key, const typename Object::hash_type hash) -> JSON & { assert(this->is_object()); assert(this->defines(key)); @@ -982,7 +994,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.front().to_integer() == 1); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto front() -> JSON & { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto front() -> JSON & { assert(this->is_array()); assert(!this->empty()); return this->data_array.data.front(); @@ -1000,7 +1012,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.front().to_integer() == 1); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto front() const -> const JSON & { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto front() const + -> const JSON & { assert(this->is_array()); assert(!this->empty()); return this->data_array.data.front(); @@ -1018,7 +1031,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.back().to_integer() == 3); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto back() -> JSON & { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto back() -> JSON & { assert(this->is_array()); assert(!this->empty()); return this->data_array.data.back(); @@ -1036,7 +1049,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); /// assert(document.back().to_integer() == 3); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto back() const -> const JSON & { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto back() const + -> const JSON & { assert(this->is_array()); assert(!this->empty()); return this->data_array.data.back(); @@ -1066,7 +1080,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(my_array.size() == 2); /// assert(my_string.size() == 3); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto size() const -> std::size_t { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto size() const -> std::size_t { if (this->is_object()) { return this->object_size(); } else if (this->is_array()) { @@ -1087,7 +1101,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const sourcemeta::core::JSON my_string{"foo"}; /// assert(my_string.string_size() == 3); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto string_size() const -> std::size_t { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto string_size() const + -> std::size_t { assert(this->is_string()); return JSON::size(this->data_string); } @@ -1104,7 +1119,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("[ 1, 2 ]"); /// assert(my_array.array_size() == 2); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto array_size() const -> std::size_t { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto array_size() const + -> std::size_t { assert(this->is_array()); return this->data_array.data.size(); } @@ -1121,7 +1137,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("{ \"foo\": 1 }"); /// assert(my_object.object_size() == 1); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto object_size() const -> std::size_t { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto object_size() const + -> std::size_t { assert(this->is_object()); return this->data_object.size(); } @@ -1137,7 +1154,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// sourcemeta::core::parse_json("\"\\uD83D\\uDCA9\"")}; /// assert(my_string.size() == 2); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto byte_size() const -> std::size_t { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto byte_size() const + -> std::size_t { assert(this->is_string()); return this->data_string.size(); } @@ -1208,7 +1226,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(my_array.empty()); /// assert(my_string.empty()); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto empty() const -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto empty() const -> bool { if (this->is_object()) { return this->data_object.empty(); } else if (this->is_array()) { @@ -1231,8 +1249,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// const auto result = document.try_at("foo"); /// EXPECT_TRUE(result); /// EXPECT_EQ(result->to_integer(), 1); - [[nodiscard]] SOURCEMETA_FORCEINLINE auto try_at(const String &key) const - -> const JSON * { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto + try_at(const String &key) const -> const JSON * { assert(this->is_object()); const auto &object{this->data_object}; return object.try_at(key, object.hash(key)); @@ -1253,7 +1271,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// document.as_object().hash("foo")); /// EXPECT_TRUE(result); /// EXPECT_EQ(result->to_integer(), 1); - [[nodiscard]] SOURCEMETA_FORCEINLINE auto + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto try_at(const String &key, const typename Object::hash_type hash) const -> const JSON * { assert(this->is_object()); @@ -1273,8 +1291,8 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.defines("foo")); /// assert(!document.defines("bar")); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto defines(const String &key) const - -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto + defines(const String &key) const -> bool { assert(this->is_object()); const auto &object{this->data_object}; return object.defines(key, object.hash(key)); @@ -1294,7 +1312,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.defines("bar", /// document.as_object().hash("bar"))); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto defines(const String &key, const typename Object::hash_type hash) const -> bool { assert(this->is_object()); @@ -1313,7 +1331,7 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { /// assert(document.defines(0)); /// assert(!document.defines(1)); /// ``` - [[nodiscard]] SOURCEMETA_FORCEINLINE auto + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto defines(const typename Array::size_type index) const -> bool { return this->defines(std::to_string(index)); } diff --git a/src/lang/numeric/include/sourcemeta/core/numeric_decimal.h b/src/lang/numeric/include/sourcemeta/core/numeric_decimal.h index 51f4d79b4..b07f83ccb 100644 --- a/src/lang/numeric/include/sourcemeta/core/numeric_decimal.h +++ b/src/lang/numeric/include/sourcemeta/core/numeric_decimal.h @@ -116,17 +116,17 @@ class SOURCEMETA_CORE_NUMERIC_EXPORT Decimal { /// Check if the decimal number represents an integer value _without_ a /// decimal component in its original representation. - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_integer() const -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_integer() const -> bool { return this->is_integral() && this->exponent_ >= 0; } /// Check if the decimal number is finite - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_finite() const -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_finite() const -> bool { return !(this->flags_ & (FLAG_NAN | FLAG_SNAN | FLAG_INFINITE)); } /// Check if the decimal number is a real number (finite and not NaN) - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_real() const -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_real() const -> bool { return this->is_finite() && !this->is_integral(); } @@ -152,34 +152,34 @@ class SOURCEMETA_CORE_NUMERIC_EXPORT Decimal { /// Check if the decimal number is NaN (Not a Number), either quiet or /// signaling - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_nan() const -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_nan() const -> bool { return (this->flags_ & FLAG_NAN) != 0; } /// Check if the decimal number is a signaling NaN - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_snan() const -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_snan() const -> bool { return (this->flags_ & FLAG_SNAN) != 0; } /// Check if the decimal number is a quiet NaN - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_qnan() const -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_qnan() const -> bool { return (this->flags_ & FLAG_NAN) != 0 && !(this->flags_ & FLAG_SNAN); } /// Get the payload of a NaN value (0 if no payload) - [[nodiscard]] SOURCEMETA_FORCEINLINE auto nan_payload() const + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto nan_payload() const -> std::uint64_t { assert(this->is_nan()); return static_cast(this->coefficient_); } /// Check if the decimal number is infinite - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_infinite() const -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_infinite() const -> bool { return (this->flags_ & FLAG_INFINITE) != 0; } /// Check if the decimal number is signed (negative, including -0) - [[nodiscard]] SOURCEMETA_FORCEINLINE auto is_signed() const -> bool { + [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_signed() const -> bool { return (this->flags_ & FLAG_SIGN) != 0; }