Skip to content

Commit

Permalink
simplify usage of blade_type_from_* traits
Browse files Browse the repository at this point in the history
Allow use of ranges with `blade_type_from_dimensions` and unsigned
integers with `blade_type_from_mask` traits. These traits now specify
the non-type template paramter to be `detail::array_subset` and
`detail::structural_bitset` respectively.

This commit also provides converting constructors for
`detail::array_subset` and `detail::structural_bitset` and makes changes
necessary to meet the criteria of a structural type.

Change-Id: I729e67cdf36f0a20d4ff638ef2cdf37943620116
  • Loading branch information
oliverlee committed Sep 29, 2024
1 parent 7397494 commit 4975653
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 85 deletions.
2 changes: 0 additions & 2 deletions rigid_geometric_algebra/blade.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include "rigid_geometric_algebra/detail/decays_to.hpp"
#include "rigid_geometric_algebra/detail/derive_subtraction.hpp"
#include "rigid_geometric_algebra/detail/derive_vector_space_operations.hpp"
#include "rigid_geometric_algebra/detail/even.hpp"
#include "rigid_geometric_algebra/detail/indices_array.hpp"
#include "rigid_geometric_algebra/detail/negate_if_odd.hpp"
#include "rigid_geometric_algebra/detail/size_checked_subrange.hpp"
Expand All @@ -19,7 +18,6 @@
#include <concepts>
#include <cstddef>
#include <format>
#include <functional>
#include <initializer_list>
#include <tuple>
#include <type_traits>
Expand Down
8 changes: 2 additions & 6 deletions rigid_geometric_algebra/blade_complement_type.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "rigid_geometric_algebra/blade_type_from.hpp"
#include "rigid_geometric_algebra/detail/disjoint_subset.hpp"
#include "rigid_geometric_algebra/is_blade.hpp"

Expand All @@ -25,12 +26,7 @@ struct blade_complement_type_<true, blade_<A, Is...>>
return detail::disjoint_subset(Is..., Js...);
}(std::make_index_sequence<algebra_dimension_v<A>>{});

template <std::size_t... Ks>
static constexpr auto type_impl(std::index_sequence<Ks...>)
-> blade_<A, complement_dimensions[Ks]...>;

using type = decltype(type_impl(
std::make_index_sequence<complement_dimensions.size()>{}));
using type = blade_type_from_dimensions_t<A, complement_dimensions>;
};

} // namespace detail
Expand Down
50 changes: 20 additions & 30 deletions rigid_geometric_algebra/blade_type_from.hpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#pragma once

#include "rigid_geometric_algebra/blade.hpp"
#include "rigid_geometric_algebra/detail/array_subset.hpp"
#include "rigid_geometric_algebra/detail/indices_array.hpp"
#include "rigid_geometric_algebra/is_algebra.hpp"
#include "rigid_geometric_algebra/detail/structural_bitset.hpp"

#include <cstddef>
#include <ranges>
#include <utility>

namespace rigid_geometric_algebra {
Expand All @@ -17,14 +17,15 @@ namespace rigid_geometric_algebra {
/// ~~~{.cpp}
/// static_assert(std::is_same_v<
/// blade<A, 0, 2, 1>,
/// blade_type_from_dimensions_t<A, std::array{0, 2, 1}>
/// blade_type_from_dimensions_t<A, {0, 2, 1}>
/// >);
/// ~~~
///
/// @{

template <class A, std::ranges::random_access_range auto dimensions>
requires is_algebra_v<A>
template <
class A,
detail::array_subset<std::size_t, algebra_dimension_v<A>> dimensions>
struct blade_type_from_dimensions
{
using type =
Expand All @@ -34,45 +35,34 @@ struct blade_type_from_dimensions
}(std::make_index_sequence<dimensions.size()>{}));
};

template <class A, auto dimensions>
template <
class A,
detail::array_subset<std::size_t, algebra_dimension_v<A>> dimensions>
using blade_type_from_dimensions_t =
typename blade_type_from_dimensions<A, dimensions>::type;

/// @}

/// determine the blade type from a dimension mask or range of dimensions
/// determine the blade type from a dimension mask
/// @tparam A algebra type
/// @tparam mask_or_dimensions forward range of `bool` or random access range
/// of dimensions
/// @tparam mask range of `bool`
///
/// Determins the `blade` type given an algebra type and either a mask or
/// dimensions. If `mask_or_dimensions` has a range value type of `bool`, it is
/// interpreted as a mask. Otherwise, it is interpreted as dimensions.
/// Determins the `blade` type given an algebra type and a mask of dimensions.
/// Each bool in the mask correspond to a dimension, starting dimension 0.
///
/// @note The `blade` type given a mask is always in canonical form.
/// @note The `blade` type is always in canonical form.
///
/// @{

