Skip to content

Commit

Permalink
added row conversions
Browse files Browse the repository at this point in the history
  • Loading branch information
marzer committed Aug 6, 2023
1 parent 4304d20 commit 20a1fcb
Show file tree
Hide file tree
Showing 11 changed files with 351 additions and 327 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Changelog

## Unreleased
## v0.4.0

- Fixed `soagen::is_table<>`
- Added support for emplace-constructing column values by unpacking all `std::tuple`-like types (not just the `emplacer`)
- Added support for taking `std::integral_constants` in `for_each_column()`
- Added `soagen::same_table_type<>`
- Added conversions between `soagen::row<>` specializations
- Optimized instantiation overhead for most type-traits

## v0.3.0
Expand Down
11 changes: 8 additions & 3 deletions docs/pages/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -875,15 +875,15 @@ game::entities e1;
game::entities e2;

e1.push_back(0, "cat");
e1.push_back(1, "dog");

e2.push_back(0, "cat");

e1.push_back(1, "dog");
e2.push_back(1, "dog");

std::cout << (e1 < e2) << "\n";
std::cout << (e1 <= e2) << "\n";
std::cout << (e1 > e2) << "\n";
std::cout << (e1 >= e2) << "\n";
std::cout << (e1 >= e2) << "\n\n";

e2[1].name = "bird";

