Skip to content

Commit

Permalink
jni::Class now permits a new Extends arg to eventually support inhe…
Browse files Browse the repository at this point in the history
…ritance.

Implementation will come in a follow up commit.

PiperOrigin-RevId: 650334924
  • Loading branch information
jwhpryor authored and copybara-github committed Jul 8, 2024
1 parent 34d7376 commit dab93f3
Show file tree
Hide file tree
Showing 7 changed files with 332 additions and 42 deletions.
1 change: 1 addition & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ cc_library(
"//implementation:configuration",
"//implementation:constructor",
"//implementation:default_class_loader",
"//implementation:extends",
"//implementation:field",
"//implementation:find_class_fallback",
"//implementation:forward_declarations",
Expand Down
29 changes: 26 additions & 3 deletions implementation/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,15 @@ cc_library(
hdrs = ["class.h"],
deps = [
":constructor",
":extends",
":field",
":method",
":no_idx",
":no_class_specified",
":object",
":static",
"//:jni_dep",
"//metaprogramming:all_unique",
"//metaprogramming:base_filter",
"//metaprogramming:tuple_manipulation",
"//metaprogramming:type_of_nth_element",
],
)

Expand Down Expand Up @@ -273,6 +274,19 @@ cc_library(
],
)

################################################################################
# Extend.
################################################################################
cc_library(
name = "extends",
hdrs = ["extends.h"],
deps = [
":no_class_specified",
"//metaprogramming:tuple_manipulation",
"//metaprogramming:type_of_nth_element",
],
)

################################################################################
# Field.
################################################################################
Expand Down Expand Up @@ -915,6 +929,15 @@ cc_test(
],
)

################################################################################
# NoClassSpecified.
################################################################################
cc_library(
name = "no_class_specified",
hdrs = ["no_class_specified.h"],
deps = [":static"],
)

################################################################################
# NoIdx.
################################################################################
Expand Down
125 changes: 92 additions & 33 deletions implementation/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,55 +13,66 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef JNI_BIND_CLASS_H_
#define JNI_BIND_CLASS_H_

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

#include "implementation/constructor.h"
#include "implementation/extends.h"
#include "implementation/field.h"
#include "implementation/method.h"
#include "implementation/no_idx.h"
#include "implementation/no_class_specified.h"
#include "implementation/object.h"
#include "implementation/static.h"
#include "jni_dep.h"
#include "metaprogramming/all_unique.h"
#include "metaprogramming/base_filter.h"
#include "metaprogramming/type_of_nth_element.h"