template <class A, std::ranges::forward_range auto mask_or_dimensions>
requires is_algebra_v<A>
struct blade_type_from
template <class A, detail::structural_bitset<algebra_dimension_v<A>> mask>
struct blade_type_from_mask
{
using type = typename decltype([] {
if constexpr (
std::is_same_v<
bool,
std::ranges::range_value_t<decltype(mask_or_dimensions)>>) {
static constexpr auto dimensions =
detail::indices_array<mask_or_dimensions>;
return blade_type_from_dimensions<A, dimensions>{};
} else {
return blade_type_from_dimensions<A, mask_or_dimensions>{};
}
}())::type;
static constexpr auto dimensions = detail::indices_array<mask>;
using type = blade_type_from_dimensions_t<A, dimensions>;
};

template <class A, auto mask_or_dimensions>
using blade_type_from_t = typename blade_type_from<A, mask_or_dimensions>::type;
template <class A, detail::structural_bitset<algebra_dimension_v<A>> mask>
using blade_type_from_mask_t = typename blade_type_from_mask<A, mask>::type;

/// @}

Expand Down
25 changes: 21 additions & 4 deletions rigid_geometric_algebra/detail/array_subset.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
#pragma once

#include "rigid_geometric_algebra/detail/contract.hpp"
#include "rigid_geometric_algebra/detail/decays_to.hpp"

#include <algorithm>
#include <array>
#include <concepts>
#include <cstddef>
#include <initializer_list>
#include <iterator>
#include <ranges>

namespace rigid_geometric_algebra::detail {
Expand All @@ -19,17 +24,29 @@ template <class T, std::size_t Capacity>
class array_subset
: public std::ranges::view_interface<array_subset<T, Capacity>>
{
public:
using base_type = std::array<T, Capacity>;
base_type base_{};
std::size_t size_{};

public:
constexpr array_subset(const base_type& base, std::size_t size)
: base_{base}, size_{size}
template <std::ranges::random_access_range R>
requires (not detail::decays_to<R, array_subset>) and
std::constructible_from<T, std::ranges::range_value_t<R>>
constexpr array_subset(R&& rng) : size_{rng.size()}
{
detail::precondition(size_ <= Capacity);
detail::precondition(rng.size() <= Capacity);
std::ranges::copy(rng, base_.begin());
}

template <std::random_access_iterator I, std::sentinel_for<I> S>
constexpr array_subset(I first, S last)
: array_subset{std::ranges::subrange{first, last}}
{}

constexpr array_subset(std::initializer_list<std::size_t> il)
: array_subset{std::ranges::subrange{il.begin(), il.end()}}
{}

constexpr auto begin() const noexcept { return base_.begin(); }
constexpr auto end() const noexcept { return begin() + size_; }
};
Expand Down
2 changes: 1 addition & 1 deletion rigid_geometric_algebra/detail/disjoint_subset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ inline constexpr class
pending = {pending.begin(), last};
}

