feat: freestanding support added

Resolves #564, #565, and #556
This commit is contained in:
Mateusz Pusz
2024-05-30 19:50:02 +02:00
parent c151740a43
commit cd36e6f974
30 changed files with 387 additions and 60 deletions

152
.github/workflows/ci-freestanding.yml vendored Normal file
View File

@ -0,0 +1,152 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Mateusz Pusz
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
name: Freestanding CI
on:
push:
paths-ignore:
- "docs/**"
pull_request:
paths-ignore:
- "docs/**"
jobs:
build:
name: "${{ matrix.formatting }} ${{ matrix.contracts }} C++${{ matrix.std }} ${{ matrix.config.name }} ${{ matrix.build_type }}"
runs-on: ${{ matrix.config.os }}
strategy:
fail-fast: false
matrix:
formatting: ["std::format", "fmtlib"]
contracts: ["none"]
std: [23]
config:
- {
name: "GCC-14",
os: ubuntu-24.04,
compiler:
{
type: GCC,
version: 14,
cc: "gcc-14",
cxx: "g++-14",
},
cxx_modules: "False",
std_format_support: "True",
conan-config: "",
}
- {
name: "Clang-18",
os: ubuntu-24.04,
compiler:
{
type: CLANG,
version: 18,
cc: "clang-18",
cxx: "clang++-18",
},
lib: "libc++",
cxx_modules: "True",
std_format_support: "True",
conan-config: "",
}
build_type: ["Release", "Debug"]
env:
CC: ${{ matrix.config.compiler.cc }}
CXX: ${{ matrix.config.compiler.cxx }}
steps:
- uses: actions/checkout@v4
- run: echo "cache_id=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_ENV
- name: Cache Conan data
uses: actions/cache@v4
if: always()
env:
cache-name: cache-conan-data
with:
path: ~/.conan2/p
key: clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }}
restore-keys: |
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-
clang-tidy-${{ matrix.config.os }}-
- uses: hendrikmuhs/ccache-action@v1.2
if: runner.os == 'Linux'
with:
key: ${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}
max-size: 50M
- name: Install Clang
if: matrix.config.compiler.type == 'CLANG'
shell: bash
working-directory: ${{ env.HOME }}
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh ${{ matrix.config.compiler.version }}
sudo apt install -y clang-tools-${{ matrix.config.compiler.version }}
- name: Install Libc++
if: matrix.config.compiler.type == 'CLANG' && matrix.config.lib == 'libc++'
shell: bash
run: |
sudo apt install -y libc++-${{ matrix.config.compiler.version }}-dev libc++abi-${{ matrix.config.compiler.version }}-dev libunwind-${{ matrix.config.compiler.version }}-dev
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.x
- name: Install Ninja
shell: bash
run: |
pip install -U ninja
- name: Install Conan
shell: bash
run: |
pip install -U conan
- name: Configure Conan
shell: bash
run: |
conan profile detect --force
if [[ "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then
sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.libcxx=.*/compiler.libcxx=${{ matrix.config.lib }}/' ~/.conan2/profiles/default
fi
sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.cppstd=.*/compiler.cppstd=${{ matrix.std }}/' ~/.conan2/profiles/default
sed -i.backup '/^\[settings\]$/,/^\[/ s/^build_type=.*/build_type=${{ matrix.build_type }}/' ~/.conan2/profiles/default
conan profile show -pr default
- run: echo "std_format=$([ "${{ matrix.formatting }}" == "std::format" ] && echo "True" || echo "False")" >> $GITHUB_ENV
- name: Run clang-tidy
shell: bash
run: |
conan build . -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" \
-c user.mp-units.build:all=True -c tools.build:cxxflags="['-ffreestanding']" \
-o cxx_modules=${{ matrix.config.cxx_modules }} -o std_format=${{ env.std_format }} -o contracts=${{ matrix.contracts }} -o freestanding=True ${{ matrix.config.conan-config }}
- name: Clean Conan cache before backup
shell: bash
run: |
conan remove *#~latest --confirm
conan remove *:*#~latest --confirm
conan cache clean "*" -s -b -d

View File

@ -67,8 +67,10 @@ endif()
# add project code
add_subdirectory(src)
# add usage example
add_subdirectory(example)
if(!${projectPrefix}API_FREESTANDING)
# add usage example
add_subdirectory(example)
endif()
# add unit tests
enable_testing()

View File

@ -66,6 +66,7 @@ class MPUnitsConan(ConanFile):
"string_view_ret": ["auto", True, False],
"no_crtp": ["auto", True, False],
"contracts": ["none", "gsl-lite", "ms-gsl"],
"freestanding": [True, False],
}
default_options = {
"cxx_modules": "auto",
@ -73,6 +74,7 @@ class MPUnitsConan(ConanFile):
"string_view_ret": "auto",
"no_crtp": "auto",
"contracts": "gsl-lite",
"freestanding": "False",
}
tool_requires = "cmake/[>=3.29]"
implements = "auto_header_only"
@ -223,6 +225,10 @@ class MPUnitsConan(ConanFile):
for key, value in self._option_feature_map.items():
if self.options.get_safe(key) == True:
self._check_feature_supported(key, value)
if self.options.freestanding and self.options.contracts != "none":
raise ConanInvalidConfiguration(
"'contracts' should be set to 'none' for a freestanding build"
)
def layout(self):
cmake_layout(self)
@ -251,6 +257,7 @@ class MPUnitsConan(ConanFile):
tc.cache_variables["MP_UNITS_API_CONTRACTS"] = str(
self.options.contracts
).upper()
tc.cache_variables["MP_UNITS_API_FREESTANDING"] = self.options.freestanding
tc.generate()
deps = CMakeDeps(self)
deps.generate()

View File

@ -42,6 +42,9 @@ message(STATUS "${projectPrefix}BUILD_AS_SYSTEM_HEADERS: ${${projectPrefix}BUILD
option(${projectPrefix}BUILD_CXX_MODULES "Add C++ modules to the list of default targets" OFF)
message(STATUS "${projectPrefix}BUILD_CXX_MODULES: ${${projectPrefix}BUILD_CXX_MODULES}")
option(${projectPrefix}API_FREESTANDING "Builds only freestanding part of the library" OFF)
message(STATUS "${projectPrefix}API_FREESTANDING: ${${projectPrefix}API_FREESTANDING}")
if(${projectPrefix}BUILD_AS_SYSTEM_HEADERS)
set(${projectPrefix}_AS_SYSTEM SYSTEM)
endif()
@ -71,6 +74,10 @@ cache_var_values(API_NO_CRTP AUTO TRUE FALSE)
set(${projectPrefix}API_CONTRACTS GSL-LITE CACHE STRING "Enable contract checking")
cache_var_values(API_CONTRACTS NONE GSL-LITE MS-GSL)
if(${projectPrefix}API_FREESTANDING AND NOT ${projectPrefix}API_CONTRACTS STREQUAL "NONE")
message(FATAL_ERROR "'${projectPrefix}API_CONTRACTS' should be set to 'NONE' for a freestanding build")
endif()
# C++ features
check_cxx_feature_supported(__cpp_lib_format ${projectPrefix}LIB_FORMAT_SUPPORTED)
check_cxx_feature_supported("__cpp_constexpr >= 202211L" ${projectPrefix}STATIC_CONSTEXPR_VARS_IN_CONSTEXPR_FUNCTIONS)

View File

@ -35,7 +35,6 @@ endfunction()
add_mp_units_module(
core mp-units-core
HEADERS include/mp-units/bits/core_gmf.h
include/mp-units/bits/fmt.h
include/mp-units/bits/get_associated_quantity.h
include/mp-units/bits/get_common_base.h
include/mp-units/bits/hacks.h
@ -73,14 +72,27 @@ add_mp_units_module(
include/mp-units/framework/value_cast.h
include/mp-units/compat_macros.h
include/mp-units/concepts.h
include/mp-units/format.h
include/mp-units/framework.h
include/mp-units/math.h
include/mp-units/ostream.h
include/mp-units/random.h
MODULE_INTERFACE_UNIT mp-units-core.cpp
)
if(NOT ${projectPrefix}API_FREESTANDING)
target_sources(
mp-units-core
PUBLIC FILE_SET
HEADERS
BASE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/include
FILES
include/mp-units/bits/fmt.h
include/mp-units/bits/requires_hosted.h
include/mp-units/math.h
include/mp-units/ostream.h
include/mp-units/format.h
include/mp-units/random.h
)
endif()
set_feature_flag(API_STD_FORMAT)
set_feature_flag(API_STRING_VIEW_RET)
set_feature_flag(API_NO_CRTP)
@ -133,4 +145,8 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
)
endif()
# target_compile_options(mp-units-core ${${projectPrefix}TARGET_SCOPE} "-ftime-trace")
# Freestanding
target_compile_definitions(
mp-units-core ${${projectPrefix}TARGET_SCOPE}
${projectPrefix}HOSTED=$<NOT:$<BOOL:${${projectPrefix}API_FREESTANDING}>>
)

View File

@ -25,7 +25,6 @@
#include <mp-units/bits/hacks.h>
#include <mp-units/compat_macros.h>
#include <array>
#include <cmath>
#include <compare>
#include <concepts>
#include <cstddef>
@ -35,18 +34,23 @@
#include <initializer_list>
#include <iterator>
#include <limits>
#include <locale>
#include <numbers>
#include <numeric>
#include <optional>
#include <random>
#include <sstream>
#include <string>
#include <ranges>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#if MP_UNITS_HOSTED
#include <cmath>
#include <locale>
#include <ostream>
#include <random>
#include <sstream>
#include <string>
#if MP_UNITS_USE_FMTLIB
MP_UNITS_DIAGNOSTIC_PUSH
MP_UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE
@ -57,6 +61,8 @@ MP_UNITS_DIAGNOSTIC_POP
#include <format>
#endif
#endif
#if __cpp_lib_text_encoding
#include <text_encoding>
#endif

View File

@ -73,6 +73,10 @@
#define MP_UNITS_DIAGNOSTIC_IGNORE_DEPRECATED
#endif
#if !defined MP_UNITS_HOSTED && defined __STDC_HOSTED__
#define MP_UNITS_HOSTED __STDC_HOSTED__
#endif
#if MP_UNITS_COMP_MSVC
#define MP_UNITS_TYPENAME typename

View File

@ -0,0 +1,29 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <mp-units/bits/hacks.h>
#if !MP_UNITS_HOSTED
#error "This header is not available in freestanding mode."
#endif

View File

@ -23,6 +23,7 @@
#pragma once
#include <mp-units/bits/ratio.h>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/fixed_string.h>
#include <mp-units/ext/type_traits.h>
#include <mp-units/framework/symbol_text.h>
@ -100,12 +101,12 @@ constexpr Out copy(const symbol_text<N, M>& txt, text_encoding encoding, Out out
for (const char8_t ch : txt.unicode()) *out++ = static_cast<char>(ch);
return out;
} else
throw std::invalid_argument("Unicode text can't be copied to CharT output");
MP_UNITS_THROW(std::invalid_argument("Unicode text can't be copied to CharT output"));
} else {
if constexpr (is_same_v<CharT, char>)
return ::mp_units::detail::copy(txt.ascii().begin(), txt.ascii().end(), out);
else
throw std::invalid_argument("ASCII text can't be copied to CharT output");
MP_UNITS_THROW(std::invalid_argument("ASCII text can't be copied to CharT output"));
}
}

