Skip to content

Commit c9ca058

Browse files
committed
Rename Tagged → Unique, move to own file
1 parent 8f35aa7 commit c9ca058

File tree

3 files changed

+163
-158
lines changed

3 files changed

+163
-158
lines changed

include/jni/jni.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
// High-level
1111

12+
#include <jni/unique.hpp>
13+
#include <jni/tagging.hpp>
1214
#include <jni/class.hpp>
1315
#include <jni/object.hpp>
1416
#include <jni/string.hpp>

include/jni/tagging.hpp

Lines changed: 1 addition & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include <jni/traits.hpp>
4+
#include <jni/unique.hpp>
45

56
#include <type_traits>
67

@@ -89,164 +90,6 @@ namespace jni
8990
};
9091

9192

92-
/*
93-
The interface for high-level references. Client code using the high-level API
94-
will most often work with values of this class template, using the following aliases:
95-
96-
* Global<P>, a.k.a. Tagged<T, DefaultRefDeleter<&JNIEnv::DeleteGlobalRef>>,
97-
* Weak<P>, a.k.a. Tagged<T, DefaultRefDeleter<&JNIEnv::DeleteWeakGlobalRef>>,
98-
* Local<P>, a.k.a. Tagged<T, LocalRefDeleter>,
99-
100-
where P is Object<>, Class<>, or Array<>.
101-
102-
`Tagged` is an ownership class with a deletion policy that's parameterized both
103-
by the appropriate method to delete the reference (global, weak, or local) and
104-
(for global and weak references), a choice about how to obtain the JNIEnv that's
105-
necessary to call the deletion method. The default policy is to delete the reference
106-
using the same JNIEnv as was passed to the constructor, but in cases where the
107-
object may be deleted on a different thread (commonly, the Java finalizer thread),
108-
EnvGettingDeleter or EnvAttachingDeleter may be needed.
109-
110-
Object<>, Class<>, or Array<> -- the underlying and inherited types used for
111-
the template parameter T -- are not publicly constructible or destructible. This
112-
is to ensure that code works only with ownership types which release the reference
113-
at an appropriate time. Our experience has shown that this is important even for
114-
local references; the default JVM cleanup behaviors for local references are not
115-
enough to ensure that the local reference table never overflows.
116-
117-
In some cases C++ references -- Object<>&, const Class<>&, or Array<>& -- are used.
118-
For example, this is the case for receiving parameters passed to a native method
119-
implementation, reflecting the fact that JVM implementations prohibit explicitly
120-
releasing this form of local reference. You may also pass C++ references to code
121-
that does not need to take ownership. However, if you need to store or copy the
122-
reference, you will need to use a method such as `NewGlobalRef` that copies at the
123-
reference level -- `Tagged`, `Object<>`, etc., are not themselves copyable.
124-
*/
125-
template < class T, class D >
126-
class Tagged : public T
127-
{
128-
private:
129-
D deleter;
130-
131-
Tagged(const Tagged&) = delete;
132-
Tagged& operator=(const Tagged&) = delete;
133-
134-
public:
135-
using Base = T;
136-
using UntaggedType = typename T::UntaggedType;
137-
138-
explicit Tagged(std::nullptr_t ptr = nullptr)
139-
: T(ptr),
140-
deleter() {}
141-
142-
explicit Tagged(JNIEnv& env, UntaggedType* ptr)
143-
: T(ptr),
144-
deleter(env) {}
145-
146-
Tagged(Tagged&& other)
147-
: T(other.release()),
148-
deleter(std::move(other.get_deleter())) {}
149-
150-
template < class U >
151-
Tagged(Tagged<U, D>&& other, std::enable_if_t<std::is_convertible<const U&, const T&>::value>* = nullptr)
152-
: T(other.release()),
153-
deleter(std::move(other.get_deleter())) {}
154-
155-
~Tagged()
156-
{
157-
reset();
158-
}
159-
160-
Tagged& operator=(Tagged&& other)
161-
{
162-
reset(other.release());
163-
deleter = std::move(other.deleter);
164-
return *this;
165-
}
166-
167-
void reset(UntaggedType* ptr = nullptr)
168-
{
169-
UntaggedType* current = this->get();
170-
T::reset(ptr);
171-
if (current)
172-
{
173-
get_deleter()(current);
174-
}
175-
}
176-
177-
UntaggedType* release()
178-
{
179-
UntaggedType* current = this->get();
180-
T::reset(nullptr);
181-
return current;
182-
}
183-
184-
D& get_deleter() { return deleter; }
185-
const D& get_deleter() const { return deleter; }
186-
};
187-
188-
189-
template < class T, template < RefDeletionMethod > class Deleter = DefaultRefDeleter >
190-
using Global = Tagged< T, Deleter<&JNIEnv::DeleteGlobalRef> >;
191-
192-
template < class T, template < RefDeletionMethod > class Deleter = DefaultRefDeleter >
193-
using Weak = Tagged< T, Deleter<&JNIEnv::DeleteWeakGlobalRef> >;
194-
195-
// Not parameterized by Deleter because local references should be short-lived enough
196-
// that DefaultRefDeleter suffices in all cases.
197-
template < class T >
198-
using Local = Tagged< T, DefaultRefDeleter<&JNIEnv::DeleteLocalRef> >;
199-
200-
201-
// Special case for JNI-provided input parameters to native methods, which apparently
202-
// should not be explicitly deleted (https://bugs.chromium.org/p/chromium/issues/detail?id=506850).
203-
struct NullDeleter
204-
{
205-
NullDeleter() = default;
206-
NullDeleter(JNIEnv&) {}
207-
void operator()(jobject*) const {}
208-
};
209-
210-
template < class T >
211-
using Input = Tagged< T, NullDeleter >;
212-
213-
214-
// Attempt to promote a weak reference to a strong one. Returns an empty result
215-
// if the weak reference has expired.
216-
//
217-
// Beware that the semantics of JNI weak references are weaker than is typically
218-
// desired: a JNI weak reference may still be promoted to a non-null strong reference
219-
// even during finalization. Consider using jni::WeakReference<T> instead.
220-
template < template < RefDeletionMethod > class Deleter, class T, template < RefDeletionMethod > class WeakDeleter >
221-
Global<T, Deleter> NewGlobal(JNIEnv& env, const Weak<T, WeakDeleter>& t)
222-
{
223-
jobject* obj = Wrap<jobject*>(env.NewGlobalRef(Unwrap(t->get())));
224-
CheckJavaException(env);
225-
return Global<T, Deleter>(env, obj);
226-
}
227-
228-
template < class T >
229-
Global<T> NewGlobal(JNIEnv& env, const Weak<T>& t)
230-
{
231-
return NewGlobal<DefaultRefDeleter>(env, t);
232-
}
233-
234-
235-
// Attempt to promote a weak reference to a strong one. Returns an empty result
236-
// if the weak reference has expired.
237-
//
238-
// Beware that the semantics of JNI weak references are weaker than is typically
239-
// desired: a JNI weak reference may still be promoted to a non-null strong reference
240-
// even during finalization. Consider using jni::WeakReference<T> instead.
241-
template < class T, template < RefDeletionMethod > class WeakDeleter >
242-
Local<T> NewLocal(JNIEnv& env, const Weak<T, WeakDeleter>& t)
243-
{
244-
jobject* obj = Wrap<jobject*>(env.NewLocalRef(Unwrap(t->get())));
245-
CheckJavaException(env);
246-
return Local<T>(env, obj);
247-
}
248-
249-
25093
template < class T >
25194
auto Tag(JNIEnv&, T primitive)
25295
-> std::enable_if_t< IsPrimitive<T>::value, T >

