ndk
ndk copied to clipboard
C++ Wrapper for jstring
Forked from #476
Proposal for jstring C++ wrapper char16_t wrapper is commented out in example as it requires some utf32-utf16 convertion
jstring.hpp
#pragma once
#include "common.h"
#include <iostream>
#include <vector>
#include <string>
using jenv = JNIEnv *;
namespace jni
{
///\brief resource managment type
enum struct jownership_e : uint8_t
{
external, ///\brief external owned not managment
owned ///\brief internaly managed
};
enum struct attach_mode_e : uint8_t
{
attached, ///\brief after intance is created internal java buffers are auto attached for jstring, jarray
detached //\brief after intance is created internal java buffers are not attached
};
template<typename CharType>
struct char_traits : public std::char_traits<CharType>
{};
template<>
struct char_traits<char> : public std::char_traits<char>
{
inline static char const * jatatch_string(jenv env, ::jstring instance) noexcept
{ return env->GetStringUTFChars(instance, nullptr); }
inline static void detach_string(jenv env, ::jstring instance, char const * ptr ) noexcept
{ env->ReleaseStringUTFChars(instance, ptr); }
inline static ::jstring construct( jenv env, char const * src , size_t sz = 0u) noexcept
{ return env->NewStringUTF(src); }
inline static size_t length(jenv env, ::jstring s, char_type const * p) noexcept { return std::char_traits<char>::length(p); }
};
#if 0
template<>
struct char_traits<char16_t> : public std::char_traits<char16_t>
{
inline static char16_t const * jatatch_string(jenv env, ::jstring instance) noexcept
{ return reinterpret_cast<char16_t const *>(env->GetStringChars(instance, nullptr)); }
inline static void detach_string(jenv env, ::jstring instance, char16_t const * ptr ) noexcept
{ env->ReleaseStringChars(instance, reinterpret_cast<jchar const *>(ptr)); }
inline static ::jstring construct( jenv env, char16_t const * src ) noexcept
{ return env->NewString(reinterpret_cast<jchar const *>(src), std::char_traits<char16_t>::length(src) ); }
inline static ::jstring construct( jenv env, char16_t const * src, size_t sz ) noexcept
{ return env->NewString(reinterpret_cast<jchar const *>(src),sz); }
//charset unused
inline static ::jstring construct( jenv env, wchar_t const * src, size_t sz, uint8_t charset = 0 ) noexcept
{
Aqurat::u16_char_buffer_type buff;
size_t const code_points_count { Aqurat::WasU16(src, src + sz, buff) };
if( !buff.empty())
return env->NewString(reinterpret_cast<jchar const *>(buff.data()), code_points_count );
return nullptr;
}
///\warning u16 java string is not nullterminated
inline static size_t length(jenv env, ::jstring s, char_type const * p) noexcept { return env->GetStringLength(s); }
};
#endif
template<typename CharType, typename CharTraits = char_traits<CharType>>
class basic_string
{
public:
using char_type = CharType;
using char_traits = CharTraits;
using const_pointer = char_type const *;
using const_iterator = const_pointer;
using native_string_type = std::basic_string<char_type>;
private:
jenv env_;
::jstring instance_;
const_pointer begin_, end_;
jownership_e owns_object_;
public:
inline explicit operator bool() const noexcept { return nullptr != instance_ ; }
inline char_type operator[]( size_t ix ) const noexcept { return begin_[ix]; }
inline operator native_string_type() const { return native_string_type{ c_str(), size() }; }
inline ::jstring get() const noexcept { return instance_; }
inline explicit operator ::jstring() const noexcept { return instance_; }
inline explicit operator ::jobject() const noexcept { return instance_; }
inline bool empty() const noexcept { return begin_ == end_; }
inline size_t size() const noexcept { return static_cast<size_t>(std::distance(begin(), end())); }
inline const_pointer data() const noexcept { return begin_; }
///\warning u16 string is not null terminated
inline const_pointer c_str() const noexcept { return begin_; }
inline const_iterator begin() const noexcept { return begin_; }
inline const_iterator end() const noexcept { return end_; }
inline basic_string() noexcept :
env_(), instance_(), begin_(), end_(), owns_object_()
{}
///\param mode use attach_mode_e::detached if string will be used only as argument to jni methods
template<typename friend_char_type>
basic_string(jenv env, size_t size, friend_char_type const * src, attach_mode_e mode = attach_mode_e::attached ) noexcept;
///\warning this constructor should be used only with char ansi, with char16 is ineffective, will calculate length
///\param src null terminated string
///\param mode use attach_mode_e::detached if string will be used only as argument to jni methods
basic_string(jenv env, char_type const * src, attach_mode_e mode = attach_mode_e::attached ) noexcept;
inline basic_string(jenv env, native_string_type const & src, attach_mode_e mode = attach_mode_e::attached ) noexcept :
basic_string( env, src.size(), src.c_str(), mode )
{}
///\warning if \param instance was obtained from call to java method in native code, set \param own to jownership_e::owned
///\param mode use attach_mode_e::detached if string will be used only as argument to jni methods
basic_string(jenv env, ::jstring instance, jownership_e own = jownership_e::external,
attach_mode_e mode = attach_mode_e::attached ) noexcept;
basic_string( basic_string && rh ) noexcept;
basic_string & operator=( basic_string && rh ) noexcept;
~basic_string() { reset(); }
void reset() noexcept;
///\brief releases repsponsibility for object, ex when returning obejct to java that was constructed in native code
::jstring release() noexcept;
};
using string = basic_string<char>;
// using u16string = basic_string<char16_t>;
inline std::ostream & operator << ( std::ostream & outstr, jni::string const & src )
{
outstr.write( src.c_str(), static_cast<ptrdiff_t>( src.size()) );
return outstr;
}
template<typename T, typename U>
template<typename friend_char_type>
basic_string<T,U>::basic_string(jenv env, size_t size, friend_char_type const * src, attach_mode_e mode ) noexcept :
env_(env), instance_( char_traits::construct(env,src,size) ),
begin_(), end_(), owns_object_(jownership_e::owned)
{
if(nullptr != instance_ && attach_mode_e::attached == mode)
{
begin_ = char_traits::jatatch_string(env, instance_);
if(nullptr != begin_)
end_= std::next(begin_, static_cast<ptrdiff_t>(char_traits::length(env,instance_,begin_)) );
}
}
extern template class basic_string<char>;
}
jstring.cc
#include <jstring.hpp>
namespace jni
{
template<typename T, typename U>
basic_string<T,U>::basic_string(jenv env, char_type const * src, attach_mode_e mode ) noexcept :
env_(env), instance_( char_traits::construct(env,src) ),
begin_(), end_(), owns_object_(jownership_e::owned)
{
if( nullptr != instance_ && attach_mode_e::attached == mode )
{
begin_ = char_traits::jatatch_string(env, instance_);
if(nullptr != begin_)
end_= std::next(begin_, static_cast<ptrdiff_t>( char_traits::length(env,instance_,begin_)) );
}
}
template<typename T, typename U>
basic_string<T,U>::basic_string( basic_string && rh ) noexcept :
env_(rh.env_), instance_(rh.instance_), begin_(rh.begin_), end_(rh.end_), owns_object_(rh.owns_object_)
{
rh.env_ = nullptr;
rh.instance_ = nullptr;
rh.begin_ = nullptr;
rh.end_ = nullptr;
rh.owns_object_ = jownership_e::external;
}
template<typename T, typename U>
basic_string<T,U>::basic_string(jenv env, ::jstring instance, jownership_e own, attach_mode_e mode ) noexcept :
env_(env), instance_(instance), begin_(), end_(), owns_object_(own)
{
if(nullptr != instance_ && attach_mode_e::attached == mode)
{
begin_ = char_traits::jatatch_string(env, instance_);
if(nullptr != begin_)
end_= std::next(begin_, static_cast<ptrdiff_t>(char_traits::length(env,instance_,begin_)) );
}
}
template<typename T, typename U>
basic_string<T,U> &
basic_string<T,U>::operator=( basic_string && rh ) noexcept
{
std::swap(env_,rh.env_);
std::swap(instance_,rh.instance_);
std::swap(begin_,rh.begin_);
std::swap(end_,rh.end_);
std::swap(owns_object_,rh.owns_object_);
return *this;
}
template<typename T, typename U>
::jstring basic_string<T,U>::release() noexcept
{
::jstring ret { instance_ };
if( nullptr != instance_ )
{
if(nullptr != begin_)
{
char_traits::detach_string(env_, instance_, begin_ );
begin_ = nullptr;
end_ = nullptr;
}
env_ = nullptr;
owns_object_ = jownership_e::external;
instance_ = nullptr;
}
return ret;
}
template<typename T, typename U>
void basic_string<T,U>::reset() noexcept
{
if( nullptr != instance_ )
{
if(nullptr != begin_)
{
char_traits::detach_string(env_, instance_, begin_ );
begin_ = nullptr;
end_ = nullptr;
}
if(owns_object_ == jownership_e::owned)
env_->DeleteLocalRef(instance_);
instance_ = nullptr;
env_ = nullptr;
}
}
template class basic_string<char>;
}