Expand All @@ -895,6 +895,11 @@ std::cout << (e1 >= e2) << "\n";
```

@out
false
true
false
true

true
true
false
Expand Down
6 changes: 5 additions & 1 deletion src/soagen/hpp/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,14 @@ namespace soagen
template <typename T>
inline constexpr bool is_unsigned = is_integer<T> && std::is_unsigned_v<T>;

/// @brief True if all `U` are the same as `T`.
/// @brief True if any `U` are the same as `T`.
template <typename T, typename... U>
inline constexpr bool any_same = (false || ... || std::is_same_v<T, U>);

/// @brief True if `Value` is in the list `Values`.
template <auto Value, auto... Values>
inline constexpr bool any_same_value = ((Value == Values) || ...);

/// @brief True if `T` is a soagen-generated SoA table type.
template <typename T>
inline constexpr bool is_soa = POXY_IMPLEMENTATION_DETAIL(false); // specialized in generated code
Expand Down
63 changes: 0 additions & 63 deletions src/soagen/hpp/generated/functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
#pragma once

#include "../core.hpp"
#if SOAGEN_CPP >= 20 && defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806
#include <bit>
#endif
#include "../header_start.hpp"

namespace soagen
Expand Down Expand Up @@ -165,66 +162,6 @@ namespace soagen
}
}

#if SOAGEN_CPP >= 20 && defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806

#define SOAGEN_HAS_INTRINSIC_BIT_CAST 1

using std::bit_cast;

#else

SOAGEN_CONSTRAINED_TEMPLATE((std::is_trivially_copyable_v<From> //
&& std::is_trivially_copyable_v<To> //
&& sizeof(From) == sizeof(To)),
typename To,
typename From)
SOAGEN_PURE_INLINE_GETTER
constexpr To bit_cast(const From& from) noexcept
{
static_assert(!std::is_reference_v<To> && !std::is_reference_v<From>);

#if SOAGEN_CLANG >= 11 || SOAGEN_GCC >= 11 || SOAGEN_MSVC >= 1926 \
|| (!SOAGEN_CLANG && !SOAGEN_GCC && SOAGEN_HAS_BUILTIN(__builtin_bit_cast))

#define SOAGEN_HAS_INTRINSIC_BIT_CAST 1
return __builtin_bit_cast(To, from);

#else

#define SOAGEN_HAS_INTRINSIC_BIT_CAST 0

if constexpr (std::is_same_v<std::remove_cv_t<From>, std::remove_cv_t<To>>)
{
return from;
}
else if constexpr (!std::is_nothrow_default_constructible_v<std::remove_cv_t<To>>)
{
union proxy_t
{
alignas(To) unsigned char dummy[sizeof(To)];
std::remove_cv_t<To> to;

proxy_t() noexcept
{}
};

proxy_t proxy;
std::memcpy(&proxy.to, &from, sizeof(To));
return proxy.to;
}
else
{
static_assert(std::is_nothrow_default_constructible_v<std::remove_cv_t<To>>,
"Bit-cast fallback requires the To type be nothrow default-constructible");

std::remove_cv_t<To> to;
std::memcpy(&to, &from, sizeof(To));
return to;
}
#endif
}

#endif
}

#include "../header_end.hpp"
64 changes: 4 additions & 60 deletions src/soagen/hpp/iterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,63 +10,8 @@
namespace soagen
{
/// @cond
template <typename, size_t...>
class iterator;

namespace detail
{
// iterator implicit conversions are allowed when:
// - changing columns
// - losing rvalue (Table&& -> Table&), (const Table&& -> const Table&)
// - gaining const (Table& -> const Table&, Table&& -> const Table&&)
// - any combination of the three

template <typename From, typename To>
inline constexpr bool iterator_implicit_conversion_ok = false;

template <typename Table, size_t... ColumnsA, size_t... ColumnsB>
inline constexpr bool iterator_implicit_conversion_ok<iterator<Table, ColumnsA...>, //
iterator<Table, ColumnsB...>> = true;

template <typename Table, size_t... ColumnsA, size_t... ColumnsB>
inline constexpr bool iterator_implicit_conversion_ok<iterator<Table&&, ColumnsA...>, //
iterator<Table&, ColumnsB...>> = true;

template <typename Table, size_t... ColumnsA, size_t... ColumnsB>
inline constexpr bool iterator_implicit_conversion_ok<iterator<const Table&&, ColumnsA...>, //
iterator<const Table&, ColumnsB...>> = true;

template <typename Table, size_t... ColumnsA, size_t... ColumnsB>
inline constexpr bool iterator_implicit_conversion_ok<iterator<Table&, ColumnsA...>, //
iterator<const Table&, ColumnsB...>> = true;

template <typename Table, size_t... ColumnsA, size_t... ColumnsB>
inline constexpr bool iterator_implicit_conversion_ok<iterator<Table&&, ColumnsA...>, //
iterator<const Table&&, ColumnsB...>> = true;

template <typename Table, size_t... ColumnsA, size_t... ColumnsB>
inline constexpr bool iterator_implicit_conversion_ok<iterator<Table&&, ColumnsA...>, //
iterator<const Table&, ColumnsB...>> = true;

// iterator explicit conversions are allowed when gaining rvalue and optionally gaining const
// (note that we specifically avoid providing anything that would be the moral equivalent of
// a const_cast because that armory is filled with very large and powerful footguns)

template <typename From, typename To>
inline constexpr bool iterator_explicit_conversion_ok = false;

template <typename Table, size_t... ColumnsA, size_t... ColumnsB>
inline constexpr bool iterator_explicit_conversion_ok<iterator<Table&, ColumnsA...>, //
iterator<Table&&, ColumnsB...>> = true;

template <typename Table, size_t... ColumnsA, size_t... ColumnsB>
inline constexpr bool iterator_explicit_conversion_ok<iterator<const Table&, ColumnsA...>, //
iterator<const Table&&, ColumnsB...>> = true;

template <typename Table, size_t... ColumnsA, size_t... ColumnsB>
inline constexpr bool iterator_explicit_conversion_ok<iterator<Table&, ColumnsA...>, //
iterator<const Table&&, ColumnsB...>> = true;

template <typename T>
struct arrow_proxy
{
Expand Down Expand Up @@ -359,9 +304,8 @@ namespace soagen
///
/// @attention There are no conversions provided which offer the equivalent of a `const_cast`-by-proxy.
/// This is by design.
///
SOAGEN_CONSTRAINED_TEMPLATE((detail::iterator_implicit_conversion_ok<iterator, iterator<T, Cols...>>
&& !detail::iterator_explicit_conversion_ok<iterator, iterator<T, Cols...>>),
SOAGEN_CONSTRAINED_TEMPLATE((detail::implicit_conversion_ok<Table, T>
&& !detail::explicit_conversion_ok<Table, T>),
typename T,
size_t... Cols)
SOAGEN_PURE_INLINE_GETTER
Expand All @@ -372,8 +316,8 @@ namespace soagen

/// @cond

SOAGEN_CONSTRAINED_TEMPLATE((!detail::iterator_implicit_conversion_ok<iterator, iterator<T, Cols...>>
&& detail::iterator_explicit_conversion_ok<iterator, iterator<T, Cols...>>),
SOAGEN_CONSTRAINED_TEMPLATE((!detail::implicit_conversion_ok<Table, T>
&& detail::explicit_conversion_ok<Table, T>),
typename T,
size_t... Cols)
SOAGEN_PURE_INLINE_GETTER
Expand Down
126 changes: 126 additions & 0 deletions src/soagen/hpp/row.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,83 @@

namespace soagen
{
/// @cond
template <typename, size_t...>
struct row;

namespace detail
{
// general rules for allowing implicit conversions:
// - losing rvalue (T&& -> T&), (const T&& -> const T&)
// - gaining const (T& -> const T&, T&& -> const T&&)
// - both

template <typename From, typename To>
inline constexpr bool implicit_conversion_ok = false;

template <typename T>
inline constexpr bool implicit_conversion_ok<T, T> = true;

template <typename T>
inline constexpr bool implicit_conversion_ok<T&, const T&> = true;

template <typename T>
inline constexpr bool implicit_conversion_ok<T&&, T&> = true;

template <typename T>
inline constexpr bool implicit_conversion_ok<T&&, const T&> = true;

template <typename T>
inline constexpr bool implicit_conversion_ok<T&&, const T&&> = true;

// general rules for allowing explicit conversions:

template <typename From, typename To>
inline constexpr bool explicit_conversion_ok = false;

template <typename T>
inline constexpr bool explicit_conversion_ok<T&, T&&> = true;

template <typename T>
inline constexpr bool explicit_conversion_ok<T&, const T&&> = true;

// tests for compatible column permutations:

template <typename From, typename To>
inline constexpr bool column_conversion_ok = false;

template <size_t... Columns>
inline constexpr bool column_conversion_ok<std::index_sequence<Columns...>, std::index_sequence<Columns...>> =
true;

template <size_t... ColumnsA, size_t... ColumnsB>
inline constexpr bool column_conversion_ok<std::index_sequence<ColumnsA...>, std::index_sequence<ColumnsB...>> =
(any_same_value<ColumnsB, ColumnsA...> && ...);

// row implicit conversions:

template <typename From, typename To>
inline constexpr bool row_implicit_conversion_ok = false;

template <typename TableA, size_t... ColumnsA, typename TableB, size_t... ColumnsB>
inline constexpr bool row_implicit_conversion_ok<row<TableA, ColumnsA...>, //
row<TableB, ColumnsB...>> =
implicit_conversion_ok<TableA, TableB>
&& column_conversion_ok<std::index_sequence<ColumnsA...>, std::index_sequence<ColumnsB...>>;

// row explicit conversions:

template <typename From, typename To>
inline constexpr bool row_explicit_conversion_ok = false;

template <typename TableA, size_t... ColumnsA, typename TableB, size_t... ColumnsB>
inline constexpr bool row_explicit_conversion_ok<row<TableA, ColumnsA...>, //
row<TableB, ColumnsB...>> =
explicit_conversion_ok<TableA, TableB>
&& column_conversion_ok<std::index_sequence<ColumnsA...>, std::index_sequence<ColumnsB...>>;
}
/// @endcond

/// @brief Base class for soagen::row.
/// @details Specialize this to add functionality to all rows of a particular type via CRTP.
template <typename Derived>
Expand Down Expand Up @@ -148,6 +225,55 @@ namespace soagen
}

/// @}

/// @name Conversion
/// @{

/// @brief Converts between different rows for the same table type.
///
/// @details This operator allows the following conversions, only some of which are implicit: <table>
/// <tr><th> From <th> To <th> `explicit`? <th> Note
/// <tr><td> `Table&` <td> `const Table&` <td> <td> gains `const`
/// <tr><td> `Table&&` <td> `Table&` <td> <td> `&&` &rarr; `&`
/// <tr><td> `Table&&` <td> `const Table&` <td> <td> `&&` &rarr; `&`, gains `const`
/// <tr><td> `Table&&` <td> `const Table&&` <td> <td> gains `const`
/// <tr><td> `const Table&&` <td> `const Table&` <td> <td> `&&` &rarr; `&`
/// <tr><td> `Table&` <td> `Table&&` <td> `explicit` <td> Equivalent to `std::move()`
/// <tr><td> `Table&` <td> `const Table&&` <td> `explicit` <td> Equivalent to `std::move()`
/// <tr><td> `const Table&` <td> `const Table&&` <td> `explicit` <td> Equivalent to `std::move()`
/// </table>
///
/// @note Any of these conversions can also reduce or re-order the columns viewed by the row.
///
/// @attention There are no conversions provided which offer the equivalent of a `const_cast`-by-proxy.
/// This is by design.
SOAGEN_CONSTRAINED_TEMPLATE((detail::row_implicit_conversion_ok<row, row<T, Cols...>>
&& !detail::row_explicit_conversion_ok<row, row<T, Cols...>>),
typename T,
size_t... Cols)
SOAGEN_PURE_INLINE_GETTER
constexpr operator row<T, Cols...>() const noexcept
{
return row<T, Cols...>{ { static_cast<decltype(std::declval<row<T, Cols...>>().template column<Cols>())>(
this->template column<Cols>()) }... };
}

/// @cond

SOAGEN_CONSTRAINED_TEMPLATE((!detail::row_implicit_conversion_ok<row, row<T, Cols...>>
&& detail::row_explicit_conversion_ok<row, row<T, Cols...>>),
typename T,
size_t... Cols)
SOAGEN_PURE_INLINE_GETTER
explicit constexpr operator row<T, Cols...>() const noexcept
{
return row<T, Cols...>{ { static_cast<decltype(std::declval<row<T, Cols...>>().template column<Cols>())>(
this->template column<Cols>()) }... };
}

/// @endcond

/// @}
};

/// @brief True if `T` is an instance of #soagen::row.
Expand Down
Loading

0 comments on commit 20a1fcb

Please sign in to comment.