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.

I'm keeping this in a separate CL since it's the first time both C++17 and C++20 versions for code in use and would like to flush out build failures.

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

#42

PiperOrigin-RevId: 710778389
  • Loading branch information
jwhpryor authored and copybara-github committed Dec 31, 2024
1 parent d855896 commit 3c42766
Show file tree
Hide file tree
Showing 13 changed files with 546 additions and 18 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
bazel*
.vscode
6 changes: 5 additions & 1 deletion implementation/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -923,8 +923,11 @@ cc_library(
"//:jni_dep",
"//implementation/jni_helper:lifecycle",
"//metaprogramming:invocable_map",
"//metaprogramming:invocable_map_20",
"//metaprogramming:queryable_map",
"//metaprogramming:queryable_map_20",
"//metaprogramming:string_contains",
"//metaprogramming:string_literal",
],
)

Expand Down Expand Up @@ -1237,9 +1240,10 @@ cc_library(
":method_selection",
":no_idx",
"//:jni_dep",
"//implementation/jni_helper:invoke_static",
"//metaprogramming:invocable_map",
"//metaprogramming:invocable_map_20",
"//metaprogramming:queryable_map",
"//metaprogramming:queryable_map_20",
],
)

Expand Down
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
48 changes: 47 additions & 1 deletion implementation/object_ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@
#include "implementation/ref_base.h"
#include "jni_dep.h"
#include "metaprogramming/invocable_map.h"
#include "metaprogramming/invocable_map_20.h"
#include "metaprogramming/queryable_map.h"
#include "metaprogramming/queryable_map_20.h"
#include "metaprogramming/string_contains.h"
#include "metaprogramming/string_literal.h"

