Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 6 additions & 17 deletions src/fury/encoder/row_encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#pragma once

#include "fury/meta/field_info.h"
#include "fury/meta/type_traits.h"
#include "fury/row/row.h"
#include "src/fury/row/writer.h"
#include <type_traits>
Expand Down Expand Up @@ -58,18 +59,6 @@ template <> struct ArrowSchemaBasicType<double> {
static inline constexpr const auto value = arrow::float64;
};

template <typename> struct RemoveMemberPointer;

template <typename T, typename U> struct RemoveMemberPointer<T U::*> {
using type = T;
};

template <typename T>
using RemoveMemberPointerT = typename RemoveMemberPointer<T>::type;

template <typename T>
using RemoveCVRefT = std::remove_cv_t<std::remove_reference_t<T>>;

inline std::string StringViewToString(std::string_view s) {
return {s.begin(), s.end()};
}
Expand Down Expand Up @@ -104,8 +93,8 @@ struct RowEncodeTrait<T, std::enable_if_t<std::is_class_v<T>>> {
static arrow::FieldVector FieldVectorImpl(std::index_sequence<I...>) {
return {arrow::field(
details::StringViewToString(FieldInfo::Names[I]),
RowEncodeTrait<details::RemoveMemberPointerT<details::RemoveCVRefT<
decltype(std::get<I>(FieldInfo::Ptrs))>>>::Type())...};
RowEncodeTrait<meta::RemoveMemberPointerCVRefT<decltype(std::get<I>(
FieldInfo::Ptrs))>>::Type())...};
}

