Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jni::Class now permits a new Extends arg to eventually support inheritance. #313

Merged
merged 1 commit into from
Jul 8, 2024
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
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