Skip to content

Commit

Permalink
folly::span_cast
Browse files Browse the repository at this point in the history
Summary:
a simple utility to convert span types to a different span.

Internal

I need it here.
https://www.internalfb.com/code/fbsource/[9f6d918078302a19fc3977b5191d8992e179e4d2]/fbcode/folly/algorithm/simd/FindFixed.h?lines=87

Differential Revision: D61202580
  • Loading branch information
DenisYaroshevskiy authored and facebook-github-bot committed Aug 13, 2024
1 parent 5df7d9a commit 47629f3
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 0 deletions.
26 changes: 26 additions & 0 deletions folly/Traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#pragma once

#include <cassert>
#include <cstdint>
#include <functional>
#include <limits>
Expand All @@ -25,6 +26,10 @@

#include <folly/Portability.h>

#if __cpp_lib_span
#include <span>
#endif

namespace folly {

#if defined(__cpp_lib_type_identity) && __cpp_lib_type_identity >= 201806L
Expand Down Expand Up @@ -1347,4 +1352,25 @@ template <typename T, typename... Dependencies>
using enable_std_hash_helper =
enable_hasher_helper<T, std::hash, Dependencies...>;

#if __cpp_lib_span

/**
* converting a span to a different span.
* treats everything is a just bytes.
*/
template <typename U, typename T, std::size_t Extend>
constexpr auto span_cast(std::span<T, Extend> in) {
U* newData = (U*)in.data();
if constexpr (Extend == std::dynamic_extent) {
assert(in.size() * sizeof(T) % sizeof(U) == 0);
return std::span<U>(newData, in.size() * sizeof(T) / sizeof(U));
} else {
static_assert(in.size() * sizeof(T) % sizeof(U) == 0);
constexpr std::size_t kResSize = Extend * sizeof(T) / sizeof(U);
return std::span<U, kResSize>(newData, kResSize);
}
}

#endif

} // namespace folly
70 changes: 70 additions & 0 deletions folly/test/TraitsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -786,3 +786,73 @@ TEST(Traits, value_list) {
folly::value_list_element_type_t<1, vtag_t<7u, 8, '9'>>>));
EXPECT_EQ(8, (folly::value_list_element_v<1, vtag_t<7u, 8, '9'>>));
}

#if __cpp_lib_span

template <typename To, typename From, std::size_t Extend>
using span_cast_result_type =
decltype(folly::span_cast<To>(std::declval<std::span<From, Extend>>()));

TEST(Traits, SpanCast) {
auto tstSpanCast = [](auto to, auto from) {
ASSERT_EQ(
static_cast<const void*>(from.data()),
static_cast<const void*>(to.data()));

ASSERT_EQ(
static_cast<const void*>(from.data() + from.size()),
static_cast<const void*>(to.data() + to.size()));
};

{
std::array<int, 4> a;
tstSpanCast(folly::span_cast<const char>(std::span(a)), std::span(a));
tstSpanCast(folly::span_cast<double>(std::span(a)), std::span(a));
}

{
std::vector<int> a(4u, 1);
tstSpanCast(folly::span_cast<const char>(std::span(a)), std::span(a));
tstSpanCast(folly::span_cast<double>(std::span(a)), std::span(a));
}

{
const std::vector<int> a(4u, 1);
tstSpanCast(folly::span_cast<char>(std::span(a)), std::span(a));
}

// types
{
static_assert(std::is_same_v<
std::span<char>,
span_cast_result_type<char, int, std::dynamic_extent>>);
static_assert(std::is_same_v<
std::span<char>,
span_cast_result_type<char, const int, std::dynamic_extent>>);
static_assert(std::is_same_v<
std::span<char, 12>,
span_cast_result_type<char, const int, 3>>);
static_assert(std::is_same_v<
std::span<const char, 12>,
span_cast_result_type<const char, char, 12>>);
static_assert(std::is_same_v<
std::span<int, 3>,
span_cast_result_type<int, const char, 12>>);
}

// constexpr
{
[[maybe_unused]] constexpr auto _ = [] {
std::array<int, 4> a{0, 1, 2, 3};
std::span<int, 4> mutableAFixed(a);
std::span<int> mutableADynamic(a);
auto resFixed = folly::span_cast<const int>(mutableAFixed);
(void)resFixed;
auto resDynamic = folly::span_cast<const int>(mutableADynamic);
(void)resDynamic;
return 0;
}();
}
}

#endif

0 comments on commit 47629f3

Please sign in to comment.