static auto FieldVector() {
Expand All @@ -122,9 +111,9 @@ struct RowEncodeTrait<T, std::enable_if_t<std::is_class_v<T>>> {
template <typename FieldInfo, size_t... I>
static auto WriteImpl(const T &value, RowWriter &writer,
std::index_sequence<I...>) {
(RowEncodeTrait<details::RemoveMemberPointerT<
details::RemoveCVRefT<decltype(std::get<I>(FieldInfo::Ptrs))>>>::
Write(value.*std::get<I>(FieldInfo::Ptrs), writer, I),
(RowEncodeTrait<meta::RemoveMemberPointerCVRefT<decltype(std::get<I>(
FieldInfo::Ptrs))>>::Write(value.*std::get<I>(FieldInfo::Ptrs), writer,
I),
...);
}

Expand Down
10 changes: 10 additions & 0 deletions src/fury/meta/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,13 @@ cc_test(
"@com_google_googletest//:gtest",
],
)

cc_test(
name = "type_traits_test",
srcs = ["type_traits_test.cc"],
copts = COPTS,
deps = [
":fury_meta",
"@com_google_googletest//:gtest",
],
)
30 changes: 21 additions & 9 deletions src/fury/meta/field_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,42 @@
#pragma once

#include "fury/meta/preprocessor.h"
#include "fury/meta/type_traits.h"
#include <array>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>

namespace fury {

namespace meta {

namespace details {

// dependent name for constant `false` to workaround static_assert(false) issue
// before C++23
template <typename T> constexpr inline bool AlwaysFalse = false;

} // namespace details

// decltype(FuryFieldInfo<T>(v)) records field meta information for type T
// it includes:
// - number of fields: typed size_t
// - field names: typed `std::string_view`
// - field member points: typed `decltype(a) T::*` for any member `T::a`
template <typename T> constexpr auto FuryFieldInfo(const T &) noexcept {
static_assert(details::AlwaysFalse<T>,
static_assert(AlwaysFalse<T>,
"FURY_FIELD_INFO for type T is expected but not defined");
}

namespace details {

// it must be able to be executed in compile-time
template <typename FieldInfo, size_t... I>
constexpr bool IsValidFieldInfoImpl(std::index_sequence<I...>) {
return IsUnique<std::get<I>(FieldInfo::Ptrs)...>::value;
}

} // namespace details

template <typename FieldInfo> constexpr bool IsValidFieldInfo() {
return details::IsValidFieldInfoImpl<FieldInfo>(
std::make_index_sequence<FieldInfo::Size>{});
}

} // namespace meta

} // namespace fury
Expand All @@ -67,6 +76,9 @@ template <typename T> constexpr auto FuryFieldInfo(const T &) noexcept {
static inline constexpr auto Ptrs = std::tuple{ \
FURY_PP_FOREACH_1(FURY_FIELD_INFO_PTRS_FUNC, type, __VA_ARGS__)}; \
}; \
static_assert( \
fury::meta::IsValidFieldInfo<FuryFieldInfoImpl<type>>(), \
"duplicated fields in FURY_FIELD_INFO arguments are detected"); \
inline constexpr auto FuryFieldInfo(const type &) noexcept { \
return FuryFieldInfoImpl<type>{}; \
};
64 changes: 64 additions & 0 deletions src/fury/meta/type_traits.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2023 The Fury Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <type_traits>

namespace fury {

namespace meta {

// dependent name for constant `false` to workaround static_assert(false) issue
// before C++23
template <typename T> constexpr inline bool AlwaysFalse = false;

// T U::* -> T
template <typename> struct RemoveMemberPointer;

template <typename T, typename U> struct RemoveMemberPointer<T U::*> {
using type = T;
};

template <typename T>
using RemoveMemberPointerT = typename RemoveMemberPointer<T>::type;

// same as std::remove_cvref_t since C++20
template <typename T>
using RemoveCVRefT = std::remove_cv_t<std::remove_reference_t<T>>;

template <typename T>
using RemoveMemberPointerCVRefT = RemoveMemberPointerT<RemoveCVRefT<T>>;

template <auto V1, auto V2>
inline constexpr bool IsSameValue =
std::is_same_v<std::integral_constant<decltype(V1), V1>,
std::integral_constant<decltype(V2), V2>>;

template <auto V, auto... Vs>
inline constexpr bool ContainsValue =
std::disjunction_v<std::bool_constant<IsSameValue<V, Vs>>...>;

template <auto...> struct IsUnique : std::true_type {};

template <auto V1, auto... VN>
struct IsUnique<V1, VN...>
: std::bool_constant<!ContainsValue<V1, VN...> && IsUnique<VN...>::value> {
};

} // namespace meta

} // namespace fury
70 changes: 70 additions & 0 deletions src/fury/meta/type_traits_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2023 The Fury Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "gtest/gtest.h"

#include "fury/meta/field_info.h"
#include "src/fury/meta/type_traits.h"

namespace fury {

namespace test {

using namespace meta;

struct A {
int x;
float y;
};

TEST(Meta, RemoveMemberPointer) {
static_assert(std::is_same_v<RemoveMemberPointerT<int A::*>, int>);
static_assert(std::is_same_v<RemoveMemberPointerT<bool A::*>, bool>);
}

TEST(Meta, IsSameValue) {
static_assert(IsSameValue<&A::x, &A::x>);
static_assert(!IsSameValue<&A::x, &A::y>);

static_assert(!IsSameValue<1, true>);
static_assert(IsSameValue<2, 2>);
}

TEST(Meta, ContainsValue) {
static_assert(ContainsValue<1, 1, 2, 3>);
static_assert(ContainsValue<2, 1, 2, 3>);
static_assert(ContainsValue<3, 1, 2, 3>);
static_assert(!ContainsValue<4, 1, 2, 3>);
static_assert(ContainsValue<true, 1, true, &A::x, 'a'>);
static_assert(ContainsValue<'a', 1, true, &A::x, 'a'>);
static_assert(!ContainsValue<0, 1, true, &A::x, 'a'>);
}

TEST(Meta, IsUnique) {
static_assert(IsUnique<1, 2, 3>::value);
static_assert(IsUnique<1, false, true, 3, &A::x>::value);
static_assert(!IsUnique<1, false, true, false, &A::x>::value);
static_assert(!IsUnique<1, false, true, &A::x, 1>::value);
}

} // namespace test

} // namespace fury

int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}