View File

@ -40,6 +40,15 @@
#endif
#if MP_UNITS_HOSTED
#define MP_UNITS_THROW(expr) throw expr
#else
#include <cstdlib>
#define MP_UNITS_THROW(expr) std::abort()
#endif
#if MP_UNITS_HOSTED
#if defined MP_UNITS_API_STD_FORMAT && !MP_UNITS_API_STD_FORMAT
#define MP_UNITS_USE_FMTLIB 1
@ -59,21 +68,7 @@
#define MP_UNITS_FMT_TO_ARG_ID(arg) (arg)
#define MP_UNITS_FMT_FROM_ARG_ID(arg) (arg)
// This re-uses code from fmt;
#if FMT_EXCEPTIONS
#if FMT_MSC_VERSION || defined(__NVCC__)
#define MP_UNITS_THROW(x) ::fmt::detail::do_throw(x)
#else
#define MP_UNITS_THROW(x) throw x
#endif
#else
#define MP_UNITS_THROW(x) \
do { \
FMT_ASSERT(false, (x).what()); \
} while (false)
#endif
#else
#else // MP_UNITS_USE_FMTLIB
#if !defined __cpp_lib_format && !defined MP_UNITS_COMP_CLANG
#error "std::formatting facility not supported"
@ -83,10 +78,8 @@
#define MP_UNITS_FMT_LOCALE(loc) loc
#define MP_UNITS_FMT_TO_ARG_ID(arg) static_cast<std::size_t>(arg)
#define MP_UNITS_FMT_FROM_ARG_ID(arg) static_cast<int>(arg)
#define MP_UNITS_THROW(arg) throw arg
#endif
#endif // MP_UNITS_USE_FMTLIB
#ifndef MP_UNITS_IN_MODULE_INTERFACE
@ -104,6 +97,8 @@ MP_UNITS_DIAGNOSTIC_POP
#endif
#endif // MP_UNITS_HOSTED
#if MP_UNITS_API_CONTRACTS == 2 || __has_include(<gsl/gsl-lite.hpp>)
#include <gsl/gsl-lite.hpp>