include/jni/unique.hpp

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#pragma once
2+
3+
namespace jni
4+
{
5+
/*
6+
Ownership type and main interface for high-level references. Client code using the high-level
7+
API will most often work with values of this class template, using the following aliases:
8+
9+
* Global<P>, a.k.a. Unique<T, DefaultRefDeleter<&JNIEnv::DeleteGlobalRef>>,
10+
* Weak<P>, a.k.a. Unique<T, DefaultRefDeleter<&JNIEnv::DeleteWeakGlobalRef>>,
11+
* Local<P>, a.k.a. Unique<T, LocalRefDeleter>,
12+
13+
where P is Object<>, Class<>, or Array<>.
14+
15+
`Unique` is an ownership class with a deletion policy that's parameterized both
16+
by the appropriate method to delete the reference (global, weak, or local) and
17+
(for global and weak references), a choice about how to obtain the JNIEnv that's
18+
necessary to call the deletion method. The default policy is to delete the reference
19+
using the same JNIEnv as was passed to the constructor, but in cases where the
20+
object may be deleted on a different thread (commonly, the Java finalizer thread),
21+
EnvGettingDeleter or EnvAttachingDeleter may be needed.
22+
23+
Object<>, Class<>, or Array<> -- the underlying and inherited types used for
24+
the template parameter T -- are not publicly constructible or destructible. This
25+
is to ensure that code works only with ownership types which release the reference
26+
at an appropriate time. Our experience has shown that this is important even for
27+
local references; the default JVM cleanup behaviors for local references are not
28+
enough to ensure that the local reference table never overflows.
29+
30+
You may also pass or receive C++ references when you wish to borrow rather than take
31+
ownership. For example, receiving parameters for a native method implementation should be
32+
C++ references, reflecting the fact that JVM implementations prohibit explicitly releasing
33+
this form of local reference. However, if you need to store or copy the reference, you
34+
will need to use a method such as `NewGlobalRef` that copies at the reference level.
35+
`Unique`, `Object<>`, etc., are not themselves copyable.
36+
*/
37+
template < class T, class D >
38+
class Unique : public T
39+
{
40+
private:
41+
D deleter;
42+
43+
Unique(const Unique&) = delete;
44+
Unique& operator=(const Unique&) = delete;
45+
46+
public:
47+
using Base = T;
48+
using UntaggedType = typename T::UntaggedType;
49+
50+
explicit Unique(std::nullptr_t ptr = nullptr)
51+
: T(ptr),
52+
deleter() {}
53+
54+
explicit Unique(JNIEnv& env, UntaggedType* ptr)
55+
: T(ptr),
56+
deleter(env) {}
57+
58+
Unique(Unique&& other)
59+
: T(other.release()),
60+
deleter(std::move(other.get_deleter())) {}
61+
62+
template < class U >
63+
Unique(Unique<U, D>&& other, std::enable_if_t<std::is_convertible<const U&, const T&>::value>* = nullptr)
64+
: T(other.release()),
65+
deleter(std::move(other.get_deleter())) {}
66+
67+
~Unique()
68+
{
69+
reset();
70+
}
71+
72+
Unique& operator=(Unique&& other)
73+
{
74+
reset(other.release());
75+
deleter = std::move(other.deleter);
76+
return *this;
77+
}
78+
79+
void reset(UntaggedType* ptr = nullptr)
80+
{
81+
UntaggedType* current = this->get();
82+
T::reset(ptr);
83+
if (current)
84+
{
85+
get_deleter()(current);
86+
}
87+
}
88+
89+
UntaggedType* release()
90+
{
91+
UntaggedType* current = this->get();
92+
T::reset(nullptr);
93+
return current;
94+
}
95+
96+
D& get_deleter() { return deleter; }
97+
const D& get_deleter() const { return deleter; }
98+
};
99+
100+
101+
template < class T, template < RefDeletionMethod > class Deleter = DefaultRefDeleter >
102+
using Global = Unique< T, Deleter<&JNIEnv::DeleteGlobalRef> >;
103+
104+
template < class T, template < RefDeletionMethod > class Deleter = DefaultRefDeleter >
105+
using Weak = Unique< T, Deleter<&JNIEnv::DeleteWeakGlobalRef> >;
106+
107+
// Not parameterized by Deleter because local references should be short-lived enough
108+
// that DefaultRefDeleter suffices in all cases.
109+
template < class T >
110+
using Local = Unique< T, DefaultRefDeleter<&JNIEnv::DeleteLocalRef> >;
111+
112+
113+
// Special case for JNI-provided input parameters to native methods, which apparently
114+
// should not be explicitly deleted (https://bugs.chromium.org/p/chromium/issues/detail?id=506850).
115+
struct NullDeleter
116+
{
117+
NullDeleter() = default;
118+
NullDeleter(JNIEnv&) {}
119+
void operator()(jobject*) const {}
120+
};
121+
122+
template < class T >
123+
using Input = Unique< T, NullDeleter >;
124+
125+
126+
// Attempt to promote a weak reference to a strong one. Returns an empty result
127+
// if the weak reference has expired.
128+
//
129+
// Beware that the semantics of JNI weak references are weaker than is typically
130+
// desired: a JNI weak reference may still be promoted to a non-null strong reference
131+
// even during finalization. Consider using jni::WeakReference<T> instead.
132+
template < template < RefDeletionMethod > class Deleter, class T, template < RefDeletionMethod > class WeakDeleter >
133+
Global<T, Deleter> NewGlobal(JNIEnv& env, const Weak<T, WeakDeleter>& t)
134+
{
135+
jobject* obj = Wrap<jobject*>(env.NewGlobalRef(Unwrap(t->get())));
136+
CheckJavaException(env);
137+
return Global<T, Deleter>(env, obj);
138+
}
139+
140+
template < class T >
141+
Global<T> NewGlobal(JNIEnv& env, const Weak<T>& t)
142+
{
143+
return NewGlobal<DefaultRefDeleter>(env, t);
144+
}
145+
146+
147+
// Attempt to promote a weak reference to a strong one. Returns an empty result
148+
// if the weak reference has expired.
149+
//
150+
// Beware that the semantics of JNI weak references are weaker than is typically
151+
// desired: a JNI weak reference may still be promoted to a non-null strong reference
152+
// even during finalization. Consider using jni::WeakReference<T> instead.
153+
template < class T, template < RefDeletionMethod > class WeakDeleter >
154+
Local<T> NewLocal(JNIEnv& env, const Weak<T, WeakDeleter>& t)
155+
{
156+
jobject* obj = Wrap<jobject*>(env.NewLocalRef(Unwrap(t->get())));
157+
CheckJavaException(env);
158+
return Local<T>(env, obj);
159+
}
160+
}

0 commit comments

Comments
 (0)