Skip to content

Commit

Permalink
Add initial pass of C++20 invocable map with Call operator.
Browse files Browse the repository at this point in the history
This flavour no longer requires a clang extension and so should unlock other compilers.

In a downstream CL I will add this to ObjectRef to enable the new syntax and eventually update existing usage.

#42

PiperOrigin-RevId: 710513656
  • Loading branch information
jwhpryor authored and copybara-github committed Dec 29, 2024
1 parent d855896 commit 0ef08a7
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 5 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
bazel*
.vscode
13 changes: 12 additions & 1 deletion implementation/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ namespace jni {

template <typename Extends_, typename Constructors_, typename Static_,
typename Methods_, typename Fields_>
struct Class {};
struct Class {
constexpr Class() = default;
constexpr Class(const char* name) {}
};

template <typename Extends_, typename... Constructors_,
typename... StaticMethods_, typename... StaticFields_,
Expand Down Expand Up @@ -70,6 +73,14 @@ struct Class<Extends_, std::tuple<Constructors_...>,
// provided where they are and aren't present.
////////////////////////////////////////////////////////////////////////////////

// To stifle a test failure.
constexpr Class()
: Object("__JNI_BIND__NO_CLASS__"),
constructors_(Constructor<>{}),
static_(),
methods_(),
fields_() {}

// Methods + Fields.
explicit constexpr Class(const char* class_name, Methods_... methods,
Fields_... fields)
Expand Down
4 changes: 2 additions & 2 deletions implementation/return.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct Return : ReturnBase {

using Raw = Raw_;

constexpr Return() = default;
constexpr Return() {}

template <typename Raw>
constexpr explicit Return(Raw raw) : raw_(raw) {}
Expand All @@ -42,7 +42,7 @@ struct Return<void> : ReturnBase {
using Raw = void;
const Void raw_{};

constexpr Return() = default;
constexpr Return() {}
};

Return() -> Return<void>;
Expand Down
23 changes: 23 additions & 0 deletions metaprogramming/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,29 @@ cc_test(
],
)

################################################################################
# Invocable Map 20.
################################################################################
cc_library(
name = "invocable_map_20",
hdrs = ["invocable_map_20.h"],
deps = [
":modified_max",
":string_literal",
],
)

cc_test(
name = "invocable_map_test_20",
srcs = ["invocable_map_20_test.cc"],
deps = [
":invocable_map_20",
":modified_max",
":string_literal",
"@googletest//:gtest_main",
],
)

################################################################################
# Invoke.
################################################################################
Expand Down
72 changes: 72 additions & 0 deletions metaprogramming/invocable_map_20.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2021 Google LLC
*
* 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.
*/

#ifndef JNI_BIND_METAPROGRAMMING_INVOCABLE_MAP_20_H
#define JNI_BIND_METAPROGRAMMING_INVOCABLE_MAP_20_H

#include <cstddef>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>

#include "modified_max.h"
#include "string_literal.h"

namespace jni::metaprogramming {

template <typename CrtpBase, const auto& tup_container_v,
typename TupContainerT, const auto TupContainerT::* nameable_member>
class InvocableMap20 {
public:
template <StringLiteral string_literal, std::size_t Idx, typename... Args>
constexpr auto Do(Args&&... args) {
return (*static_cast<CrtpBase*>(this))
.template InvocableMapCall<Idx, Args...>(string_literal.value,
std::forward<Args>(args)...);
}

template <std::size_t N, std::size_t... Is>
static constexpr std::size_t SelectCandidate(StringLiteral<N> string_literal,
std::index_sequence<Is...>) {
return ModifiedMax(
{((std::get<Is>(tup_container_v.*nameable_member).name_ ==
std::string_view{string_literal.value})
? std::size_t{Is}
: kNegativeOne)...,
kNegativeOne});
}

template <StringLiteral string_literal, typename... Args>
constexpr auto Call(Args&&... args) {
return Do<string_literal,
SelectCandidate(
string_literal,
std::make_index_sequence<std::tuple_size_v<std::decay_t<
decltype(tup_container_v.*nameable_member)>>>())>(
std::forward<Args>(args)...);
}
};

template <typename CrtpBase, const auto& tup_container_v,
const auto std::decay_t<decltype(tup_container_v)>::* nameable_member>
using InvocableMap20_t =
InvocableMap20<CrtpBase, tup_container_v,
std::decay_t<decltype(tup_container_v)>, nameable_member>;

} // namespace jni::metaprogramming

#endif // JNI_BIND_METAPROGRAMMING_INVOCABLE_MAP_20_H
80 changes: 80 additions & 0 deletions metaprogramming/invocable_map_20_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright 2024 Google LLC
*
* 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 "invocable_map_20.h"

#include <string_view>
#include <tuple>
#include <type_traits>

#include "invocable_map_20.h"
#include "modified_max.h"
#include "string_literal.h"
#include <gtest/gtest.h>

using jni::metaprogramming::InvocableMap20_t;

struct Str {
const char* name_;
constexpr Str(const char* name) : name_(name) {}
};

struct NameContainer {
std::tuple<Str, Str, Str> container1_;
std::tuple<Str, Str, Str> container2_;
};

constexpr NameContainer name_container{
{{"Foo"}, {"Bar"}, {"Baz"}},
{{"Fizz"}, {"Buzz"}, {"Bang"}},
};

////////////////////////////////////////////////////////////////////////////////
class SampleClassNowExposingCallOperator1
: public InvocableMap20_t<SampleClassNowExposingCallOperator1,
name_container, &NameContainer::container1_> {
protected:
friend InvocableMap20_t<SampleClassNowExposingCallOperator1, name_container,
&NameContainer::container1_>;

template <size_t I, typename... Args>
auto InvocableMapCall(const char* key, Args&&... ts) {
if (std::string_view(key) == "Foo") {
EXPECT_TRUE(I == 0);
EXPECT_TRUE((std::is_same_v<std::tuple<Args...>, std::tuple<int>>));
} else if (std::string_view(key) == "Bar") {
EXPECT_TRUE(I == 1);
EXPECT_TRUE(
(std::is_same_v<std::tuple<Args...>, std::tuple<float, float>>));
} else if (std::string_view(key) == "Baz") {
EXPECT_TRUE(I == 2);
EXPECT_TRUE((
std::is_same_v<std::tuple<Args...>, std::tuple<int, float, double>>));
} else {
FAIL();
}
}
};

TEST(InvocableMapTest1, HasCorrectTypesAndForwardsCalls) {
SampleClassNowExposingCallOperator1 val;
val.Call<"Foo">(1);
val.Call<"Bar">(2.f, 3.f);
val.Call<"Baz">(4, 5.f, double{6});

// By design, doesn't compile.
// val("BazNar", 7, 8, 9);
}
4 changes: 2 additions & 2 deletions metaprogramming/string_literal.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ struct StringLiteral {
template <size_t N>
StringLiteral(const char (&str)[N]) -> StringLiteral<N>;

} // namespace jni::metaprogramming

#endif // __cplusplus >= 202002L
#endif // __cplusplus

} // namespace jni::metaprogramming

#endif // JNI_BIND_METAPROGRAMMING_STRING_LITERAL_H_

0 comments on commit 0ef08a7

Please sign in to comment.