View File

@ -35,8 +35,11 @@
#include <compare> // IWYU pragma: export
#include <cstddef>
#include <cstdlib>
#include <ostream>
#include <ranges>
#include <string_view>
#if MP_UNITS_HOSTED
#include <ostream>
#endif
#endif
MP_UNITS_EXPORT
@ -123,11 +126,14 @@ public:
return data()[pos];
}
#if MP_UNITS_HOSTED
[[nodiscard]] constexpr const_reference at(size_type pos) const
{
if (pos >= size()) throw std::out_of_range("basic_fixed_string::at");
return (*this)[pos];
}
#endif
[[nodiscard]] constexpr const_reference front() const
{
MP_UNITS_EXPECTS(!empty());
@ -239,11 +245,13 @@ public:
}
// inserters and extractors
#if MP_UNITS_HOSTED
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
const basic_fixed_string& str)
{
return os << str.c_str();
}
#endif
};
// deduction guides
@ -282,6 +290,7 @@ struct std::hash<mp_units::fixed_u32string<N>> : std::hash<std::u32string_view>
template<std::size_t N>
struct std::hash<mp_units::fixed_wstring<N>> : std::hash<std::wstring_view> {};
#if MP_UNITS_HOSTED
// formatting support
template<typename CharT, std::size_t N>
struct MP_UNITS_STD_FMT::formatter<mp_units::basic_fixed_string<CharT, N>> : formatter<std::basic_string_view<CharT>> {
@ -291,4 +300,6 @@ struct MP_UNITS_STD_FMT::formatter<mp_units::basic_fixed_string<CharT, N>> : for
return formatter<std::basic_string_view<CharT>>::format(std::basic_string_view<CharT>(str), ctx);
}
};
#endif
// NOLINTEND(*-avoid-c-arrays)