return {dims, static_cast<std::size_t>(pending.begin() - dims.begin())};
return {dims.begin(), pending.begin()};
}

} disjoint_subset{};
Expand Down
33 changes: 25 additions & 8 deletions rigid_geometric_algebra/detail/structural_bitset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace rigid_geometric_algebra::detail {
template <std::size_t N>
struct structural_bitset
{
static_assert(N <= 8);
static_assert(N <= 8, "this type only supports algebras up to 8 dimensions");
using value_type = std::uint8_t;

class const_iterator
Expand Down Expand Up @@ -69,7 +69,24 @@ struct structural_bitset

/// unsigned integer representation of the data
///
value_type value{};
/// @note bits at index size or higher are ignored
///
value_type value_{};

/// construct with no bits
///
structural_bitset() = default;

/// construct from bits
/// @pre bits does not set bits at size or higher
///
constexpr structural_bitset(value_type bits) : value_{bits}
{
static constexpr auto mask = (value_type{} - value_type{1}) << size;
detail::precondition(
(bits &= mask) == value_type{},
"`bits` has bits higher than structural_bitset size");
}

/// sets bits to `true`
/// @tparam Self reference to `structural_bitset` type
Expand All @@ -90,7 +107,7 @@ struct structural_bitset
{
detail::precondition(
pos < size, "`pos` exceeds number of bits in `structural_bitset`");
self.value |= std::uint8_t{1} << pos;
self.value_ |= std::uint8_t{1} << pos;
return std::forward<Self>(self);
}

Expand All @@ -99,7 +116,7 @@ struct structural_bitset
[[nodiscard]]
constexpr auto count() const noexcept -> std::size_t
{
return std::size_t(std::popcount(value));
return std::size_t(std::popcount(value_));
}

/// returns the value of a bit
Expand All @@ -112,7 +129,7 @@ struct structural_bitset
{
detail::precondition(
pos < size, "`pos` exceeds number of bits in `structural_bitset`");
return (value & (std::uint8_t{1} << pos)) != 0;
return (value_ & (std::uint8_t{1} << pos)) != 0;
}

/// returns the binary OR between two `structural_bitset`s
Expand All @@ -121,7 +138,7 @@ struct structural_bitset
operator|(structural_bitset lhs, structural_bitset rhs) noexcept
-> structural_bitset
{
return {lhs.value |= rhs.value};
return {lhs.value_ |= rhs.value_};
}

/// returns the binary AND between two `structural_bitset`s
Expand All @@ -130,15 +147,15 @@ struct structural_bitset
operator&(structural_bitset lhs, structural_bitset rhs) noexcept
-> structural_bitset
{
return {lhs.value &= rhs.value};
return {lhs.value_ &= rhs.value_};
}

/// returns an unsigned integer representation of the data
///
[[nodiscard]]
constexpr auto to_unsigned() const noexcept -> value_type
{
return value;
return value_;
}

/// iterators for range-based access
Expand Down
1 change: 1 addition & 0 deletions rigid_geometric_algebra/rigid_geometric_algebra.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace rigid_geometric_algebra {} // namespace rigid_geometric_algebra
#include "rigid_geometric_algebra/blade.hpp"
#include "rigid_geometric_algebra/blade_complement_type.hpp"
#include "rigid_geometric_algebra/blade_sum.hpp"
#include "rigid_geometric_algebra/blade_type_from.hpp"
#include "rigid_geometric_algebra/canonical_type.hpp"
#include "rigid_geometric_algebra/complement.hpp"
#include "rigid_geometric_algebra/field.hpp"
Expand Down
11 changes: 5 additions & 6 deletions rigid_geometric_algebra/scalar_type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

#include "rigid_geometric_algebra/algebra_dimension.hpp"
#include "rigid_geometric_algebra/blade.hpp"
#include "rigid_geometric_algebra/blade_type_from.hpp"
#include "rigid_geometric_algebra/is_algebra.hpp"

#include <cstddef>
#include <utility>
#include <ranges>

namespace rigid_geometric_algebra {

Expand All @@ -28,11 +29,9 @@ struct antiscalar_
template <class A>
struct antiscalar_<true, A>
{
using type =
decltype([]<std::size_t... Is>(std::index_sequence<Is...>)
-> ::rigid_geometric_algebra::blade<A, Is...> {
return {};
}(std::make_index_sequence<algebra_dimension_v<A>>{}));
using type = blade_type_from_dimensions_t<
A,
std::views::iota(0UZ, algebra_dimension_v<A>)>;
};

} // namespace detail
Expand Down
13 changes: 8 additions & 5 deletions rigid_geometric_algebra/sorted_canonical_blades.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,20 @@ struct sorted_canonical_blades
using A = common_algebra_type_t<Bs...>;

static constexpr auto sorted = [] {
auto values = std::array{blade_ordering<A>{Bs::dimension_mask}...};
std::ranges::sort(values);
const auto duplicates = std::ranges::unique(values);
return detail::array_subset(values, values.size() - duplicates.size());
auto blades = std::array{blade_ordering<A>{Bs::dimension_mask}...};

std::ranges::sort(blades);
const auto [last, _] = std::ranges::unique(blades);

return detail::array_subset<blade_ordering<A>, sizeof...(Bs)>{
blades.begin(), last};
}();

static_assert(sorted.size() != 0);

template <std::size_t... Is>
static constexpr auto impl(std::index_sequence<Is...>)
-> detail::type_list<blade_type_from_t<A, sorted[Is].mask>...>;
-> detail::type_list<blade_type_from_mask_t<A, sorted[Is].mask>...>;

using type = decltype(impl(std::make_index_sequence<sorted.size()>{}));
};
Expand Down
4 changes: 2 additions & 2 deletions rigid_geometric_algebra/wedge.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ class wedge_blade_fn
using blade_result_t = decltype([] {
using A = common_algebra_type_t<B1, B2>;

static constexpr auto joined =
static constexpr auto mask =
(std::remove_cvref_t<B1>::dimension_mask |
std::remove_cvref_t<B2>::dimension_mask);

return blade_type_from_t<A, joined>{};
return blade_type_from_mask_t<A, mask>{};
}());

public:
Expand Down
Loading

0 comments on commit 4975653

Please sign in to comment.