Skip to content

Commit

Permalink
Introduced a way to generate tags automatically
Browse files Browse the repository at this point in the history
  • Loading branch information
Yaraslaut committed Feb 10, 2024
1 parent ba8084f commit 3d40452
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 154 deletions.
20 changes: 11 additions & 9 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,22 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Run clang-format style check for C/C++/Protobuf programs.
uses: jidicula/[email protected]
with:
clang-format-version: '16'
check-path: '.'
#exclude-regex: 'sse2neon.h'
- name: Install clang
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 17
sudo apt-get install clang-format-17
- name: "Clang-format"
run:|
clang-format-17 --Werror --dry-run test-boxed-cpp.cpp include/boxed-cpp/boxed.hpp

editorconfig:
name: "Check editorconfig"
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: editorconfig-checker/action-editorconfig-checker@main

- run: editorconfig-checker

ubuntu:
Expand Down Expand Up @@ -68,7 +71,7 @@ jobs:
- name: "Cmake configure"
run: |
cmake -S . -B build -G Ninja \
-DBOXED_CPP_TESTS=OFF \
-DBOXED_TESTING=ON \
-DENABLE_TIDY=ON \
-DPEDANTIC_COMPILER=ON \
-DCMAKE_CXX_FLAGS="-Wno-unknown-warning-option" \
Expand All @@ -79,5 +82,4 @@ jobs:
run: cmake --build build --parallel 3

