Skip to content

Commit e890186

Browse files
committed
Another iteration on high-level ownership semantics
1 parent 8030424 commit e890186

File tree

5 files changed

+218
-52
lines changed

5 files changed

+218
-52
lines changed

examples/hello.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ static void RegisterHighLevel(JavaVM* vm)
4444

4545
jni::JNIEnv& env { jni::GetEnv(*vm) };
4646

47-
static auto system = jni::Class<System>::Find(env).NewGlobalRef(env).Release();
48-
static auto printStream = jni::Class<PrintStream>::Find(env).NewGlobalRef(env).Release();
47+
static auto system = *jni::Class<System>::Find(env).NewGlobalRef(env).release();
48+
static auto printStream = *jni::Class<PrintStream>::Find(env).NewGlobalRef(env).release();
4949

5050
static auto out = system.GetStaticField<jni::Object<PrintStream>>(env, "out");
5151
static auto println = printStream.GetMethod<void (jni::String)>(env, "println");

include/jni/array.hpp

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,18 @@
44
#include <jni/object.hpp>
55
#include <jni/tagging.hpp>
66
#include <jni/make.hpp>
7+
#include <jni/pointer_to_value.hpp>
78

89
namespace jni
910
{
10-
template < class E, class Enable = void > class Array;
11+
template < class E, class Enable = void >
12+
class Array;
13+
14+
template < class TagType >
15+
class ArrayDeleter;
16+
17+
template < class E >
18+
using UniqueArray = std::unique_ptr< const Array<E>, ArrayDeleter<E> >;
1119

1220
template < class E >
1321
class Array< E, std::enable_if_t<IsPrimitive<E>::value> >
@@ -17,23 +25,21 @@ namespace jni
1725
using UntaggedType = jarray<E>;
1826

1927
private:
20-
UniqueGlobalRef<UntaggedType> reference;
2128
UntaggedType* array = nullptr;
2229

2330
public:
2431
explicit Array(UntaggedType* a)
2532
: array(a)
2633
{}
2734

28-
explicit Array(UniqueGlobalRef<UntaggedType>&& r)
29-
: reference(std::move(r)),
30-
array(reference.get())
31-
{}
32-
3335
explicit operator bool() const { return array; }
36+
3437
UntaggedType& operator*() const { return *array; }
3538
UntaggedType* Get() const { return array; }
3639

40+
friend bool operator==( const Array& a, const Array& b ) { return a.Get() == b.Get(); }
41+
friend bool operator!=( const Array& a, const Array& b ) { return !( a == b ); }
42+
3743
jsize Length(JNIEnv& env) const
3844
{
3945
return GetArrayLength(env, SafeDereference(env, array));
@@ -67,6 +73,11 @@ namespace jni
6773
{
6874
return Array<E>(&NewArray<E>(env, length));
6975
}
76+
77+
UniqueArray<E> NewGlobalRef(JNIEnv& env) const
78+
{
79+
return Seize(env, Array(jni::NewGlobalRef(env, array).release()));
80+
}
7081
};
7182

7283
template < class TheTag >
@@ -79,23 +90,21 @@ namespace jni
7990
using UntaggedElementType = typename ElementType::UntaggedObjectType;
8091

8192
private:
82-
UniqueGlobalRef<UntaggedType> reference;
8393
UntaggedType* array = nullptr;
8494

8595
public:
8696
explicit Array(UntaggedType* a)
8797
: array(a)
8898
{}
8999

90-
explicit Array(UniqueGlobalRef<UntaggedType>&& r)
91-
: reference(std::move(r)),
92-
array(reference.get())
93-
{}
94-
95100
explicit operator bool() const { return array; }
101+
96102
UntaggedType& operator*() const { return *array; }
97103
UntaggedType* Get() const { return array; }
98104

105+
friend bool operator==( const Array& a, const Array& b ) { return a.Get() == b.Get(); }
106+
friend bool operator!=( const Array& a, const Array& b ) { return !( a == b ); }
107+
99108
jsize Length(JNIEnv& env) const
100109
{
101110
return GetArrayLength(env, SafeDereference(env, array));
@@ -117,6 +126,39 @@ namespace jni
117126
{
118127
return Array<Object<TheTag>>(&NewObjectArray(env, length, clazz, initialElement.Get()));
119128
}
129+
130+
UniqueArray<Object<TheTag>> NewGlobalRef(JNIEnv& env) const
131+
{
132+
return Seize(env, Array(jni::NewGlobalRef(env, array).release()));
133+
}
134+
};
135+
136+
template < class E >
137+
class ArrayDeleter
138+
{
139+
private:
140+
JNIEnv* env = nullptr;
141+
142+
public:
143+
using pointer = PointerToValue< Array<E> >;
144+
145+
ArrayDeleter() = default;
146+
ArrayDeleter(JNIEnv& e) : env(&e) {}
147+
148+
void operator()(pointer p) const
149+
{
150+
if (p)
151+
{
152+
assert(env);
153+
env->DeleteGlobalRef(Unwrap(p->Get()));
154+
}
155+
}
156+
};
157+
158+
template < class E >
159+
UniqueArray<E> Seize(JNIEnv& env, Array<E>&& array)
160+
{
161+
return UniqueArray<E>(PointerToValue<Array<E>>(std::move(array)), ArrayDeleter<E>(env));
120162
};
121163

122164

include/jni/class.hpp

Lines changed: 63 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <jni/functions.hpp>
44
#include <jni/tagging.hpp>
5+
#include <jni/pointer_to_value.hpp>
56

67
namespace jni
78
{
@@ -12,90 +13,92 @@ namespace jni
1213
template < class TheTag, class > class Method;
1314
template < class TheTag, class > class StaticMethod;
1415

16+
template < class TheTag >
17+
class Class;
18+
19+
template < class TagType >
20+
class ClassDeleter;
21+
22+
template < class TagType >
23+
using UniqueClass = std::unique_ptr< const Class<TagType>, ClassDeleter<TagType> >;
24+
1525
template < class TheTag >
1626
class Class
1727
{
1828
private:
19-
UniqueGlobalRef<jclass> reference;
20-
jclass& clazz;
29+
jclass* clazz = nullptr;
2130

2231
public:
2332
using TagType = TheTag;
2433

25-
explicit Class(jclass& c)
26-
: clazz(c)
34+
explicit Class(std::nullptr_t = nullptr)
2735
{}
2836

29-
explicit Class(UniqueGlobalRef<jclass>&& r)
30-
: reference(std::move(r)),
31-
clazz(*reference)
37+
explicit Class(jclass& c)
38+
: clazz(&c)
3239
{}
3340

34-
operator jclass&() const { return clazz; }
35-
jclass* Get() const { return &clazz; }
41+
explicit operator bool() const { return clazz; }
42+
43+
operator jclass&() const { return *clazz; }
44+
jclass& operator*() const { return *clazz; }
45+
jclass* Get() const { return clazz; }
46+
47+
friend bool operator==( const Class& a, const Class& b ) { return a.Get() == b.Get(); }
48+
friend bool operator!=( const Class& a, const Class& b ) { return !( a == b ); }
3649

3750
template < class... Args >
3851
Object<TagType> New(JNIEnv& env, const Constructor<TagType, Args...>& method, const Args&... args) const
3952
{
40-
return Object<TagType>(&NewObject(env, clazz, method, Untag(args)...));
53+
return Object<TagType>(&NewObject(env, *clazz, method, Untag(args)...));
4154
}
4255

4356
template < class T >
4457
auto Get(JNIEnv& env, const StaticField<TagType, T>& field) const
4558
-> std::enable_if_t< IsPrimitive<T>::value, T >
4659
{
47-
return jni::GetStaticField<T>(env, clazz, field);
60+
return jni::GetStaticField<T>(env, *clazz, field);
4861
}
4962

5063
template < class T >
5164
auto Get(JNIEnv& env, const StaticField<TagType, T>& field) const
5265
-> std::enable_if_t< !IsPrimitive<T>::value, T >
5366
{
54-
return T(reinterpret_cast<UntaggedType<T>>(jni::GetStaticField<jobject*>(env, clazz, field)));
67+
return T(reinterpret_cast<UntaggedType<T>>(jni::GetStaticField<jobject*>(env, *clazz, field)));
5568
}
5669

5770
template < class T >
5871
auto Set(JNIEnv& env, const StaticField<TagType, T>& field, T value) const
5972
-> std::enable_if_t< IsPrimitive<T>::value >
6073
{
61-
SetStaticField<T>(env, clazz, field, value);
74+
SetStaticField<T>(env, *clazz, field, value);
6275
}
6376

6477
template < class T >
6578
auto Set(JNIEnv& env, const StaticField<TagType, T>& field, const T& value) const
6679
-> std::enable_if_t< !IsPrimitive<T>::value >
6780
{
68-
SetStaticField<jobject*>(env, clazz, field, value.Get());
81+
SetStaticField<jobject*>(env, *clazz, field, value.Get());
6982
}
7083

7184
template < class R, class... Args >
7285
auto Call(JNIEnv& env, const StaticMethod<TagType, R (Args...)>& method, const Args&... args) const
7386
-> std::enable_if_t< IsPrimitive<R>::value, R >
7487
{
75-
return CallStaticMethod<R>(env, clazz, method, Untag(args)...);
88+
return CallStaticMethod<R>(env, *clazz, method, Untag(args)...);
7689
}
7790

7891
template < class R, class... Args >
7992
auto Call(JNIEnv& env, const StaticMethod<TagType, R (Args...)>& method, const Args&... args) const
8093
-> std::enable_if_t< !IsPrimitive<R>::value, R >
8194
{
82-
return R(reinterpret_cast<UntaggedType<R>>(CallStaticMethod<jobject*>(env, clazz, method, Untag(args)...)));
95+
return R(reinterpret_cast<UntaggedType<R>>(CallStaticMethod<jobject*>(env, *clazz, method, Untag(args)...)));
8396
}
8497

8598
template < class... Args >
8699
void Call(JNIEnv& env, const StaticMethod<TagType, void (Args...)>& method, const Args&... args) const
87100
{
88-
CallStaticMethod<void>(env, clazz, method, Untag(args)...);
89-
}
90-
91-
Class NewGlobalRef(JNIEnv& env) const
92-
{
93-
return Class(jni::NewGlobalRef(env, &clazz));
94-
}
95-
96-
Class Release()
97-
{
98-
return Class(*reference.release());
101+
CallStaticMethod<void>(env, *clazz, method, Untag(args)...);
99102
}
100103

101104
static Class Find(JNIEnv& env)
@@ -132,5 +135,38 @@ namespace jni
132135
{
133136
return StaticMethod<TagType, T>(env, *this, name);
134137
}
138+
139+
UniqueClass<TagType> NewGlobalRef(JNIEnv& env) const
140+
{
141+
return Seize(env, Class(*jni::NewGlobalRef(env, clazz).release()));
142+
}
143+
};
144+
145+
template < class TagType >
146+
class ClassDeleter
147+
{
148+
private:
149+
JNIEnv* env = nullptr;
150+
151+
public:
152+
using pointer = PointerToValue< Class<TagType> >;
153+
154+
ClassDeleter() = default;
155+
ClassDeleter(JNIEnv& e) : env(&e) {}
156+
157+
void operator()(pointer p) const
158+
{
159+
if (p)
160+
{
161+
assert(env);
162+
env->DeleteGlobalRef(Unwrap(p->Get()));
163+
}
164+
}
165+
};
166+
167+
template < class TagType >
168+
UniqueClass<TagType> Seize(JNIEnv& env, Class<TagType>&& clazz)
169+
{
170+
return UniqueClass<TagType>(PointerToValue<Class<TagType>>(std::move(clazz)), ClassDeleter<TagType>(env));
135171
};
136172
}

include/jni/object.hpp

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <jni/functions.hpp>
44
#include <jni/tagging.hpp>
5+
#include <jni/pointer_to_value.hpp>
56

67
#include <cstddef>
78

@@ -16,6 +17,15 @@ namespace jni
1617
template < class TagType >
1718
struct UntaggedObjectType { using Type = jobject; };
1819

20+
template < class TheTag >
21+
class Object;
22+
23+
template < class TagType >
24+
class ObjectDeleter;
25+
26+
template < class TagType >
27+
using UniqueObject = std::unique_ptr< const Object<TagType>, ObjectDeleter<TagType> >;
28+
1929
template < class TheTag = ObjectTag >
2030
class Object
2131
{
@@ -24,7 +34,6 @@ namespace jni
2434
using UntaggedObjectType = typename UntaggedObjectType<TagType>::Type;
2535

2636
private:
27-
UniqueGlobalRef<UntaggedObjectType> reference;
2837
UntaggedObjectType* obj = nullptr;
2938

3039
public:
@@ -39,15 +48,14 @@ namespace jni
3948
: obj(&o)
4049
{}
4150

42-
explicit Object(UniqueGlobalRef<UntaggedObjectType>&& r)
43-
: reference(std::move(r)),
44-
obj(reference.get())
45-
{}
46-
4751
explicit operator bool() const { return obj; }
52+
4853
UntaggedObjectType& operator*() const { return *obj; }
4954
UntaggedObjectType* Get() const { return obj; }
5055

56+
friend bool operator==( const Object& a, const Object& b ) { return a.Get() == b.Get(); }
57+
friend bool operator!=( const Object& a, const Object& b ) { return !( a == b ); }
58+
5159
template < class T >
5260
auto Get(JNIEnv& env, const Field<TagType, T>& field) const
5361
-> std::enable_if_t< IsPrimitive<T>::value, T >
@@ -116,14 +124,37 @@ namespace jni
116124
CallNonvirtualMethod<void>(env, obj, clazz, method, Untag(args)...);
117125
}
118126

119-
Object NewGlobalRef(JNIEnv& env) const
127+
UniqueObject<TagType> NewGlobalRef(JNIEnv& env) const
120128
{
121-
return Object(jni::NewGlobalRef(env, obj));
129+
return Seize(env, Object(jni::NewGlobalRef(env, obj).release()));
122130
}
131+
};
123132

124-
Object Release()
133+
template < class TagType >
134+
class ObjectDeleter
135+
{
136+
private:
137+
JNIEnv* env = nullptr;
138+
139+
public:
140+
using pointer = PointerToValue< Object<TagType> >;
141+
142+
ObjectDeleter() = default;
143+
ObjectDeleter(JNIEnv& e) : env(&e) {}
144+
145+
void operator()(pointer p) const
125146
{
126-
return Object(reference.release());
147+
if (p)
148+
{
149+
assert(env);
150+
env->DeleteGlobalRef(Unwrap(p->Get()));
151+
}
127152
}
128153
};
154+
155+
template < class TagType >
156+
UniqueObject<TagType> Seize(JNIEnv& env, Object<TagType>&& object)
157+
{
158+
return UniqueObject<TagType>(PointerToValue<Object<TagType>>(std::move(object)), ObjectDeleter<TagType>(env));
159+
};
129160
}

0 commit comments

Comments
 (0)