namespace jni {

Expand All @@ -47,11 +50,17 @@ namespace jni {
// operator[].
template <typename JniT>
class ObjectRef
// C++17 augmentations.
: public metaprogramming::InvocableMap<
ObjectRef<JniT>, JniT::stripped_class_v, typename JniT::ClassT,
&JniT::ClassT::methods_>,
public metaprogramming::QueryableMap_t<
ObjectRef<JniT>, JniT::stripped_class_v, &JniT::ClassT::fields_>,
// C++ 20 augmentations.
public metaprogramming::InvocableMap20_t<
ObjectRef<JniT>, JniT::stripped_class_v, &JniT::ClassT::methods_>,
public metaprogramming::QueryableMap20_t<
ObjectRef<JniT>, JniT::stripped_class_v, &JniT::ClassT::fields_>,
public RefBase<typename JniT::StorageType> {
protected:
static_assert(
Expand Down Expand Up @@ -83,6 +92,12 @@ class ObjectRef

explicit ObjectRef(RefBaseT&& rhs) : RefBaseT(std::move(rhs)) {}

////////////////////////////////////////////////////////////////////////////////
// Implementation: C++17 + clang
// Supports syntax like: "obj("foo", 123, args)", "obj["foo"].Get()"
// This syntax is less portable and may be removed in a major future release.
////////////////////////////////////////////////////////////////////////////////
#if __clang__
// Invoked through CRTP from InvocableMap.
template <size_t I, typename... Args>
auto InvocableMapCall(const char* key, Args&&... args) const {
Expand All @@ -103,10 +118,41 @@ class ObjectRef
auto QueryableMapCall(const char* key) const {
return FieldRef<JniT, IdType::FIELD, I>{GetJClass(), RefBaseT::object_ref_};
}
#endif // __clang__

////////////////////////////////////////////////////////////////////////////////
// C++20 Implementation (will only be included if supported).
// Supports syntax like: "obj.Call<"foo">(123, args)",
// "obj.Access<"foo">().Get()" Prefer using this syntax as they are more
// portable.
////////////////////////////////////////////////////////////////////////////////
#if __cplusplus >= 202002L
// Invoked through CRTP from InvocableMap, C++20 only.
template <size_t I, metaprogramming::StringLiteral key_literal,
typename... Args>
auto InvocableMap20Call(Args&&... args) const {
using IdT = Id<JniT, IdType::OVERLOAD_SET, I, kNoIdx, kNoIdx, 0>;
using MethodSelectionForArgs =
OverloadSelector<IdT, IdType::OVERLOAD, IdType::OVERLOAD_PARAM,
Args...>;

static_assert(MethodSelectionForArgs::kIsValidArgSet,
"JNI Error: Invalid argument set.");

return MethodSelectionForArgs::OverloadRef::Invoke(
GetJClass(), RefBaseT::object_ref_, std::forward<Args>(args)...);
}

// Invoked through CRTP from QueryableMap20, C++20 only.
template <size_t I, metaprogramming::StringLiteral key_literal>
auto QueryableMap20Call() const {
return FieldRef<JniT, IdType::FIELD, I>{GetJClass(), RefBaseT::object_ref_};
}
#endif // __cplusplus >= 202002L
};

// Imbues constructors for ObjectRefs and handles calling the correct
// intermediate constructors. Access to this class is constrainted for non
// intermediate constructors. Access to this class is constrained for non
// default classloaders (see |ValidatorProxy|).
template <typename JniT>
class ConstructorValidator : public ObjectRef<JniT> {
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
69 changes: 67 additions & 2 deletions implementation/static_ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
#include "implementation/no_idx.h"
#include "jni_dep.h"
#include "metaprogramming/invocable_map.h"
#include "metaprogramming/invocable_map_20.h"
#include "metaprogramming/queryable_map.h"
#include "metaprogramming/queryable_map_20.h"

namespace jni {

Expand All @@ -41,13 +43,23 @@ template <typename CrtpBase_, const auto& class_v_, const auto& class_loader_v_,
struct StaticRefHelper {
using JniT = JniT<jobject, class_v_, class_loader_v_, jvm_v_>;

// C++17 augmentations.
using MethodMapT = metaprogramming::InvocableMap<CrtpBase_, JniT::static_v,
typename JniT::StaticT,
&JniT::StaticT::methods_>;
using FieldMapT = metaprogramming::QueryableMap_t<CrtpBase_, JniT::static_v,
&JniT::StaticT::fields_>;

// C++ 20 augmentations.
using MethodMap20T =
metaprogramming::InvocableMap20_t<CrtpBase_, JniT::static_v,
&JniT::StaticT::methods_>;
using FieldMap20T =
metaprogramming::QueryableMap20_t<CrtpBase_, JniT::static_v,
&JniT::StaticT::fields_>;
};

// C++17 augmentations.
template <typename CrtpBase_, const auto& class_v_, const auto& class_loader_v_,
const auto& jvm_v_>
using StaticRefHelperMethodMap_t =
Expand All @@ -60,21 +72,48 @@ using StaticRefHelperFieldMap_t =
typename StaticRefHelper<CrtpBase_, class_v_, class_loader_v_,
jvm_v_>::FieldMapT;

// C++20 augmentations.
template <typename CrtpBase_, const auto& class_v_, const auto& class_loader_v_,
const auto& jvm_v_>
using StaticRefHelperMethodMap20_t =
typename StaticRefHelper<CrtpBase_, class_v_, class_loader_v_,
jvm_v_>::MethodMap20T;
template <typename CrtpBase_, const auto& class_v_, const auto& class_loader_v_,
const auto& jvm_v_>
using StaticRefHelperFieldMap20_t =
typename StaticRefHelper<CrtpBase_, class_v_, class_loader_v_,
jvm_v_>::FieldMap20T;

template <const auto& class_v_,
const auto& class_loader_v_ = kDefaultClassLoader,
const auto& jvm_v_ = kDefaultJvm>
struct StaticRef
: public StaticRefHelperMethodMap_t<
: public
// C++17 augmentations.
StaticRefHelperMethodMap_t<
StaticRef<class_v_, class_loader_v_, jvm_v_>, class_v_,
class_loader_v_, jvm_v_>,
StaticRefHelperFieldMap_t<StaticRef<class_v_, class_loader_v_, jvm_v_>,
class_v_, class_loader_v_, jvm_v_> {
class_v_, class_loader_v_, jvm_v_>,
// C++ 20 augmentations.
StaticRefHelperMethodMap20_t<
StaticRef<class_v_, class_loader_v_, jvm_v_>, class_v_,
class_loader_v_, jvm_v_>,
StaticRefHelperFieldMap20_t<StaticRef<class_v_, class_loader_v_, jvm_v_>,
class_v_, class_loader_v_, jvm_v_>
{
using JniT = JniT<jobject, class_v_, class_loader_v_, jvm_v_>;

jclass GetJClass() const {
return ClassRef_t<JniT>::GetAndMaybeLoadClassRef(nullptr);
}

////////////////////////////////////////////////////////////////////////////////
// Implementation: C++17 + clang
// Supports syntax like: "obj("foo", 123, args)", "obj["foo"].Get()"
// This syntax is less portable and may be removed in a major future release.
////////////////////////////////////////////////////////////////////////////////
#if __clang__
template <size_t I, typename... Args>
auto InvocableMapCall(const char* key, Args&&... args) const {
using IdT = Id<JniT, IdType::STATIC_OVERLOAD_SET, I, kNoIdx, kNoIdx, 0>;
Expand All @@ -93,6 +132,32 @@ struct StaticRef
auto QueryableMapCall(const char* key) const {
return FieldRef<JniT, IdType::STATIC_FIELD, I>{GetJClass(), nullptr};
}
#endif // __clang__

#if __cplusplus >= 202002L
// Invoked through CRTP from InvocableMap, C++20 only.
template <size_t I, metaprogramming::StringLiteral key_literal,
typename... Args>
auto InvocableMap20Call(Args&&... args) const {
using IdT = Id<JniT, IdType::STATIC_OVERLOAD_SET, I, kNoIdx, kNoIdx, 0>;
using MethodSelectionForArgs =
OverloadSelector<IdT, IdType::STATIC_OVERLOAD,
IdType::STATIC_OVERLOAD_PARAM, Args...>;

static_assert(MethodSelectionForArgs::kIsValidArgSet,
"JNI Error: Invalid argument set.");

return MethodSelectionForArgs::OverloadRef::Invoke(
GetJClass(), nullptr, std::forward<Args>(args)...);
}

// Invoked through CRTP from QueryableMap20, C++20 only.
template <size_t I, metaprogramming::StringLiteral key_literal>
auto QueryableMap20Call() const {
return FieldRef<JniT, IdType::STATIC_FIELD, I>{GetJClass(), nullptr};
}
#endif // __cplusplus >= 202002L

};

} // namespace jni
Expand Down
53 changes: 53 additions & 0 deletions metaprogramming/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,30 @@ 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"],
tags = ["cpp20"],
deps = [
":invocable_map_20",
":modified_max",
":string_literal",
"@googletest//:gtest_main",
],
)

################################################################################
# Invoke.
################################################################################
Expand Down Expand Up @@ -961,6 +985,35 @@ cc_test(
],
)

################################################################################
# Queryable Map 20.
################################################################################
cc_library(
name = "queryable_map_20",
hdrs = ["queryable_map_20.h"],
deps = [
":interleave",
":lambda_string",
":modified_max",
":string_literal",
":tuple_from_size",
":tuple_manipulation",
":type_of_nth_element",
],
)

cc_test(
name = "queryable_map_20_test",
srcs = ["queryable_map_20_test.cc"],
tags = ["cpp20"],
deps = [
":modified_max",
":queryable_map_20",
":string_literal",
"@googletest//:gtest_main",
],
)

################################################################################
# Reduce.
################################################################################
Expand Down
Loading

0 comments on commit 3c42766

Please sign in to comment.