- name: "run test"
if: ${{ false }} # disabled, because of Github runner image bug in compiler-vs-stdlib
run: ./build/test-boxed-cpp
7 changes: 4 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ install(EXPORT boxed-cpp-targets
# ---------------------------------------------------------------------------
# unit tests

option(BOXED_CPP_TESTS "Enables building of unittests for boxed-cpp [default: OFF]" OFF)
if(BOXED_CPP_TESTS)
option(BOXED_TESTING "Enables building of unittests for boxed-cpp [default: OFF]" OFF)
if(BOXED_TESTING)
find_package(Catch2 3.4.0 QUIET)
if(NOT Catch2_FOUND)
ThirdPartiesAdd_Catch2()
Expand All @@ -62,7 +62,8 @@ if(BOXED_CPP_TESTS)
add_executable(test-boxed-cpp
test-boxed-cpp.cpp
)
target_compile_features(test-boxed-cpp INTERFACE cxx_std_20)
target_link_libraries(test-boxed-cpp boxed-cpp Catch2::Catch2WithMain)
add_test(test-boxed-cpp ./test-boxed-cpp)
endif()
message(STATUS "[boxed-cpp] Compile unit tests: ${BOXED_CPP_TESTS}")
message(STATUS "[boxed-cpp] Compile unit tests: ${BOXED_TESTING}")
28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@ Example of creation boxed structures and usage
#include <boxed-cpp/boxed.hpp>

// Create unique structures
namespace tags { struct Speed{}; struct Permittivity{}; struct Permeability{}; }

using Speed = boxed::boxed<double, tags::Speed>;
using Permittivity = boxed::boxed<double, tags::Permittivity>;
using Permeability = boxed::boxed<double, tags::Permeability>;

using Speed = boxed::boxed<double>;
using Permittivity = boxed::boxed<double>;
using Permeability = boxed::boxed<double>;

int main()
{
Expand All @@ -36,6 +34,9 @@ int main()

auto speed = wave_speed(vacuum_permittivity, vacuum_permeability);
// speed == Speed(299792458.0);

// Wrong order of parameters will result in compilation error
// wave_speed(vacuum_permeability, vacuum_permittivity);
}

```
Expand All @@ -62,13 +63,13 @@ double value_d = speed_of_light * 2.0;
```


# More advanced usage
You can forget about the order of parameters in your code. Complete code see: [godbolt](https://godbolt.org/z/K4r9d9far)
# More examples of usage
You can crate functions that will automatically adjust order of parameters. Complete code see: [godbolt](https://godbolt.org/z/aqobbcGe6)

``` c++
using rho_type = boxed::boxed<double,Tag::Rho>;
using theta_type = boxed::boxed<double,Tag::Theta>;
using phi_type = boxed::boxed<double,Tag::Phi>;
using rho_type = boxed::boxed<double>;
using theta_type = boxed::boxed<double>;
using phi_type = boxed::boxed<double>;

template <typename... F>
struct overload: F...{ using F::operator()...;};
Expand All @@ -89,7 +90,6 @@ struct Wrap
}
};


auto x_coord = Wrap([](rho_type rho){ return unbox(rho); },
[](theta_type theta){ return sin(unbox(theta)); },
[](phi_type phi){ return cos(unbox(phi)); }
Expand All @@ -101,9 +101,9 @@ int main()
theta_type theta{3.14 / 3.0};
phi_type phi{3.14/2.0};

assert(x_coord(rho,theta,phi) == x_coord(theta,rho,phi));
assert(x_coord(rho,theta,phi) == x_coord(phi,rho,theta));
assert(x_coord(rho,theta,phi) == x_coord(phi,rho,theta));
std::cout << x_coord(rho,theta,phi) << std::endl; // 0.000689428
std::cout << x_coord(phi,theta,rho) << std::endl; // 0.000689428
std::cout << x_coord(rho,phi,theta) << std::endl; // 0.000689428
}
```
Expand Down
125 changes: 69 additions & 56 deletions include/boxed-cpp/boxed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ namespace boxed
{
// {{{ forward decls
template <typename T, typename Tag>
struct boxed;
struct boxed_with_tag;

template <typename T, typename Tag = decltype([] {})>
using boxed = boxed_with_tag<T, Tag>;

namespace helper
{
template <typename A>
struct is_boxed;
template <typename A, typename B>
struct is_boxed<boxed<A, B>>;
struct is_boxed<boxed_with_tag<A, B>>;
} // namespace helper
// }}}

Expand All @@ -31,11 +34,18 @@ constexpr bool is_boxed = helper::is_boxed<T>::value;
*
* @code
* namespace tags { struct Length{}; }
* using Length = boxed<std::size_t, tags::Length>;
* using Length = boxed_wihh_tag<std::size_t, tags::Length>;
* @endcode
*
* You also can create boxed type without providing a tag with
* the `boxed` alias.
*
* @code
* using Length = boxed<std::size_t>;
* @endcode
*/
template <typename T, typename Tag>
struct boxed
struct boxed_with_tag
{
// clang-format off
static_assert(
Expand All @@ -47,13 +57,13 @@ struct boxed
using inner_type = T;
using element_type = T;

constexpr boxed(): value {} {}
constexpr explicit boxed(T value) noexcept: value { value } {}
constexpr boxed(boxed const&) = default;
constexpr boxed& operator=(boxed const&) = default;
constexpr boxed(boxed&&) noexcept = default;
constexpr boxed& operator=(boxed&&) noexcept = default;
~boxed() = default;
constexpr boxed_with_tag(): value {} {}
constexpr explicit boxed_with_tag(T value) noexcept: value { value } {}
constexpr boxed_with_tag(boxed_with_tag const&) = default;
constexpr boxed_with_tag& operator=(boxed_with_tag const&) = default;
constexpr boxed_with_tag(boxed_with_tag&&) noexcept = default;
constexpr boxed_with_tag& operator=(boxed_with_tag&&) noexcept = default;
~boxed_with_tag() = default;

T value;

Expand All @@ -72,57 +82,57 @@ struct boxed

template <typename Source>
// NOLINTNEXTLINE(readability-identifier-naming)
[[nodiscard]] constexpr static boxed<T, Tag> cast_from(Source value)
[[nodiscard]] constexpr static boxed_with_tag<T, Tag> cast_from(Source value)
{
if constexpr (is_boxed<Source>)
return boxed<T, Tag> { static_cast<T>(value.value) };
return boxed_with_tag<T, Tag> { static_cast<T>(value.value) };
else
return boxed<T, Tag>(static_cast<T>(value));
return boxed_with_tag<T, Tag>(static_cast<T>(value));
}

[[nodiscard]] constexpr auto operator<=>(boxed const& other) const noexcept = default;
[[nodiscard]] constexpr auto operator<=>(boxed_with_tag const& other) const noexcept = default;
};

template <typename T, typename U>
std::ostream& operator<<(std::ostream& os, boxed<T, U> value)
std::ostream& operator<<(std::ostream& os, boxed_with_tag<T, U> value)
{
os << value.value;
return os;
}

// clang-format off
template <typename T, typename U> constexpr boxed<T, U>& operator++(boxed<T, U>& a) noexcept { ++a.value; return a; }
template <typename T, typename U> constexpr boxed<T, U>& operator--(boxed<T, U>& a) noexcept { --a.value; return a; }
template <typename T, typename U> constexpr boxed<T, U> operator++(boxed<T, U>& a, int) noexcept { auto old = a; a.value++; return old; }
template <typename T, typename U> constexpr boxed<T, U> operator--(boxed<T, U>& a, int) noexcept { auto old = a; a.value--; return old; }
template <typename T, typename U> constexpr T const& operator*(boxed<T, U> const& a) noexcept { return a.value; }
template <typename T, typename U> constexpr bool operator!(boxed<T, U> const& a) noexcept { return !a.value; }
template <typename T, typename U> constexpr boxed<T, U> operator+(boxed<T, U> const& a, boxed<T, U> const& b) noexcept { return boxed<T, U>{a.value + b.value}; }
template <typename T, typename U> constexpr boxed<T, U> operator-(boxed<T, U> const& a, boxed<T, U> const& b) noexcept { return boxed<T, U>{a.value - b.value}; }
template <typename T, typename U> constexpr boxed<T, U> operator*(boxed<T, U> const& a, boxed<T, U> const& b) noexcept { return boxed<T, U>{a.value * b.value}; }
template <typename T, typename U> constexpr boxed<T, U> operator/(boxed<T, U> const& a, boxed<T, U> const& b) noexcept { return boxed<T, U>{a.value / b.value}; }
template <typename T, typename U> constexpr boxed<T, U> operator%(boxed<T, U> const& a, boxed<T, U> const& b) noexcept { return boxed<T, U>{a.value % b.value}; }

template <typename T, typename U> constexpr boxed<T, U> operator-(boxed<T, U> const& a) noexcept { return boxed<T, U>{-a.value}; }
template <typename T, typename U> constexpr boxed<T, U> operator+(boxed<T, U> const& a) noexcept { return boxed<T, U>{+a.value}; }

template <typename T, typename U> constexpr boxed<T, U> operator+(boxed<T, U> const& a, T b) noexcept { return boxed<T, U>{a.value + b}; }
template <typename T, typename U> constexpr boxed<T, U> operator-(boxed<T, U> const& a, T b) noexcept { return boxed<T, U>{a.value - b}; }
template <typename T, typename U> constexpr boxed<T, U> operator*(boxed<T, U> const& a, T b) noexcept { return boxed<T, U>{a.value * b}; }
template <typename T, typename U> constexpr boxed<T, U> operator/(boxed<T, U> const& a, T b) noexcept { return boxed<T, U>{a.value / b}; }

template <typename T, typename U> constexpr boxed<T, U> operator+(T b, boxed<T, U> const& a) noexcept { return boxed<T, U>{b - a.value}; }
template <typename T, typename U> constexpr boxed<T, U> operator-(T b, boxed<T, U> const& a) noexcept { return boxed<T, U>{b - a.value}; }
template <typename T, typename U> constexpr boxed<T, U> operator*(T b, boxed<T, U> const& a) noexcept { return boxed<T, U>{b * a.value}; }
template <typename T, typename U> constexpr boxed<T, U> operator/(T b, boxed<T, U> const& a) noexcept { return boxed<T, U>{b / a.value}; }

template <typename T, typename U> constexpr boxed<T, U>& operator+=(boxed<T, U>& a, boxed<T, U> const& b) noexcept { a.value += b.value; return a; }
template <typename T, typename U> constexpr boxed<T, U>& operator-=(boxed<T, U>& a, boxed<T, U> const& b) noexcept { a.value -= b.value; return a; }
template <typename T, typename U> constexpr boxed<T, U>& operator*=(boxed<T, U>& a, boxed<T, U> const& b) noexcept { a.value *= b.value; return a; }
template <typename T, typename U> constexpr boxed<T, U>& operator/=(boxed<T, U>& a, boxed<T, U> const& b) noexcept { a.value /= b.value; return a; }
template <typename T, typename U> constexpr boxed<T, U>& operator%=(boxed<T, U>& a, boxed<T, U> const& b) noexcept { a.value %= b.value; return a; }

template <typename T, typename U> std::ostream& operator<<(std::ostream& os, boxed<T, U> const& v) { return os << v.value; }
template <typename T, typename U> constexpr boxed_with_tag<T, U>& operator++(boxed_with_tag<T, U>& a) noexcept { ++a.value; return a; }
template <typename T, typename U> constexpr boxed_with_tag<T, U>& operator--(boxed_with_tag<T, U>& a) noexcept { --a.value; return a; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator++(boxed_with_tag<T, U>& a, int) noexcept { auto old = a; a.value++; return old; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator--(boxed_with_tag<T, U>& a, int) noexcept { auto old = a; a.value--; return old; }
template <typename T, typename U> constexpr T const& operator*(boxed_with_tag<T, U> const& a) noexcept { return a.value; }
template <typename T, typename U> constexpr bool operator!(boxed_with_tag<T, U> const& a) noexcept { return !a.value; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator+(boxed_with_tag<T, U> const& a, boxed_with_tag<T, U> const& b) noexcept { return boxed_with_tag<T, U>{a.value + b.value}; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator-(boxed_with_tag<T, U> const& a, boxed_with_tag<T, U> const& b) noexcept { return boxed_with_tag<T, U>{a.value - b.value}; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator*(boxed_with_tag<T, U> const& a, boxed_with_tag<T, U> const& b) noexcept { return boxed_with_tag<T, U>{a.value * b.value}; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator/(boxed_with_tag<T, U> const& a, boxed_with_tag<T, U> const& b) noexcept { return boxed_with_tag<T, U>{a.value / b.value}; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator%(boxed_with_tag<T, U> const& a, boxed_with_tag<T, U> const& b) noexcept { return boxed_with_tag<T, U>{a.value % b.value}; }

template <typename T, typename U> constexpr boxed_with_tag<T, U> operator-(boxed_with_tag<T, U> const& a) noexcept { return boxed_with_tag<T, U>{-a.value}; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator+(boxed_with_tag<T, U> const& a) noexcept { return boxed_with_tag<T, U>{+a.value}; }

template <typename T, typename U> constexpr boxed_with_tag<T, U> operator+(boxed_with_tag<T, U> const& a, T b) noexcept { return boxed_with_tag<T, U>{a.value + b}; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator-(boxed_with_tag<T, U> const& a, T b) noexcept { return boxed_with_tag<T, U>{a.value - b}; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator*(boxed_with_tag<T, U> const& a, T b) noexcept { return boxed_with_tag<T, U>{a.value * b}; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator/(boxed_with_tag<T, U> const& a, T b) noexcept { return boxed_with_tag<T, U>{a.value / b}; }

template <typename T, typename U> constexpr boxed_with_tag<T, U> operator+(T b, boxed_with_tag<T, U> const& a) noexcept { return boxed_with_tag<T, U>{b - a.value}; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator-(T b, boxed_with_tag<T, U> const& a) noexcept { return boxed_with_tag<T, U>{b - a.value}; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator*(T b, boxed_with_tag<T, U> const& a) noexcept { return boxed_with_tag<T, U>{b * a.value}; }
template <typename T, typename U> constexpr boxed_with_tag<T, U> operator/(T b, boxed_with_tag<T, U> const& a) noexcept { return boxed_with_tag<T, U>{b / a.value}; }

template <typename T, typename U> constexpr boxed_with_tag<T, U>& operator+=(boxed_with_tag<T, U>& a, boxed_with_tag<T, U> const& b) noexcept { a.value += b.value; return a; }
template <typename T, typename U> constexpr boxed_with_tag<T, U>& operator-=(boxed_with_tag<T, U>& a, boxed_with_tag<T, U> const& b) noexcept { a.value -= b.value; return a; }
template <typename T, typename U> constexpr boxed_with_tag<T, U>& operator*=(boxed_with_tag<T, U>& a, boxed_with_tag<T, U> const& b) noexcept { a.value *= b.value; return a; }
template <typename T, typename U> constexpr boxed_with_tag<T, U>& operator/=(boxed_with_tag<T, U>& a, boxed_with_tag<T, U> const& b) noexcept { a.value /= b.value; return a; }
template <typename T, typename U> constexpr boxed_with_tag<T, U>& operator%=(boxed_with_tag<T, U>& a, boxed_with_tag<T, U> const& b) noexcept { a.value %= b.value; return a; }

template <typename T, typename U> std::ostream& operator<<(std::ostream& os, boxed_with_tag<T, U> const& v) { return os << v.value; }
// clang-format on

namespace helper
Expand All @@ -134,7 +144,7 @@ namespace helper
};

template <typename A, typename B>
struct is_boxed<boxed<A, B>>
struct is_boxed<boxed_with_tag<A, B>>
{
constexpr static bool value = true; // NOLINT(readability-identifier-naming)
};
Expand All @@ -144,14 +154,14 @@ namespace helper

// Casts from one boxed type to another boxed type.
template <typename To, typename From, typename FromTag>
constexpr auto boxed_cast(boxed::boxed<From, FromTag> const& from) noexcept
constexpr auto boxed_cast(boxed::boxed_with_tag<From, FromTag> const& from) noexcept
{
return To { static_cast<typename To::inner_type>(from.value) };
}

// Casting a boxed type out of the box.
template <typename To, typename From, typename FromTag>
constexpr auto unbox(boxed::boxed<From, FromTag> const& from) noexcept
constexpr auto unbox(boxed::boxed_with_tag<From, FromTag> const& from) noexcept
{
return static_cast<To>(from.value);
}
Expand All @@ -169,7 +179,7 @@ constexpr auto unbox(T from) noexcept
namespace std
{
template <typename A, typename B>
struct numeric_limits<boxed::boxed<A, B>>
struct numeric_limits<boxed::boxed_with_tag<A, B>>
{
using value_type = A;
using Boxed = boxed::boxed<A, B>;
Expand All @@ -193,9 +203,12 @@ struct numeric_limits<boxed::boxed<A, B>>
namespace std // {{{
{
template <typename T, typename U>
struct hash<boxed::boxed<T, U>>
struct hash<boxed::boxed_with_tag<T, U>>
{
constexpr size_t operator()(boxed::boxed<T, U> v) const noexcept { return std::hash<T> {}(v.value); }
constexpr size_t operator()(boxed::boxed_with_tag<T, U> v) const noexcept
{
return std::hash<T> {}(v.value);
}
};
} // namespace std
// {{{ fmtlib integration
Expand All @@ -209,15 +222,15 @@ namespace fmt
{

template <typename A, typename B>
struct formatter<boxed::boxed<A, B>>
struct formatter<boxed::boxed_with_tag<A, B>>
{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx)
{
return ctx.begin();
}
template <typename FormatContext>
auto format(const boxed::boxed<A, B> _value, FormatContext& ctx)
auto format(const boxed::boxed_with_tag<A, B> _value, FormatContext& ctx)
{
return fmt::format_to(ctx.out(), "{}", _value.value);
}
Expand Down
Loading

0 comments on commit 3d40452

Please sign in to comment.