View File

@ -24,6 +24,8 @@
#pragma once
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/fmt.h>
#include <mp-units/bits/module_macros.h>
#include <mp-units/compat_macros.h>

View File

@ -37,8 +37,10 @@
#include <array>
#include <cstdint>
#include <iterator>
#include <string>
#include <string_view>
#if MP_UNITS_HOSTED
#include <string>
#endif
#endif
namespace mp_units {
@ -318,9 +320,15 @@ MP_UNITS_EXPORT template<dimension_symbol_formatting fmt = dimension_symbol_form
#endif
{
auto get_size = []() consteval {
#if MP_UNITS_HOSTED
std::basic_string<CharT> buffer;
dimension_symbol_to<CharT>(std::back_inserter(buffer), D{}, fmt);
return buffer.size();
#else
std::array<CharT, 128> buffer; // TODO unsafe
auto end = dimension_symbol_to<CharT>(buffer.begin(), D{}, fmt);
return end - buffer.begin();
#endif
};
#if MP_UNITS_API_STRING_VIEW_RET // Permitting static constexpr variables in constexpr functions

View File

@ -44,8 +44,10 @@
#include <array>
#include <cstdint>
#include <iterator>
#include <string>
#include <string_view>
#if MP_UNITS_HOSTED
#include <string>
#endif
#endif
namespace mp_units {
@ -718,8 +720,8 @@ constexpr Out print_separator(Out out, const unit_symbol_formatting& fmt)
{
if (fmt.separator == unit_symbol_separator::half_high_dot) {
if (fmt.encoding != text_encoding::unicode)
throw std::invalid_argument(
"'unit_symbol_separator::half_high_dot' can be only used with 'text_encoding::unicode'");
MP_UNITS_THROW(
std::invalid_argument("'unit_symbol_separator::half_high_dot' can be only used with 'text_encoding::unicode'"));
const std::string_view dot = "";
out = detail::copy(dot.begin(), dot.end(), out);
} else {
@ -844,9 +846,15 @@ MP_UNITS_EXPORT template<unit_symbol_formatting fmt = unit_symbol_formatting{},
#endif
{
auto get_size = []() consteval {
#if MP_UNITS_HOSTED
std::basic_string<CharT> buffer;
unit_symbol_to<CharT>(std::back_inserter(buffer), U{}, fmt);
return buffer.size();
#else
std::array<CharT, 128> buffer; // TODO unsafe
auto end = unit_symbol_to<CharT>(buffer.begin(), U{}, fmt);
return end - buffer.begin();
#endif
};
#if MP_UNITS_API_STRING_VIEW_RET // Permitting static constexpr variables in constexpr functions

View File

@ -22,6 +22,8 @@
#pragma once
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/framework/customization_points.h>
#include <mp-units/framework/quantity.h>

View File

@ -23,6 +23,8 @@
#pragma once
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/framework/quantity.h>
#include <mp-units/framework/unit.h>

View File

@ -8,8 +8,11 @@ export module mp_units.core;
#include <mp-units/compat_macros.h>
#include <mp-units/concepts.h>
#include <mp-units/format.h>
#include <mp-units/framework.h>
#if MP_UNITS_HOSTED
#include <mp-units/format.h>
#include <mp-units/math.h>
#include <mp-units/ostream.h>
#include <mp-units/random.h>
#endif

View File

@ -25,8 +25,7 @@ cmake_minimum_required(VERSION 3.23)
add_mp_units_module(
systems mp-units-systems
DEPENDENCIES mp-units::core
HEADERS include/mp-units/systems/angular/math.h
include/mp-units/systems/angular/units.h
HEADERS include/mp-units/systems/angular/units.h
include/mp-units/systems/iec80000/binary_prefixes.h
include/mp-units/systems/iec80000/quantities.h
include/mp-units/systems/iec80000/unit_symbols.h
@ -39,9 +38,7 @@ add_mp_units_module(
include/mp-units/systems/isq/si_quantities.h
include/mp-units/systems/isq/space_and_time.h
include/mp-units/systems/isq/thermodynamics.h
include/mp-units/systems/si/chrono.h
include/mp-units/systems/si/constants.h
include/mp-units/systems/si/math.h
include/mp-units/systems/si/prefixes.h
include/mp-units/systems/si/unit_symbols.h
include/mp-units/systems/si/units.h
@ -60,3 +57,17 @@ add_mp_units_module(
include/mp-units/systems/usc.h
MODULE_INTERFACE_UNIT mp-units-systems.cpp
)
if(NOT ${projectPrefix}API_FREESTANDING)
target_sources(
mp-units-systems
PUBLIC FILE_SET
HEADERS
BASE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/include
FILES
include/mp-units/systems/angular/math.h
include/mp-units/systems/si/math.h
include/mp-units/systems/si/chrono.h
)
endif()

View File

@ -23,7 +23,9 @@
#pragma once
// IWYU pragma: begin_exports
#if MP_UNITS_HOSTED
#include <mp-units/systems/angular/math.h>
#endif
#include <mp-units/systems/angular/units.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE

View File

@ -22,6 +22,8 @@
#pragma once
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/systems/angular/units.h>

View File

@ -23,9 +23,11 @@
#pragma once
// IWYU pragma: begin_exports
#if MP_UNITS_HOSTED
#include <mp-units/systems/si/chrono.h>
#include <mp-units/systems/si/constants.h>
#include <mp-units/systems/si/math.h>
#endif
#include <mp-units/systems/si/constants.h>
#include <mp-units/systems/si/prefixes.h>
#include <mp-units/systems/si/unit_symbols.h>
#include <mp-units/systems/si/units.h>

View File

@ -22,6 +22,8 @@
#pragma once
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/systems/isq/si_quantities.h>
#include <mp-units/systems/si/prefixes.h>

View File

@ -22,6 +22,8 @@
#pragma once
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/systems/isq/space_and_time.h>
#include <mp-units/systems/si/units.h>

View File

@ -22,5 +22,7 @@
cmake_minimum_required(VERSION 3.5)
add_subdirectory(runtime)
if(!${projectPrefix}API_FREESTANDING)
add_subdirectory(runtime)
endif()
add_subdirectory(static)

View File

@ -32,7 +32,6 @@ add_library(
unit_tests_static
angular_test.cpp
cgs_test.cpp
chrono_test.cpp
compare_test.cpp
concepts_test.cpp
# custom_rep_test_min_expl.cpp
@ -40,7 +39,6 @@ add_library(
dimension_test.cpp
dimension_symbol_test.cpp
fixed_string_test.cpp
fractional_exponent_quantity.cpp
hep_test.cpp
iau_test.cpp
iec80000_test.cpp
@ -49,7 +47,6 @@ add_library(
isq_test.cpp
isq_angle_test.cpp
# magnitude_test.cpp
math_test.cpp
natural_test.cpp
prime_test.cpp
quantity_point_test.cpp
@ -64,6 +61,11 @@ add_library(
unit_symbol_test.cpp
usc_test.cpp
)
if(NOT ${projectPrefix}API_FREESTANDING)
target_sources(unit_tests_static PRIVATE chrono_test.cpp fractional_exponent_quantity.cpp math_test.cpp)
endif()
target_compile_options(unit_tests_static PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wno-subobject-linkage>)
target_link_libraries(unit_tests_static PRIVATE mp-units::mp-units)
target_link_libraries(unit_tests_static PRIVATE unit_tests_static_truncating)

View File

@ -23,14 +23,18 @@
#include <mp-units/systems/isq/space_and_time.h>
#include <mp-units/systems/natural.h>
#include <mp-units/systems/si.h>
#include <optional>
#include <type_traits>
#if MP_UNITS_HOSTED
#include <chrono>
#include <complex>
#include <optional>
#include <string>
#include <type_traits>
#endif
#if MP_UNITS_HOSTED
template<typename T>
inline constexpr bool mp_units::is_scalar<std::complex<T>> = true;
#endif
namespace {
@ -157,7 +161,9 @@ static_assert(!Unit<named_unit<"?", si::metre, isq::length>>);
static_assert(!Unit<prefixed_unit<"?", mag<10>, si::second>>);
static_assert(!Unit<struct isq::dim_length>);
static_assert(!Unit<int>);
#if MP_UNITS_HOSTED
static_assert(!Unit<std::chrono::seconds>);
#endif
// NamedUnit
static_assert(detail::NamedUnit<struct si::metre>);
@ -181,7 +187,9 @@ static_assert(!detail::NamedUnit<named_unit<"?", si::metre, isq::length>>);
static_assert(!detail::NamedUnit<prefixed_unit<"?", mag<10>, si::second>>);
static_assert(!detail::NamedUnit<struct isq::dim_length>);
static_assert(!detail::NamedUnit<int>);
#if MP_UNITS_HOSTED
static_assert(!detail::NamedUnit<std::chrono::seconds>);
#endif
// PrefixableUnit
static_assert(PrefixableUnit<struct si::metre>);
@ -205,7 +213,9 @@ static_assert(!PrefixableUnit<named_unit<"?", si::metre, isq::length>>);
static_assert(!PrefixableUnit<prefixed_unit<"?", mag<10>, si::second>>);
static_assert(!PrefixableUnit<struct isq::dim_length>);
static_assert(!PrefixableUnit<int>);
#if MP_UNITS_HOSTED
static_assert(!PrefixableUnit<std::chrono::seconds>);
#endif
// AssociatedUnit
static_assert(AssociatedUnit<struct si::metre>);
@ -229,7 +239,9 @@ static_assert(!AssociatedUnit<named_unit<"?", si::metre, isq::length>>);
static_assert(!AssociatedUnit<prefixed_unit<"?", mag<10>, si::second>>);
static_assert(!AssociatedUnit<struct isq::dim_length>);
static_assert(!AssociatedUnit<int>);
#if MP_UNITS_HOSTED
static_assert(!AssociatedUnit<std::chrono::seconds>);
#endif
// UnitOf
static_assert(UnitOf<struct si::metre, isq::length>);
@ -284,27 +296,33 @@ static_assert(!ReferenceOf<std::remove_const_t<decltype(dimensionless[one])>, is
// Representation
static_assert(Representation<int>);
static_assert(Representation<double>);
static_assert(Representation<std::complex<double>>);
static_assert(!Representation<bool>);
static_assert(!Representation<std::optional<int>>);
static_assert(!Representation<std::chrono::seconds>);
#if MP_UNITS_HOSTED
static_assert(Representation<std::complex<double>>);
static_assert(!Representation<std::string>);
static_assert(!Representation<std::chrono::seconds>);
#endif
// RepresentationOf
static_assert(RepresentationOf<int, quantity_character::scalar>);
static_assert(RepresentationOf<double, quantity_character::scalar>);
static_assert(RepresentationOf<std::complex<double>, quantity_character::scalar>);
static_assert(!RepresentationOf<bool, quantity_character::scalar>);
static_assert(!RepresentationOf<std::optional<int>, quantity_character::scalar>);
#if MP_UNITS_HOSTED
static_assert(RepresentationOf<std::complex<double>, quantity_character::scalar>);
static_assert(!RepresentationOf<std::chrono::seconds, quantity_character::scalar>);
static_assert(!RepresentationOf<std::string, quantity_character::scalar>);
#endif
// Quantity
static_assert(Quantity<quantity<si::metre>>);
static_assert(Quantity<quantity<isq::length[si::metre]>>);
static_assert(Quantity<quantity<si::metre, int>>);
static_assert(Quantity<quantity<isq::length[si::metre], int>>);
#if MP_UNITS_HOSTED
static_assert(!Quantity<std::chrono::seconds>);
#endif
static_assert(!Quantity<quantity_point<si::metre, my_origin>>);
static_assert(!Quantity<std::remove_const_t<decltype(isq::length[si::metre])>>);
@ -332,8 +350,10 @@ static_assert(!QuantityOf<quantity<dimensionless[one]>, isq::rotation>);
static_assert(!QuantityOf<quantity<dimensionless[one]>, isq::angular_measure>);
// QuantityLike
#if MP_UNITS_HOSTED
static_assert(QuantityLike<std::chrono::seconds>);
static_assert(QuantityLike<std::chrono::hours>);
#endif
static_assert(!QuantityLike<quantity<isq::time[si::second]>>);
static_assert(!QuantityLike<quantity_point<isq::length[si::metre], my_origin>>);
static_assert(!QuantityLike<int>);
@ -349,8 +369,10 @@ static_assert(!QuantityPoint<std::remove_const_t<decltype(isq::length[si::metre]
static_assert(!QuantityPoint<absolute_point_origin<struct my_origin, isq::length>>);
static_assert(!QuantityPoint<struct my_origin>);
static_assert(!QuantityPoint<struct my_relative_origin>);
#if MP_UNITS_HOSTED
static_assert(!QuantityPoint<std::chrono::seconds>);
static_assert(!QuantityPoint<std::chrono::time_point<std::chrono::system_clock>>);
#endif
static_assert(!QuantityPoint<int>);
// QuantityPointOf
@ -384,8 +406,10 @@ static_assert(!PointOrigin<quantity_point<si::metre, my_origin>>);
static_assert(!PointOrigin<quantity_point<isq::length[si::metre], my_origin>>);
static_assert(!PointOrigin<quantity_point<isq::radius[si::metre], my_origin>>);
static_assert(!PointOrigin<std::remove_const_t<decltype(isq::length[si::metre])>>);
#if MP_UNITS_HOSTED
static_assert(!PointOrigin<std::chrono::seconds>);
static_assert(!PointOrigin<std::chrono::time_point<std::chrono::system_clock>>);
#endif
static_assert(!PointOrigin<int>);
// PointOriginFor
@ -408,13 +432,17 @@ static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre], my_relative
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre], my_relative_origin>, isq::radius>);
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre], my_relative_origin>, isq::time>);
static_assert(!PointOriginFor<std::remove_const_t<decltype(isq::length[si::metre])>, isq::length>);
#if MP_UNITS_HOSTED
static_assert(!PointOriginFor<std::chrono::seconds, isq::length>);
static_assert(!PointOriginFor<std::chrono::time_point<std::chrono::system_clock>, isq::length>);
#endif
static_assert(!PointOriginFor<int, isq::length>);
// QuantityPointLike
#if MP_UNITS_HOSTED
static_assert(QuantityPointLike<std::chrono::time_point<std::chrono::system_clock>>);
static_assert(!QuantityPointLike<std::chrono::seconds>);
#endif
static_assert(!QuantityPointLike<quantity<isq::time[si::second]>>);
static_assert(!QuantityPointLike<quantity_point<si::metre, my_origin>>);
static_assert(!QuantityPointLike<int>);

View File

@ -31,12 +31,12 @@ namespace {
constexpr std::array array = {'a', 'b', 'c'};
auto from_string = [] {
std::string txt = "abc";
std::string_view txt = "abc";
return fixed_string<3>(std::from_range, txt);
};
auto from_string_iter = [] {
std::string txt = "abc";
std::string_view txt = "abc";
return fixed_string<3>(txt.begin(), txt.end());
};
@ -90,6 +90,7 @@ static_assert(txt9[0] == 'c');
static_assert(txt9[1] == 'b');
static_assert(txt9[2] == 'a');
#if MP_UNITS_HOSTED
static_assert(txt1.at(0) == 'a');
static_assert(txt2.at(0) == 'a');
static_assert(txt2.at(1) == 'b');
@ -97,6 +98,7 @@ static_assert(txt2.at(2) == 'c');
static_assert(txt9.at(0) == 'c');
static_assert(txt9.at(1) == 'b');
static_assert(txt9.at(2) == 'a');
#endif
static_assert(txt1.front() == 'a');
static_assert(txt1.back() == 'a');

View File

@ -20,7 +20,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#if MP_UNITS_HOSTED
#include <mp-units/math.h> // IWYU pragma: keep
#endif
#include <mp-units/systems/iau.h>
#include <mp-units/systems/isq/space_and_time.h>
#include <mp-units/systems/si.h>
@ -42,7 +44,7 @@ static_assert(isq::length(1 * LD) == 384'399 * si::kilo<si::metre>);
static_assert(isq::length(1 * ly) == 9'460'730'472'580'800 * si::metre);
static_assert(isq::length(10'000'000'000 * A) == 1 * si::metre);
#if __cpp_lib_constexpr_cmath || MP_UNITS_COMP_GCC
#if MP_UNITS_HOSTED && (__cpp_lib_constexpr_cmath || MP_UNITS_COMP_GCC)
// TODO Should the below work for `1 * pc`? If yes, how to extent the type and how to convert it to a floating-point
// representation for comparison purposes?
static_assert(round<si::metre>(isq::length(1.L * pc)) == 30'856'775'814'913'673 * si::metre);

View File

@ -26,20 +26,25 @@
#include <mp-units/systems/isq.h>
#include <mp-units/systems/si.h>
#include <mp-units/systems/usc.h>
#include <chrono>
#include <concepts>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <utility>
#if MP_UNITS_HOSTED
#include <chrono>
#endif
namespace {
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
using namespace mp_units::usc::unit_symbols;
#if MP_UNITS_HOSTED
using namespace std::chrono_literals;
using sys_seconds = std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
#endif
inline constexpr struct zeroth_length : absolute_point_origin<zeroth_length, isq::length> {
} zeroth_length;
@ -444,6 +449,7 @@ static_assert(!std::convertible_to<quantity<isq::length[m]>, quantity_point<isq:
static_assert(!std::constructible_from<quantity_point<special_height[m]>, quantity<isq::height[m]>>);
static_assert(!std::convertible_to<quantity<special_height[m]>, quantity_point<isq::height[m]>>);
#if MP_UNITS_HOSTED
// quantity-like
static_assert(!std::constructible_from<quantity_point<si::second>, std::chrono::seconds>);
static_assert(!std::convertible_to<std::chrono::seconds, quantity_point<si::second>>);
@ -453,7 +459,7 @@ static_assert(!std::convertible_to<std::chrono::seconds, quantity_point<isq::tim
static_assert(!std::constructible_from<quantity_point<isq::period_duration[s]>, std::chrono::seconds>);
static_assert(!std::convertible_to<std::chrono::seconds, quantity_point<isq::period_duration[s]>>);
#endif
// ----------------------
// explicit point origins
@ -499,6 +505,7 @@ static_assert(!std::convertible_to<quantity<special_height[m]>, quantity_point<i
static_assert(!std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity<isq::length[m]>>);
static_assert(!std::convertible_to<quantity<isq::length[m]>, quantity_point<si::metre, mean_sea_level>>);
#if MP_UNITS_HOSTED
// quantity-like
static_assert(!std::constructible_from<quantity_point<si::second, chrono_point_origin<std::chrono::system_clock>>,
std::chrono::seconds>);
@ -516,6 +523,7 @@ static_assert(
static_assert(
!std::convertible_to<std::chrono::seconds,
quantity_point<isq::period_duration[s], chrono_point_origin<std::chrono::system_clock>>>);
#endif
///////////////////////////////////////
@ -775,6 +783,7 @@ static_assert(!std::constructible_from<quantity_point<isq::height[m], other_abso
static_assert(!std::convertible_to<quantity_point<isq::height[m], ground_level>,
quantity_point<isq::height[m], other_absolute_level>>);
#if MP_UNITS_HOSTED
// quantity-point-like
static_assert(
std::constructible_from<quantity_point<isq::time[s], chrono_point_origin<std::chrono::system_clock>>, sys_seconds>);
@ -786,6 +795,7 @@ static_assert(
!std::constructible_from<quantity_point<isq::time[s], chrono_point_origin<std::chrono::steady_clock>>, sys_seconds>);
static_assert(
!std::convertible_to<sys_seconds, quantity_point<isq::time[s], chrono_point_origin<std::chrono::steady_clock>>>);
#endif
//////////////////////////////////
@ -889,6 +899,7 @@ static_assert(std::is_same_v<std::remove_const_t<decltype(quantity_point{20 * de
static_assert(quantity_point{20 * deg_C}.unit == si::degree_Celsius);
static_assert(quantity_point{20 * deg_C}.quantity_spec == kind_of<isq::thermodynamic_temperature>);
#if MP_UNITS_HOSTED
using namespace std::chrono_literals;
static_assert(std::is_same_v<decltype(quantity_point{sys_seconds{123s}})::rep, std::chrono::seconds::rep>);
static_assert(std::is_same_v<std::remove_const_t<decltype(quantity_point{sys_seconds{123s}}.point_origin)>,
@ -897,6 +908,7 @@ static_assert(std::is_same_v<std::remove_const_t<decltype(quantity_point{sys_sec
chrono_point_origin_<std::chrono::system_clock>>);
static_assert(quantity_point{sys_seconds{24h}}.unit == si::second);
static_assert(quantity_point{sys_seconds{24h}}.quantity_spec == kind_of<isq::time>);
#endif
////////////

View File

@ -27,12 +27,14 @@
#include <mp-units/systems/isq/mechanics.h>
#include <mp-units/systems/isq/space_and_time.h>
#include <mp-units/systems/si.h>
#include <chrono>
#include <concepts>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <utility>
#if MP_UNITS_HOSTED
#include <chrono>
#endif
template<>
inline constexpr bool mp_units::is_vector<int> = true;
@ -311,12 +313,13 @@ static_assert(quantity{123. * m}.quantity_spec == kind_of<isq::length>);
static_assert(quantity{123. * h}.unit == si::hour);
static_assert(quantity{123. * h}.quantity_spec == kind_of<isq::time>);
#if MP_UNITS_HOSTED
using namespace std::chrono_literals;
static_assert(std::is_same_v<decltype(quantity{123s})::rep, std::chrono::seconds::rep>);
static_assert(std::is_same_v<decltype(quantity{123.s})::rep, long double>);
static_assert(quantity{24h}.unit == si::hour);
static_assert(quantity{24h}.quantity_spec == kind_of<isq::time>);
#endif
////////////////////////
// assignment operator