namespace jni {

static constexpr struct NoClass {
const char* name_ = "__JNI_BIND__NO_CLASS__";
const Static<std::tuple<>, std::tuple<>> static_{};
const std::tuple<> methods_{};
const std::tuple<> fields_{};

constexpr bool operator==(const NoClass&) const { return true; }
constexpr bool operator!=(const NoClass&) const { return true; }
} kNoClassSpecified;

template <typename Constructors_, typename Static_, typename Methods_,
typename Fields_>
template <typename Extends_, typename Constructors_, typename Static_,
typename Methods_, typename Fields_>
struct Class {};

template <typename... Constructors_, typename... StaticMethods_,
typename... StaticFields_, typename... Methods_, typename... Fields_>
struct Class<std::tuple<Constructors_...>,
template <typename Extends_, typename... Constructors_,
typename... StaticMethods_, typename... StaticFields_,
typename... Methods_, typename... Fields_>
struct Class<Extends_, std::tuple<Constructors_...>,
std::tuple<Static<std::tuple<StaticMethods_...>,
std::tuple<StaticFields_...>>>,
std::tuple<Methods_...>, std::tuple<Fields_...>> : public Object {
public:
// Filtering outputs a std::tuple<T>, the caller will use just T in ctor.
using ExtendsArgT = metaprogramming::TypeOfNthTupleElement_t<0, Extends_>;

// The type of the parent class (default `RootObject`).
const ExtendsStrip_t<Extends_> parent_;

const std::tuple<Constructors_...> constructors_;
const Static<std::tuple<StaticMethods_...>, std::tuple<StaticFields_...>>
static_;
const std::tuple<Methods_...> methods_;
const std::tuple<Fields_...> fields_;

// Ctors + static.
////////////////////////////////////////////////////////////////////////////////
// Constructors can pass any correctly ordered permutation of:
// - Extends (parent declaration)
// - Constructors
// - Statics
// - Methods
// - Fields
//
// For types that are not packs (e.g. Statics), they must have permutations
// provided where they are and aren't present.
////////////////////////////////////////////////////////////////////////////////

// Methods + Fields.
explicit constexpr Class(const char* class_name, Methods_... methods,
Fields_... fields)
: Class(class_name, Constructor<>{}, Static{}, methods..., fields...) {}

// Constructors + Statics + Methods + Fields.
explicit constexpr Class(
const char* class_name, Constructors_... constructors,
Static<std::tuple<StaticMethods_...>, std::tuple<StaticFields_...>>
Expand All @@ -73,7 +84,7 @@ struct Class<std::tuple<Constructors_...>,
methods_(methods...),
fields_(fields...) {}

// No ctors, static.
// Statics + Methods + Fields.
explicit constexpr Class(
const char* class_name,
Static<std::tuple<StaticMethods_...>, std::tuple<StaticFields_...>>
Expand All @@ -85,7 +96,7 @@ struct Class<std::tuple<Constructors_...>,
methods_(methods...),
fields_(fields...) {}

// Ctors, no static.
// Constructors only + Methods + Fields.
explicit constexpr Class(const char* class_name,
Constructors_... constructors, Methods_... methods,
Fields_... fields)
Expand All @@ -95,16 +106,62 @@ struct Class<std::tuple<Constructors_...>,
methods_(methods...),
fields_(fields...) {}

// No ctors, no static.
explicit constexpr Class(const char* class_name, Methods_... methods,
////////////////////////////////////////////////////////////////////////////////
// Constructors with `Extends`.
////////////////////////////////////////////////////////////////////////////////

// Extends + Methods + Fields.
explicit constexpr Class(const char* class_name, ExtendsArgT extends,
Methods_... methods, Fields_... fields)
: parent_(extends.parent_),
Object(class_name),
methods_(methods...),
fields_(fields...) {}

// Extends + Statics + Methods + Fields.
explicit constexpr Class(
const char* class_name, ExtendsArgT extends,
Static<std::tuple<StaticMethods_...>, std::tuple<StaticFields_...>>
statik,
Methods_... methods, Fields_... fields)
: Object(class_name),
parent_(extends.parent_),
static_(statik),
methods_(methods...),
fields_(fields...) {}

// Extends + Constructors + Methods + Fields.
explicit constexpr Class(const char* class_name, ExtendsArgT extends,
Constructors_... constructors, Methods_... methods,
Fields_... fields)
: Class(class_name, Constructor<>{}, Static{}, methods..., fields...) {}
: Object(class_name),
parent_(extends.parent_),
constructors_(constructors...),
methods_(methods...),
fields_(fields...) {}

// Extends + Statics + Constructor + Methods + Fields.
explicit constexpr Class(
const char* class_name, ExtendsArgT extends,
Constructors_... constructors,
Static<std::tuple<StaticMethods_...>, std::tuple<StaticFields_...>>
statik,
Methods_... methods, Fields_... fields)
: Object(class_name),
parent_(extends.parent_),
constructors_(constructors...),
static_(statik),
methods_(methods...),
fields_(fields...) {}

template <typename... Params, typename... Constructors,
////////////////////////////////////////////////////////////////////////////////
// Equality operators.
////////////////////////////////////////////////////////////////////////////////
template <typename ParentClass, typename... Params, typename... Constructors,
typename... StaticMethods, typename... StaticFields,
typename... Fields, typename... Methods>
constexpr bool operator==(
const Class<std::tuple<Constructors...>,
const Class<ParentClass, std::tuple<Constructors...>,
std::tuple<Static<std::tuple<StaticMethods...>,
std::tuple<StaticFields...>>>,
std::tuple<Methods...>, std::tuple<Fields...>>& rhs) const {
Expand All @@ -119,17 +176,19 @@ struct Class<std::tuple<Constructors_...>,

template <typename... Params>
Class(const char*, Params...)
-> Class<metaprogramming::BaseFilterWithDefault_t<ConstructorBase,
-> Class<metaprogramming::BaseFilterWithDefault_t<
ExtendsBase, Extends<RootObject>, Params...>,
metaprogramming::BaseFilterWithDefault_t<ConstructorBase,
Constructor<>, Params...>,
metaprogramming::BaseFilterWithDefault_t<
StaticBase, Static<std::tuple<>, std::tuple<>>, Params...>,
metaprogramming::BaseFilter_t<MethodBase, Params...>,
metaprogramming::BaseFilter_t<FieldBase, Params...>>;

Class(const char*)
->Class<std::tuple<Constructor<>>,
std::tuple<Static<std::tuple<>, std::tuple<>>>, std::tuple<>,
std::tuple<>>;
-> Class<std::tuple<Extends<RootObject>>, std::tuple<Constructor<>>,
std::tuple<Static<std::tuple<>, std::tuple<>>>, std::tuple<>,
std::tuple<>>;

} // namespace jni

Expand Down
117 changes: 111 additions & 6 deletions implementation/class_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,118 @@
namespace {

using ::jni::Class;
using ::jni::Constructor;
using ::jni::Extends;
using ::jni::Field;
using ::jni::LocalObject;
using ::jni::Method;
using ::jni::Static;
using ::jni::test::JniTest;

static constexpr Class k_class_one{"classOne"};
static constexpr Class k_class_one_prime{"classOne"};
static constexpr Class k_class_two{"classTwo"};
////////////////////////////////////////////////////////////////////////////////
// Constructor Tests.
////////////////////////////////////////////////////////////////////////////////

static_assert(k_class_one == k_class_one);
static_assert(k_class_one == k_class_one_prime);
static_assert(!(k_class_two == k_class_one_prime));
/*
Class unfortunately requires a matrix of viable arguments because it filters
all the inputs and infers types through CTAD (which makes for a nicer API).
Below tests compilation where:
E => jni::Extends arg(s) present.
C => jni::Constructor arg(s) present.
S => jni::Static arg(s) present.
M => jni::Method arg(s) present.
F => jni::Field arg(s) present.
To make the tests more optically simple to inspect, each of the above are
encoded as a binary string. i.e.
ESCMF
10001
For 10001, both Extends and a Field are used.
*/

static constexpr Class kParent{"kClass"};

static constexpr Extends e = Extends{kParent};
static constexpr Static s = Static{Method{"Foo", jni::Return{}}};
static constexpr Constructor c = Constructor{jint{}};
static constexpr Method m = Method{"Foo", jni::Return{}};
static constexpr Field f = Field{"field", int{}};

static constexpr Class k00000{"c"};
static constexpr Class k00001{"c", f};
static constexpr Class k00010{"c", m};
static constexpr Class k00011{"c", m, f};
static constexpr Class k00100{"c", s};
static constexpr Class k00101{"c", s, f};
static constexpr Class k00111{"c", s, m, f};
static constexpr Class k01000{"c", c};
static constexpr Class k01001{"c", c, f};
static constexpr Class k01010{"c", c, m};
static constexpr Class k01011{"c", c, m, f};
static constexpr Class k01100{"c", c, s};
static constexpr Class k01101{"c", c, s, f};
static constexpr Class k01111{"c", c, s, m, f};

static constexpr Class k10000{"c", e};
static constexpr Class k10001{"c", e, f};
static constexpr Class k10010{"c", e, m};
static constexpr Class k10011{"c", e, m, f};
static constexpr Class k10100{"c", e, s};
static constexpr Class k10101{"c", e, s, f};
static constexpr Class k10111{"c", e, s, m, f};
static constexpr Class k11000{"c", e, c};
static constexpr Class k11001{"c", e, c, f};
static constexpr Class k11010{"c", e, c, m};
static constexpr Class k11011{"c", e, c, m, f};
static constexpr Class k11100{"c", e, c, s};
static constexpr Class k11101{"c", e, c, s, f};
static constexpr Class k11111{"c", e, c, s, m, f};

// This test is just a smoke test for the above classes to silence clang.
TEST_F(JniTest, ClassTest_AllClassesInstantiate) {
LocalObject<k00000> obj_k00000{};
LocalObject<k00001> obj_k00001{};
LocalObject<k00010> obj_k00010{};
LocalObject<k00011> obj_k00011{};
LocalObject<k00100> obj_k00100{};
LocalObject<k00101> obj_k00101{};
LocalObject<k00111> obj_k00111{};
LocalObject<k01000> obj_k01000{123};
LocalObject<k01001> obj_k01001{123};
LocalObject<k01010> obj_k01010{123};
LocalObject<k01011> obj_k01011{123};
LocalObject<k01100> obj_k01100{123};
LocalObject<k01101> obj_k01101{123};
LocalObject<k01111> obj_k01111{123};

LocalObject<k10000> obj_k10000{};
LocalObject<k10001> obj_k10001{};
LocalObject<k10010> obj_k10010{};
LocalObject<k10011> obj_k10011{};
LocalObject<k10100> obj_k10100{};
LocalObject<k10101> obj_k10101{};
LocalObject<k10111> obj_k10111{};
LocalObject<k11000> obj_k11000{123};
LocalObject<k11001> obj_k11001{123};
LocalObject<k11010> obj_k11010{123};
LocalObject<k11011> obj_k11011{123};
LocalObject<k11100> obj_k11100{123};
LocalObject<k11101> obj_k11101{123};
LocalObject<k11111> obj_k11111{123};
}

////////////////////////////////////////////////////////////////////////////////
// Equality Tests.
////////////////////////////////////////////////////////////////////////////////

static constexpr Class kClass1{"classOne"};
static constexpr Class kClass1Prime{"classOne"};
static constexpr Class kClass2{"classTwo"};

static_assert(kClass1 == kClass1);
static_assert(kClass1 == kClass1Prime);
static_assert(!(kClass2 == kClass1Prime));

} // namespace
Loading

0 comments on commit dab93f3

Please sign in to comment.