Commit d74d3ae5 authored by Andrew Twyman's avatar Andrew Twyman

Standardize whitespace in code, with a repeatable script

parent 7dfc5b18
File mode changed from 100755 to 100644
......@@ -9,26 +9,26 @@ import java.util.logging.Logger;
import com.dropbox.djinni.NativeLibLoader;
public class SortTest {
private static SecureRandom random = new SecureRandom();
private static final Logger log =
Logger.getLogger(SortTest.class.getName());
public static String randomString() {
return new BigInteger(130, random).toString(10).substring(0, 5);
}
public static void main(String[] args) throws Exception {
public static void main(String[] args) throws Exception {
NativeLibLoader.loadLibs();
// Create some random strings to sort below
ArrayList<String> strs = new ArrayList<String>();
for (int i = 0; i < 5; ++i) {
strs.add(randomString());
}
log.log(Level.INFO, "Input strings:\n" + String.join("\n", strs));
// Sort them!
ItemList sorted = SortItems.runSort(new ItemList(strs));
log.log(
......
......@@ -26,7 +26,7 @@ import com.intellij.psi.TokenType;
/**
* This class is a scanner generated by
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
* on 8/11/15 2:15 PM from the specification file
* <tt>/Users/jaetzold/src/idea/plugins/djinni/src/com/dropbox/djinni/ideaplugin/YamlLexer.flex</tt>
......@@ -45,23 +45,23 @@ class YamlLexer implements FlexLexer {
* at the beginning of a line
* l is of the form l = 2*k, k a non negative integer
*/
private static final int ZZ_LEXSTATE[] = {
private static final int ZZ_LEXSTATE[] = {
0, 0, 1, 1
};
/**
/**
* Translates characters to character classes
*/
private static final String ZZ_CMAP_PACKED =
private static final String ZZ_CMAP_PACKED =
"\11\0\1\3\1\1\1\0\1\6\1\2\22\0\1\5\1\7\1\0"+
"\1\7\26\0\1\10\2\0\1\10\36\0\1\4\uffa3\0";
/**
/**
* Translates characters to character classes
*/
private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED);
/**
/**
* Translates DFA states to action switch labels.
*/
private static final int [] ZZ_ACTION = zzUnpackAction();
......@@ -90,7 +90,7 @@ class YamlLexer implements FlexLexer {
}
/**
/**
* Translates a state to a row index in the transition table
*/
private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
......@@ -118,7 +118,7 @@ class YamlLexer implements FlexLexer {
return j;
}
/**
/**
* The transition table of the DFA
*/
private static final int [] ZZ_TRANS = zzUnpackTrans();
......@@ -250,7 +250,7 @@ class YamlLexer implements FlexLexer {
}
/**
/**
* Unpacks the compressed character translation table.
*
* @param packed the packed character translation table
......@@ -399,7 +399,7 @@ class YamlLexer implements FlexLexer {
private void zzDoEOF() {
if (!zzEOFDone) {
zzEOFDone = true;
}
}
......@@ -482,35 +482,35 @@ class YamlLexer implements FlexLexer {
zzMarkedPos = zzMarkedPosL;
switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
case 6:
case 6:
{ yybegin(WAITING_VALUE);return YamlTypes.SEPARATOR;
}
case 9: break;
case 2:
case 2:
{ yybegin(YYINITIAL); return YamlTypes.CRLF;
}
case 10: break;
case 5:
case 5:
{ yybegin(YYINITIAL); return YamlTypes.COMMENT;
}
case 11: break;
case 4:
case 4:
{ return TokenType.BAD_CHARACTER;
}
case 12: break;
case 7:
case 7:
{ yybegin(YYINITIAL); return YamlTypes.VALUE;
}
case 13: break;
case 3:
case 3:
{ yybegin(YYINITIAL); return TokenType.WHITE_SPACE;
}
case 14: break;
case 8:
case 8:
{ yybegin(WAITING_VALUE); return TokenType.WHITE_SPACE;
}
case 15: break;
case 1:
case 1:
{ yybegin(YYINITIAL); return YamlTypes.KEY;
}
case 16: break;
......
......@@ -86,4 +86,4 @@ public class YamlParserDefinition implements ParserDefinition{
public PsiElement createElement(ASTNode node) {
return YamlTypes.Factory.createElement(node);
}
}
\ No newline at end of file
}
......@@ -23,7 +23,7 @@ import static com.dropbox.djinni.ideaplugin.psi.DjinniTypes.*;
/**
* This class is a scanner generated by
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
* on 8/12/15 1:36 PM from the specification file
* <tt>/Users/jaetzold/src/idea/plugins/djinni/src/com/dropbox/djinni/ideaplugin/_DjinniLexer.flex</tt>
......@@ -41,14 +41,14 @@ public class _DjinniLexer implements FlexLexer {
* at the beginning of a line
* l is of the form l = 2*k, k a non negative integer
*/
private static final int ZZ_LEXSTATE[] = {
private static final int ZZ_LEXSTATE[] = {
0, 0
};
/**
/**
* Translates characters to character classes
*/
private static final String ZZ_CMAP_PACKED =
private static final String ZZ_CMAP_PACKED =
"\11\0\1\1\1\2\1\3\1\1\1\1\22\0\1\1\1\0\1\7"+
"\1\4\3\0\1\5\1\27\1\30\1\0\1\22\1\21\1\10\1\12"+
"\1\0\12\11\1\17\1\20\1\25\1\16\1\26\1\0\1\31\32\15"+
......@@ -111,12 +111,12 @@ public class _DjinniLexer implements FlexLexer {
"\32\13\13\0\131\13\3\0\6\13\2\0\6\13\2\0\6\13\2\0"+
"\3\13\43\0";
/**
/**
* Translates characters to character classes
*/
private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED);
/**
/**
* Translates DFA states to action switch labels.
*/
private static final int [] ZZ_ACTION = zzUnpackAction();
......@@ -148,7 +148,7 @@ public class _DjinniLexer implements FlexLexer {
}
/**
/**
* Translates a state to a row index in the transition table
*/
private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
......@@ -180,7 +180,7 @@ public class _DjinniLexer implements FlexLexer {
return j;
}
/**
/**
* The transition table of the DFA
*/
private static final int [] ZZ_TRANS = zzUnpackTrans();
......@@ -329,7 +329,7 @@ public class _DjinniLexer implements FlexLexer {
}
/**
/**
* Unpacks the compressed character translation table.
*
* @param packed the packed character translation table
......@@ -549,99 +549,99 @@ public class _DjinniLexer implements FlexLexer {
zzMarkedPos = zzMarkedPosL;
switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
case 17:
case 17:
{ return LEFT_PARAM_BRACE;
}
case 25: break;
case 14:
case 14:
{ return RIGHT_BLOCK_BRACE;
}
case 26: break;
case 4:
case 4:
{ return COMMENT;
}
case 27: break;
case 22:
case 22:
{ return MAP;
}
case 28: break;
case 6:
case 6:
{ return IDENTIFIER;
}
case 29: break;
case 24:
case 24:
{ return OPTIONAL;
}
case 30: break;
case 1:
case 1:
{ return com.intellij.psi.TokenType.BAD_CHARACTER;
}
case 31: break;
case 12:
case 12:
{ return PLUS;
}
case 32: break;
case 11:
case 11:
{ return LIST_SEPARATOR;
}
case 33: break;
case 9:
case 9:
{ return COLON;
}
case 34: break;
case 20:
case 20:
{ return STRING_LITERAL;
}
case 35: break;
case 13:
case 13:
{ return LEFT_BLOCK_BRACE;
}
case 36: break;
case 19:
case 19:
{ return AT;
}
case 37: break;
case 21:
case 21:
{ return SET;
}
case 38: break;
case 23:
case 23:
{ return LIST;
}
case 39: break;
case 10:
case 10:
{ return SEMICOLON;
}
case 40: break;
case 18:
case 18:
{ return RIGHT_PARAM_BRACE;
}
case 41: break;
case 15:
case 15:
{ return LEFT_GENERICS_BRACE;
}
case 42: break;
case 16:
case 16:
{ return RIGHT_GENERICS_BRACE;
}
case 43: break;
case 8:
case 8:
{ return EQ;
}
case 44: break;
case 3:
case 3:
{ return SPACE;
}
case 45: break;
case 7:
case 7:
{ return TEXT;
}
case 46: break;
case 5:
case 5:
{ return NUMBER_LITERAL;
}
case 47: break;
case 2:
case 2:
{ return com.intellij.psi.TokenType.WHITE_SPACE;
}
case 48: break;
......
......@@ -38,7 +38,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
def find(ty: TypeRef) { find(ty.resolved) }
def find(tm: MExpr) {
tm.args.foreach(find)
find(tm.base)
find(tm.base)
}
def find(m: Meta) = for(r <- objcppMarshal.references(m)) r match {
case ImportRef(arg) => body.add("#import " + arg)
......@@ -78,7 +78,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
case Some(nnHdr) => refs.privHeader.add("#include " + nnHdr)
case _ =>
}
def writeObjcFuncDecl(method: Interface.Method, w: IndentWriter) {
val label = if (method.static) "+" else "-"
val ret = objcMarshal.fqReturnType(method.ret)
......@@ -264,7 +264,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
}
w.wl
val fromCppFunc = if (spec.cppNnType.isEmpty) "fromCpp(const CppType& cpp)"
else "fromCppOpt(const CppOptType& cpp)"
else "fromCppOpt(const CppOptType& cpp)"
w.wl(s"auto $helperClass::$fromCppFunc -> ObjcType").braced {
// Handle null
w.w("if (!cpp)").braced {
......@@ -309,7 +309,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
refs.privHeader.add("!#import " + q(spec.objcppIncludeObjcPrefix + (if(r.ext.objc) "../" else "") + headerName(ident)))
refs.privHeader.add("!#include " + q(spec.objcppIncludeCppPrefix + (if(r.ext.cpp) "../" else "") + spec.cppFileIdentStyle(ident) + "." + spec.cppHeaderExt))
refs.body.add("#include <cassert>")
refs.body.add("!#import " + q(spec.objcppIncludePrefix + objcppMarshal.privateHeaderName(objcName)))
......
......@@ -18,7 +18,7 @@ class YamlGenerator(spec: Spec) extends Generator(spec) {
val jniMarshal = new JNIMarshal(spec)
case class QuotedString(str: String) // For anything that migt require escaping
private def writeYamlFile(name: String, origin: String, f: IndentWriter => Unit): Unit = {
createFile(spec.yamlOutFolder.get, name, out => new IndentWriter(out, " "), w => {
w.wl("# AUTOGENERATED FILE - DO NOT MODIFY!")
......@@ -40,59 +40,59 @@ class YamlGenerator(spec: Spec) extends Generator(spec) {
}
private def writeYamlFile(ident: String, origin: String, td: InternTypeDecl): Unit =
writeYamlFile(spec.yamlPrefix + ident + ".yaml", origin, w => {
writeYamlFile(spec.yamlPrefix + ident + ".yaml", origin, w => {
write(w, td)
})
})
private def write(w: IndentWriter, td: TypeDecl) {
write(w, preamble(td))
w.wl("cpp:").nested { write(w, cpp(td)) }
w.wl("objc:").nested { write(w, objc(td)) }
w.wl("objcpp:").nested { write(w, objcpp(td)) }
w.wl("java:").nested { write(w, java(td)) }
w.wl("jni:").nested { write(w, jni(td)) }
write(w, preamble(td))
w.wl("cpp:").nested { write(w, cpp(td)) }
w.wl("objc:").nested { write(w, objc(td)) }
w.wl("objcpp:").nested { write(w, objcpp(td)) }
w.wl("java:").nested { write(w, java(td)) }
w.wl("jni:").nested { write(w, jni(td)) }
}
private def write(w: IndentWriter, m: Map[String, Any]) {
for((k, v) <- m) {
w.w(k + ": ")
v match {
case s: String => write(w, s)
case s: QuotedString => write(w, s)
case m: Map[_, _] => w.wl.nested { write(w, m.asInstanceOf[Map[String, Any]]) }
case s: Seq[_] => write(w, s)
case b: Boolean => write(w, b)
case _ => throw new AssertionError("unexpected map value")
}
}
for((k, v) <- m) {
w.w(k + ": ")
v match {
case s: String => write(w, s)
case s: QuotedString => write(w, s)
case m: Map[_, _] => w.wl.nested { write(w, m.asInstanceOf[Map[String, Any]]) }
case s: Seq[_] => write(w, s)
case b: Boolean => write(w, b)
case _ => throw new AssertionError("unexpected map value")
}
}
}
private def write(w: IndentWriter, s: Seq[Any]) {
// The only arrays we have are small enough to use flow notation
w.wl(s.mkString("[", ",", "]"))
// The only arrays we have are small enough to use flow notation
w.wl(s.mkString("[", ",", "]"))
}
private def write(w: IndentWriter, b: Boolean) {
w.wl(if(b) "true" else "false")
w.wl(if(b) "true" else "false")
}
private def write(w: IndentWriter, s: String) {
if(s.isEmpty) w.wl(q("")) else w.wl(s)
if(s.isEmpty) w.wl(q("")) else w.wl(s)
}
private def write(w: IndentWriter, s: QuotedString) {
if(s.str.isEmpty) w.wl(q("")) else w.wl("'" + s.str.replaceAllLiterally("'", "''") + "'")
if(s.str.isEmpty) w.wl(q("")) else w.wl("'" + s.str.replaceAllLiterally("'", "''") + "'")
}
private def preamble(td: TypeDecl) = Map[String, Any](
"name" -> (spec.yamlPrefix + td.ident.name),
"typedef" -> QuotedString(typeDef(td)),
"params" -> td.params.collect { case p: TypeParam => p.ident.name },
"params" -> td.params.collect { case p: TypeParam => p.ident.name },
"prefix" -> spec.yamlPrefix
)
private def typeDef(td: TypeDecl) = {
def ext(e: Ext): String = (if(e.cpp) " +c" else "") + (if(e.objc) " +o" else "") + (if(e.java) " +j" else "")
def ext(e: Ext): String = (if(e.cpp) " +c" else "") + (if(e.objc) " +o" else "") + (if(e.java) " +j" else "")
def deriving(r: Record) = {
if(r.derivingTypes.isEmpty) {
""
......@@ -103,11 +103,11 @@ class YamlGenerator(spec: Spec) extends Generator(spec) {
}.mkString(" deriving(", ", ", ")")
}
}
td.body match {
case i: Interface => "interface" + ext(i.ext)
case r: Record => "record" + ext(r.ext) + deriving(r)
case e: Enum => "enum"
}
td.body match {
case i: Interface => "interface" + ext(i.ext)
case r: Record => "record" + ext(r.ext) + deriving(r)
case e: Enum => "enum"
}
}
private def cpp(td: TypeDecl) = Map[String, Any](
......@@ -138,8 +138,8 @@ class YamlGenerator(spec: Spec) extends Generator(spec) {
)
private def jni(td: TypeDecl) = Map[String, Any](
"translator" -> QuotedString(jniMarshal.helperName(mexpr(td))),
"header" -> QuotedString(jniMarshal.include(td.ident)),
"translator" -> QuotedString(jniMarshal.helperName(mexpr(td))),
"header" -> QuotedString(jniMarshal.include(td.ident)),
"typename" -> jniMarshal.fqParamType(mexpr(td)),
"typeSignature" -> QuotedString(jniMarshal.fqTypename(td.ident, td.body))
)
......@@ -148,44 +148,44 @@ class YamlGenerator(spec: Spec) extends Generator(spec) {
private def mexpr(td: TypeDecl) = MExpr(meta(td), List())
private def meta(td: TypeDecl) = {
val defType = td.body match {
case i: Interface => DInterface
case r: Record => DRecord
case e: Enum => DEnum
}
MDef(td.ident, 0, defType, td.body)
val defType = td.body match {
case i: Interface => DInterface
case r: Record => DRecord
case e: Enum => DEnum
}
MDef(td.ident, 0, defType, td.body)
}
override def generate(idl: Seq[TypeDecl]) {
val internOnly = idl.collect { case itd: InternTypeDecl => itd }.sortWith(_.ident.name < _.ident.name)
if(spec.yamlOutFile.isDefined) {
writeYamlFile(internOnly)
} else {
for(td <- internOnly) {
writeYamlFile(td.ident, td.origin, td)
}
}
val internOnly = idl.collect { case itd: InternTypeDecl => itd }.sortWith(_.ident.name < _.ident.name)
if(spec.yamlOutFile.isDefined) {
writeYamlFile(internOnly)
} else {
for(td <- internOnly) {
writeYamlFile(td.ident, td.origin, td)
}
}
}
override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum) {
// unused
// unused
}
override def generateInterface(origin: String, ident: Ident, doc: Doc, typeParams: Seq[TypeParam], i: Interface) {
// unused
// unused
}
override def generateRecord(origin: String, ident: Ident, doc: Doc, params: Seq[TypeParam], r: Record) {
// unused
// unused
}
}
object YamlGenerator {
def metaFromYaml(td: ExternTypeDecl) = MExtern(
td.ident.name.stripPrefix(td.properties("prefix").toString), // Make sure the generator uses this type with its original name for all intents and purposes
td.params.size,
defType(td),
td.body,
td.params.size,
defType(td),
td.body,
MExtern.Cpp(
nested(td, "cpp")("typename").toString,
nested(td, "cpp")("header").toString,
......@@ -213,12 +213,12 @@ object YamlGenerator {
)
private def nested(td: ExternTypeDecl, key: String) = {
td.properties.get(key).collect { case m: JMap[_, _] => m.collect { case (k: String, v: Any) => (k, v) } } getOrElse(Map[String, Any]())
td.properties.get(key).collect { case m: JMap[_, _] => m.collect { case (k: String, v: Any) => (k, v) } } getOrElse(Map[String, Any]())
}
private def defType(td: ExternTypeDecl) = td.body match {
case i: Interface => DInterface
case r: Record => DRecord
case e: Enum => DEnum
case i: Interface => DInterface
case r: Record => DRecord
case e: Enum => DEnum
}
}
......@@ -248,7 +248,7 @@ abstract class Generator(spec: Spec)
}
protected def createFile(folder: File, fileName: String, f: IndentWriter => Unit): Unit = createFile(folder, fileName, out => new IndentWriter(out), f)
implicit def identToString(ident: Ident): String = ident.name
val idCpp = spec.cppIdentStyle
val idJava = spec.javaIdentStyle
......
//
//
// Copyright 2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
......@@ -45,33 +45,33 @@ import java.util.stream.Stream;
* <code>
* NativeLibLoader.loadLibs()
* </code>
* to load the libraries (e.g. in your main() or a class static initializer).
* to load the libraries (e.g. in your main() or a class static initializer).
*/
public class NativeLibLoader {
/**
* Canonical directory in a jar containing (djinni-adapted) native libraries
*/
public static final String djinniNativeLibsJarPath =
"resources/djinni_native_libs";
/**
* Load native libraries with djinni support from the (comma-separated)
* path(s) provided in this system property
* path(s) provided in this system property
*/
public static final String djinniNativeLibsSysProp =
"djinni.native_libs_dirs";
private static final Logger log =
Logger.getLogger(NativeLibLoader.class.getName());
private NativeLibLoader() { }
private NativeLibLoader() { }
// Load native libs from canonical locations
public static void loadLibs() throws URISyntaxException, IOException {
// Try to load from Jar
loadLibsFromJarPath(djinniNativeLibsJarPath);
// Try to load from system
String localPaths = System.getProperty(djinniNativeLibsSysProp);
if (localPaths != null) {
......@@ -81,7 +81,7 @@ public class NativeLibLoader {
}
}
}
// Load native lib(s) from the given `localPath` - a file or directory
public static void loadLibsFromLocalPath(Path localPath) throws IOException {
File localFile = localPath.toFile();
......@@ -100,7 +100,7 @@ public class NativeLibLoader {
loadLibrary(localFile.getAbsolutePath());
}
}
// Load a directory of libs from a jar resource path
public static void loadLibsFromJarPath(String jarPath)
throws URISyntaxException, IOException {
......@@ -111,12 +111,12 @@ public class NativeLibLoader {
.getClassLoader()
.getResource(djinniNativeLibsJarPath);
if (libsURL == null) { return; }
// Are we actually referencing a jar path?
if (!libsURL.toURI().getScheme().equals("jar")) { return; }
log.log(Level.FINE, "Loading libs from jar path " + jarPath);
// Walk the directory and load libs
FileSystem fs =
FileSystems.newFileSystem(libsURL.toURI(), Collections.emptyMap());
......@@ -124,10 +124,10 @@ public class NativeLibLoader {
for (Path p : (Iterable<Path>)Files.walk(myPath, 1)::iterator) {
loadLibFromJarPath(p);
}
fs.close();
}
// Load a single native lib from a jar resource with path `libPath`
public static void loadLibFromJarPath(Path libPath) throws IOException {
......@@ -137,7 +137,7 @@ public class NativeLibLoader {
InputStream libIn =
NativeLibLoader.class.getResourceAsStream(libPath.toString());
if (libIn == null) { return; } // Invalid `libPath`
// Name the tempfile
String libName = libPath.getName(libPath.getNameCount() - 1).toString();
// Name the tempfile after the lib to ease debugging
......@@ -146,27 +146,27 @@ public class NativeLibLoader {
if (extPos > 0) { suffix = libName.substring(extPos + 1); }
// Try to suffix the tempfile with the lib's suffix so that other
// tools (e.g. profilers) identify the file correctly
File tempLib = File.createTempFile(libName, suffix);
tempLib.deleteOnExit();
log.log(
Level.FINE,
"Copying jar lib " + libPath + " to " + tempLib.getAbsolutePath());
try {
Files.copy(libIn, tempLib.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (SecurityException e) {
} catch (SecurityException e) {
throw new RuntimeException(
"SecurityException while trying to create tempfile: " +
e.getMessage() + "\n\n If you cannot grant this process " +
"permissions to create temporary files, you need to install " +
"the native libraries manually and provide the installation " +
"the native libraries manually and provide the installation " +
"path(s) using the system property " + djinniNativeLibsSysProp);
}
loadLibrary(tempLib.getAbsolutePath());
}
private static void loadLibrary(String abspath) {
System.load(abspath);
log.log(Level.INFO, "Loaded " + abspath);
......
......@@ -27,166 +27,166 @@
namespace djinni
{
template<class Self, class CppT, class JniT>
class Primitive
{
public:
using CppType = CppT;
using JniType = JniT;
static CppType toCpp(JNIEnv* /*jniEnv*/, JniType j) noexcept { return static_cast<CppType>(j); }
static JniType fromCpp(JNIEnv* /*jniEnv*/, CppType c) noexcept { return static_cast<JniType>(c); }
struct Boxed
{
using JniType = jobject;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
const auto& data = JniClass<Self>::get();
assert(jniEnv->IsInstanceOf(j, data.clazz.get()));
auto ret = Primitive::toCpp(jniEnv, Self::unbox(jniEnv, data.method_unbox, j));
jniExceptionCheck(jniEnv);
return ret;
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, CppType c)
{
const auto& data = JniClass<Self>::get();
auto ret = jniEnv->CallStaticObjectMethod(data.clazz.get(), data.method_box, Primitive::fromCpp(jniEnv, c));
jniExceptionCheck(jniEnv);
return {jniEnv, ret};
}
};
protected:
Primitive(const char* javaClassSpec,
const char* staticBoxMethod,
const char* staticBoxMethodSignature,
const char* unboxMethod,
const char* unboxMethodSignature)
: clazz(jniFindClass(javaClassSpec))
, method_box(jniGetStaticMethodID(clazz.get(), staticBoxMethod, staticBoxMethodSignature))
, method_unbox(jniGetMethodID(clazz.get(), unboxMethod, unboxMethodSignature))
{}
private:
const GlobalRef<jclass> clazz;
const jmethodID method_box;
const jmethodID method_unbox;
};
class Bool : public Primitive<Bool, bool, jboolean>
{
Bool() : Primitive("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", "booleanValue", "()Z") {}
friend JniClass<Bool>;
friend Primitive<Bool, bool, jboolean>;
static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {
template<class Self, class CppT, class JniT>
class Primitive
{
public:
using CppType = CppT;
using JniType = JniT;
static CppType toCpp(JNIEnv* /*jniEnv*/, JniType j) noexcept { return static_cast<CppType>(j); }
static JniType fromCpp(JNIEnv* /*jniEnv*/, CppType c) noexcept { return static_cast<JniType>(c); }
struct Boxed
{
using JniType = jobject;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
const auto& data = JniClass<Self>::get();
assert(jniEnv->IsInstanceOf(j, data.clazz.get()));
auto ret = Primitive::toCpp(jniEnv, Self::unbox(jniEnv, data.method_unbox, j));
jniExceptionCheck(jniEnv);
return ret;
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, CppType c)
{
const auto& data = JniClass<Self>::get();
auto ret = jniEnv->CallStaticObjectMethod(data.clazz.get(), data.method_box, Primitive::fromCpp(jniEnv, c));
jniExceptionCheck(jniEnv);
return {jniEnv, ret};
}
};
protected:
Primitive(const char* javaClassSpec,
const char* staticBoxMethod,
const char* staticBoxMethodSignature,
const char* unboxMethod,
const char* unboxMethodSignature)
: clazz(jniFindClass(javaClassSpec))
, method_box(jniGetStaticMethodID(clazz.get(), staticBoxMethod, staticBoxMethodSignature))
, method_unbox(jniGetMethodID(clazz.get(), unboxMethod, unboxMethodSignature))
{}
private:
const GlobalRef<jclass> clazz;
const jmethodID method_box;
const jmethodID method_unbox;
};
class Bool : public Primitive<Bool, bool, jboolean>
{
Bool() : Primitive("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", "booleanValue", "()Z") {}
friend JniClass<Bool>;
friend Primitive<Bool, bool, jboolean>;
static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {
auto result = jniEnv->CallBooleanMethod(j, method);
jniExceptionCheck(jniEnv);
return result;
}
};
class I8 : public Primitive<I8, int8_t, jbyte>
{
I8() : Primitive("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", "byteValue", "()B") {}
friend JniClass<I8>;
friend Primitive<I8, int8_t, jbyte>;
};
class I8 : public Primitive<I8, int8_t, jbyte>
{
I8() : Primitive("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", "byteValue", "()B") {}
friend JniClass<I8>;
friend Primitive<I8, int8_t, jbyte>;
static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {
auto result = jniEnv->CallByteMethod(j, method);
jniExceptionCheck(jniEnv);
return result;
}
};
class I16 : public Primitive<I16, int16_t, jshort>
{
I16() : Primitive("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", "shortValue", "()S") {}
friend JniClass<I16>;
friend Primitive<I16, int16_t, jshort>;
};
class I16 : public Primitive<I16, int16_t, jshort>
{
I16() : Primitive("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", "shortValue", "()S") {}
friend JniClass<I16>;
friend Primitive<I16, int16_t, jshort>;
static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {
auto result = jniEnv->CallShortMethod(j, method);
jniExceptionCheck(jniEnv);
return result;
}
};
class I32 : public Primitive<I32, int32_t, jint>
{
I32() : Primitive("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", "intValue", "()I") {}
friend JniClass<I32>;
friend Primitive<I32, int32_t, jint>;
};
class I32 : public Primitive<I32, int32_t, jint>
{
I32() : Primitive("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", "intValue", "()I") {}
friend JniClass<I32>;
friend Primitive<I32, int32_t, jint>;
static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {
auto result = jniEnv->CallIntMethod(j, method);
jniExceptionCheck(jniEnv);
return result;
}
};
class I64 : public Primitive<I64, int64_t, jlong>
{
I64() : Primitive("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", "longValue", "()J") {}
friend JniClass<I64>;
friend Primitive<I64, int64_t, jlong>;
};
class I64 : public Primitive<I64, int64_t, jlong>
{
I64() : Primitive("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", "longValue", "()J") {}
friend JniClass<I64>;
friend Primitive<I64, int64_t, jlong>;
static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {
auto result = jniEnv->CallLongMethod(j, method);
jniExceptionCheck(jniEnv);
return result;
}
};
};
class F32 : public Primitive<F32, float, jfloat>
{
F32() : Primitive("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", "floatValue", "()F") {}
friend JniClass<F32>;
friend Primitive<F32, float, jfloat>;
class F32 : public Primitive<F32, float, jfloat>
{
F32() : Primitive("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", "floatValue", "()F") {}
friend JniClass<F32>;
friend Primitive<F32, float, jfloat>;
static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {
auto result = jniEnv->CallFloatMethod(j, method);
jniExceptionCheck(jniEnv);
return result;
}
};
};
class F64 : public Primitive<F64, double, jdouble>
{
F64() : Primitive("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", "doubleValue", "()D") {}
friend JniClass<F64>;
friend Primitive<F64, double, jdouble>;
class F64 : public Primitive<F64, double, jdouble>
{
F64() : Primitive("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", "doubleValue", "()D") {}
friend JniClass<F64>;
friend Primitive<F64, double, jdouble>;
static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {
auto result = jniEnv->CallDoubleMethod(j, method);
jniExceptionCheck(jniEnv);
return result;
}
};
struct String
{
using CppType = std::string;
using JniType = jstring;
using Boxed = String;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
return jniUTF8FromString(jniEnv, j);
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)
{
return {jniEnv, jniStringFromUTF8(jniEnv, c.c_str())};
}
};
struct Binary
{
using CppType = std::vector<uint8_t>;
using JniType = jbyteArray;
using Boxed = Binary;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
};
struct String
{
using CppType = std::string;
using JniType = jstring;
using Boxed = String;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
return jniUTF8FromString(jniEnv, j);
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)
{
return {jniEnv, jniStringFromUTF8(jniEnv, c.c_str())};
}
};
struct Binary
{
using CppType = std::vector<uint8_t>;
using JniType = jbyteArray;
using Boxed = Binary;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
std::vector<uint8_t> ret;
......@@ -220,63 +220,63 @@ namespace djinni
}
return ret;
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)
{
assert(c.size() <= std::numeric_limits<jsize>::max());
auto j = LocalRef<jbyteArray>(jniEnv, jniEnv->NewByteArray(static_cast<jsize>(c.size())));
jniExceptionCheck(jniEnv);
// Using .data() on an empty vector is UB
if(!c.empty())
{
jniEnv->SetByteArrayRegion(j.get(), 0, c.size(), reinterpret_cast<const jbyte*>(c.data()));
}
return j;
}
};
struct Date
{
using CppType = std::chrono::system_clock::time_point;
using JniType = jobject;
using Boxed = Date;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
static const auto POSIX_EPOCH = std::chrono::system_clock::from_time_t(0);
assert(j != nullptr);
const auto & data = JniClass<Date>::get();
assert(jniEnv->IsInstanceOf(j, data.clazz.get()));
auto time_millis = jniEnv->CallLongMethod(j, data.method_get_time);
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)
{
assert(c.size() <= std::numeric_limits<jsize>::max());
auto j = LocalRef<jbyteArray>(jniEnv, jniEnv->NewByteArray(static_cast<jsize>(c.size())));
jniExceptionCheck(jniEnv);
return POSIX_EPOCH + std::chrono::milliseconds{time_millis};
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)
{
static const auto POSIX_EPOCH = std::chrono::system_clock::from_time_t(0);
const auto & data = JniClass<Date>::get();
const auto cpp_millis = std::chrono::duration_cast<std::chrono::milliseconds>(c - POSIX_EPOCH);
const jlong millis = static_cast<jlong>(cpp_millis.count());
auto j = LocalRef<jobject>(jniEnv, jniEnv->NewObject(data.clazz.get(), data.constructor, millis));
jniExceptionCheck(jniEnv);
return j;
}
private:
Date() = default;
friend ::djinni::JniClass<Date>;
const GlobalRef<jclass> clazz { jniFindClass("java/util/Date") };
const jmethodID constructor { jniGetMethodID(clazz.get(), "<init>", "(J)V") };
const jmethodID method_get_time { jniGetMethodID(clazz.get(), "getTime", "()J") };
};
template <template <class> class OptionalType, class T>
struct Optional
{
// Using .data() on an empty vector is UB
if(!c.empty())
{
jniEnv->SetByteArrayRegion(j.get(), 0, c.size(), reinterpret_cast<const jbyte*>(c.data()));
}
return j;
}
};
struct Date
{
using CppType = std::chrono::system_clock::time_point;
using JniType = jobject;
using Boxed = Date;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
static const auto POSIX_EPOCH = std::chrono::system_clock::from_time_t(0);
assert(j != nullptr);
const auto & data = JniClass<Date>::get();
assert(jniEnv->IsInstanceOf(j, data.clazz.get()));
auto time_millis = jniEnv->CallLongMethod(j, data.method_get_time);
jniExceptionCheck(jniEnv);
return POSIX_EPOCH + std::chrono::milliseconds{time_millis};
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)
{
static const auto POSIX_EPOCH = std::chrono::system_clock::from_time_t(0);
const auto & data = JniClass<Date>::get();
const auto cpp_millis = std::chrono::duration_cast<std::chrono::milliseconds>(c - POSIX_EPOCH);
const jlong millis = static_cast<jlong>(cpp_millis.count());
auto j = LocalRef<jobject>(jniEnv, jniEnv->NewObject(data.clazz.get(), data.constructor, millis));
jniExceptionCheck(jniEnv);
return j;
}
private:
Date() = default;
friend ::djinni::JniClass<Date>;
const GlobalRef<jclass> clazz { jniFindClass("java/util/Date") };
const jmethodID constructor { jniGetMethodID(clazz.get(), "<init>", "(J)V") };
const jmethodID method_get_time { jniGetMethodID(clazz.get(), "getTime", "()J") };
};
template <template <class> class OptionalType, class T>
struct Optional
{
// SFINAE helper: if C::CppOptType exists, opt_type<T>(nullptr) will return
// that type. If not, it returns OptionalType<C::CppType>. This is necessary
// because we special-case optional interfaces to be represented as a nullable
......@@ -285,228 +285,228 @@ namespace djinni
template <typename C> static typename C::CppOptType opt_type(typename C::CppOptType *);
using CppType = decltype(opt_type<T>(nullptr));
using JniType = typename T::Boxed::JniType;
using Boxed = Optional;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
return j ? CppType(T::Boxed::toCpp(jniEnv, j)) : CppType();
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const OptionalType<typename T::CppType> &c)
{
return c ? T::Boxed::fromCpp(jniEnv, *c) : LocalRef<JniType>{};
}
using JniType = typename T::Boxed::JniType;
using Boxed = Optional;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
return j ? CppType(T::Boxed::toCpp(jniEnv, j)) : CppType();
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const OptionalType<typename T::CppType> &c)
{
return c ? T::Boxed::fromCpp(jniEnv, *c) : LocalRef<JniType>{};
}
// fromCpp used for nullable shared_ptr
template <typename C = T>
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const typename C::CppOptType & cppOpt) {
return T::Boxed::fromCppOpt(jniEnv, cppOpt);
}
};
struct ListJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/util/ArrayList") };
const jmethodID constructor { jniGetMethodID(clazz.get(), "<init>", "(I)V") };
const jmethodID method_add { jniGetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z") };
const jmethodID method_get { jniGetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;") };
const jmethodID method_size { jniGetMethodID(clazz.get(), "size", "()I") };
};
template <class T>
class List
{
using ECppType = typename T::CppType;
using EJniType = typename T::Boxed::JniType;
public:
using CppType = std::vector<ECppType>;
using JniType = jobject;
using Boxed = List;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
const auto& data = JniClass<ListJniInfo>::get();
assert(jniEnv->IsInstanceOf(j, data.clazz.get()));
auto size = jniEnv->CallIntMethod(j, data.method_size);
};
struct ListJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/util/ArrayList") };
const jmethodID constructor { jniGetMethodID(clazz.get(), "<init>", "(I)V") };
const jmethodID method_add { jniGetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z") };
const jmethodID method_get { jniGetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;") };
const jmethodID method_size { jniGetMethodID(clazz.get(), "size", "()I") };
};
template <class T>
class List
{
using ECppType = typename T::CppType;
using EJniType = typename T::Boxed::JniType;
public:
using CppType = std::vector<ECppType>;
using JniType = jobject;
using Boxed = List;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
const auto& data = JniClass<ListJniInfo>::get();
assert(jniEnv->IsInstanceOf(j, data.clazz.get()));
auto size = jniEnv->CallIntMethod(j, data.method_size);
jniExceptionCheck(jniEnv);
auto c = CppType();
c.reserve(size);
for(jint i = 0; i < size; ++i)
{
auto je = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(j, data.method_get, i));
jniExceptionCheck(jniEnv);
c.push_back(T::Boxed::toCpp(jniEnv, static_cast<EJniType>(je.get())));
}
return c;
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)
{
const auto& data = JniClass<ListJniInfo>::get();
assert(c.size() <= std::numeric_limits<jint>::max());
auto size = static_cast<jint>(c.size());
auto j = LocalRef<jobject>(jniEnv, jniEnv->NewObject(data.clazz.get(), data.constructor, size));
jniExceptionCheck(jniEnv);
for(const auto& ce : c)
{
auto je = T::Boxed::fromCpp(jniEnv, ce);
jniEnv->CallBooleanMethod(j, data.method_add, get(je));
jniExceptionCheck(jniEnv);
}
return j;
}
};
struct IteratorJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/util/Iterator") };
const jmethodID method_next { jniGetMethodID(clazz.get(), "next", "()Ljava/lang/Object;") };
};
struct SetJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/util/HashSet") };
const jmethodID constructor { jniGetMethodID(clazz.get(), "<init>", "()V") };
const jmethodID method_add { jniGetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z") };
const jmethodID method_size { jniGetMethodID(clazz.get(), "size", "()I") };
const jmethodID method_iterator { jniGetMethodID(clazz.get(), "iterator", "()Ljava/util/Iterator;") };
};
template <class T>
class Set
{
using ECppType = typename T::CppType;
using EJniType = typename T::Boxed::JniType;
public:
using CppType = std::unordered_set<ECppType>;
using JniType = jobject;
using Boxed = Set;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
const auto& data = JniClass<SetJniInfo>::get();
const auto& iteData = JniClass<IteratorJniInfo>::get();
assert(jniEnv->IsInstanceOf(j, data.clazz.get()));
auto size = jniEnv->CallIntMethod(j, data.method_size);
auto c = CppType();
c.reserve(size);
for(jint i = 0; i < size; ++i)
{
auto je = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(j, data.method_get, i));
jniExceptionCheck(jniEnv);
c.push_back(T::Boxed::toCpp(jniEnv, static_cast<EJniType>(je.get())));
}
return c;
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)
{
const auto& data = JniClass<ListJniInfo>::get();
assert(c.size() <= std::numeric_limits<jint>::max());
auto size = static_cast<jint>(c.size());
auto j = LocalRef<jobject>(jniEnv, jniEnv->NewObject(data.clazz.get(), data.constructor, size));
jniExceptionCheck(jniEnv);
auto c = CppType();
auto it = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(j, data.method_iterator));
for(const auto& ce : c)
{
auto je = T::Boxed::fromCpp(jniEnv, ce);
jniEnv->CallBooleanMethod(j, data.method_add, get(je));
jniExceptionCheck(jniEnv);
}
return j;
}
};
struct IteratorJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/util/Iterator") };
const jmethodID method_next { jniGetMethodID(clazz.get(), "next", "()Ljava/lang/Object;") };
};
struct SetJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/util/HashSet") };
const jmethodID constructor { jniGetMethodID(clazz.get(), "<init>", "()V") };
const jmethodID method_add { jniGetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z") };
const jmethodID method_size { jniGetMethodID(clazz.get(), "size", "()I") };
const jmethodID method_iterator { jniGetMethodID(clazz.get(), "iterator", "()Ljava/util/Iterator;") };
};
template <class T>
class Set
{
using ECppType = typename T::CppType;
using EJniType = typename T::Boxed::JniType;
public:
using CppType = std::unordered_set<ECppType>;
using JniType = jobject;
using Boxed = Set;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
const auto& data = JniClass<SetJniInfo>::get();
const auto& iteData = JniClass<IteratorJniInfo>::get();
assert(jniEnv->IsInstanceOf(j, data.clazz.get()));
auto size = jniEnv->CallIntMethod(j, data.method_size);
jniExceptionCheck(jniEnv);
auto c = CppType();
auto it = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(j, data.method_iterator));
jniExceptionCheck(jniEnv);
for(jint i = 0; i < size; ++i)
{
auto je = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(it, iteData.method_next));
jniExceptionCheck(jniEnv);
c.insert(T::Boxed::toCpp(jniEnv, static_cast<EJniType>(je.get())));
}
return c;
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)
{
assert(c.size() <= std::numeric_limits<jint>::max());
const auto& data = JniClass<SetJniInfo>::get();
auto j = LocalRef<jobject>(jniEnv, jniEnv->NewObject(data.clazz.get(), data.constructor));
jniExceptionCheck(jniEnv);
for(jint i = 0; i < size; ++i)
{
auto je = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(it, iteData.method_next));
jniExceptionCheck(jniEnv);
c.insert(T::Boxed::toCpp(jniEnv, static_cast<EJniType>(je.get())));
}
return c;
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)
{
assert(c.size() <= std::numeric_limits<jint>::max());
const auto& data = JniClass<SetJniInfo>::get();
auto j = LocalRef<jobject>(jniEnv, jniEnv->NewObject(data.clazz.get(), data.constructor));
jniExceptionCheck(jniEnv);
for(const auto& ce : c)
{
auto je = T::fromCpp(jniEnv, ce);
jniEnv->CallBooleanMethod(j, data.method_add, get(je));
jniExceptionCheck(jniEnv);
}
return j;
}
};
struct MapJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/util/HashMap") };
const jmethodID constructor { jniGetMethodID(clazz.get(), "<init>", "()V") };
const jmethodID method_put { jniGetMethodID(clazz.get(), "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") };
const jmethodID method_size { jniGetMethodID(clazz.get(), "size", "()I") };
const jmethodID method_entrySet { jniGetMethodID(clazz.get(), "entrySet", "()Ljava/util/Set;") };
};
struct EntrySetJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/util/Set") };
const jmethodID method_iterator { jniGetMethodID(clazz.get(), "iterator", "()Ljava/util/Iterator;") };
};
struct EntryJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/util/Map$Entry") };
const jmethodID method_getKey { jniGetMethodID(clazz.get(), "getKey", "()Ljava/lang/Object;") };
const jmethodID method_getValue { jniGetMethodID(clazz.get(), "getValue", "()Ljava/lang/Object;") };
};
template <class Key, class Value>
class Map
{
using CppKeyType = typename Key::CppType;
using CppValueType = typename Value::CppType;
using JniKeyType = typename Key::Boxed::JniType;
using JniValueType = typename Value::Boxed::JniType;
public:
using CppType = std::unordered_map<CppKeyType, CppValueType>;
using JniType = jobject;
using Boxed = Map;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
const auto& data = JniClass<MapJniInfo>::get();
const auto& entrySetData = JniClass<EntrySetJniInfo>::get();
const auto& entryData = JniClass<EntryJniInfo>::get();
const auto& iteData = JniClass<IteratorJniInfo>::get();
assert(jniEnv->IsInstanceOf(j, data.clazz.get()));
auto size = jniEnv->CallIntMethod(j, data.method_size);
for(const auto& ce : c)
{
auto je = T::fromCpp(jniEnv, ce);
jniEnv->CallBooleanMethod(j, data.method_add, get(je));
jniExceptionCheck(jniEnv);
}
return j;
}
};
struct MapJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/util/HashMap") };
const jmethodID constructor { jniGetMethodID(clazz.get(), "<init>", "()V") };
const jmethodID method_put { jniGetMethodID(clazz.get(), "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") };
const jmethodID method_size { jniGetMethodID(clazz.get(), "size", "()I") };
const jmethodID method_entrySet { jniGetMethodID(clazz.get(), "entrySet", "()Ljava/util/Set;") };
};
struct EntrySetJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/util/Set") };
const jmethodID method_iterator { jniGetMethodID(clazz.get(), "iterator", "()Ljava/util/Iterator;") };
};
struct EntryJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/util/Map$Entry") };
const jmethodID method_getKey { jniGetMethodID(clazz.get(), "getKey", "()Ljava/lang/Object;") };
const jmethodID method_getValue { jniGetMethodID(clazz.get(), "getValue", "()Ljava/lang/Object;") };
};
template <class Key, class Value>
class Map
{
using CppKeyType = typename Key::CppType;
using CppValueType = typename Value::CppType;
using JniKeyType = typename Key::Boxed::JniType;
using JniValueType = typename Value::Boxed::JniType;
public:
using CppType = std::unordered_map<CppKeyType, CppValueType>;
using JniType = jobject;
using Boxed = Map;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
const auto& data = JniClass<MapJniInfo>::get();
const auto& entrySetData = JniClass<EntrySetJniInfo>::get();
const auto& entryData = JniClass<EntryJniInfo>::get();
const auto& iteData = JniClass<IteratorJniInfo>::get();
assert(jniEnv->IsInstanceOf(j, data.clazz.get()));
auto size = jniEnv->CallIntMethod(j, data.method_size);
jniExceptionCheck(jniEnv);
auto entrySet = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(j, data.method_entrySet));
auto entrySet = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(j, data.method_entrySet));
jniExceptionCheck(jniEnv);
auto c = CppType();
c.reserve(size);
auto it = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(entrySet, entrySetData.method_iterator));
auto c = CppType();
c.reserve(size);
auto it = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(entrySet, entrySetData.method_iterator));
jniExceptionCheck(jniEnv);
for(jint i = 0; i < size; ++i)
{
auto je = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(it, iteData.method_next));
for(jint i = 0; i < size; ++i)
{
auto je = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(it, iteData.method_next));
jniExceptionCheck(jniEnv);
auto jKey = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(je, entryData.method_getKey));
jniExceptionCheck(jniEnv);
auto jKey = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(je, entryData.method_getKey));
auto jValue = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(je, entryData.method_getValue));
jniExceptionCheck(jniEnv);
c.emplace(Key::Boxed::toCpp(jniEnv, static_cast<JniKeyType>(jKey.get())),
Value::Boxed::toCpp(jniEnv, static_cast<JniValueType>(jValue.get())));
}
return c;
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)
{
const auto& data = JniClass<MapJniInfo>::get();
assert(c.size() <= std::numeric_limits<jint>::max());
auto size = c.size();
auto j = LocalRef<jobject>(jniEnv, jniEnv->NewObject(data.clazz.get(), data.constructor, size));
jniExceptionCheck(jniEnv);
for(const auto& ce : c)
{
auto jKey = Key::Boxed::fromCpp(jniEnv, ce.first);
auto jValue = Value::Boxed::fromCpp(jniEnv, ce.second);
jniEnv->CallObjectMethod(j, data.method_put, get(jKey), get(jValue));
jniExceptionCheck(jniEnv);
auto jValue = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(je, entryData.method_getValue));
jniExceptionCheck(jniEnv);
c.emplace(Key::Boxed::toCpp(jniEnv, static_cast<JniKeyType>(jKey.get())),
Value::Boxed::toCpp(jniEnv, static_cast<JniValueType>(jValue.get())));
}
return c;
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)
{
const auto& data = JniClass<MapJniInfo>::get();
assert(c.size() <= std::numeric_limits<jint>::max());
auto size = c.size();
auto j = LocalRef<jobject>(jniEnv, jniEnv->NewObject(data.clazz.get(), data.constructor, size));
jniExceptionCheck(jniEnv);
for(const auto& ce : c)
{
auto jKey = Key::Boxed::fromCpp(jniEnv, ce.first);
auto jValue = Value::Boxed::fromCpp(jniEnv, ce.second);
jniEnv->CallObjectMethod(j, data.method_put, get(jKey), get(jValue));
jniExceptionCheck(jniEnv);
}
return j;
}
};
}
return j;
}
};
} // namespace djinni
......@@ -12,4 +12,3 @@ java:
linux:
cd ..; ./test-suite/java/docker/run_dockerized_test.sh
......@@ -5,52 +5,52 @@
namespace djinni
{
struct DurationJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/time/Duration") };
const jmethodID method_ofNanos { jniGetStaticMethodID(clazz.get(), "ofNanos", "(J)Ljava/time/Duration;") };
const jmethodID method_toNanos { jniGetMethodID(clazz.get(), "toNanos", "()J") };
};
// This is only a helper, trying to use it as member/param will fail
template<class Ratio>
struct DurationPeriod;
using Duration_h = DurationPeriod<std::ratio<3600>>;
using Duration_min = DurationPeriod<std::ratio<60>>;
using Duration_s = DurationPeriod<std::ratio<1>>;
using Duration_ms = DurationPeriod<std::milli>;
using Duration_us = DurationPeriod<std::micro>;
using Duration_ns = DurationPeriod<std::nano>;
template<class Rep, class Period>
struct Duration;
template<class Rep, class Ratio>
struct Duration<Rep, DurationPeriod<Ratio>>
{
using CppType = std::chrono::duration<typename Rep::CppType, Ratio>;
using JniType = jobject;
using Boxed = Duration;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
const auto& data = JniClass<DurationJniInfo>::get();
assert(jniEnv->IsInstanceOf(j, data.clazz.get()));
jlong nanos = jniEnv->CallLongMethod(j, data.method_toNanos);
jniExceptionCheck(jniEnv);
return std::chrono::duration_cast<CppType>(std::chrono::duration<jlong, std::nano>{nanos});
}
static LocalRef<jobject> fromCpp(JNIEnv* jniEnv, CppType c)
{
const auto& data = JniClass<DurationJniInfo>::get();
jlong nanos = std::chrono::duration_cast<std::chrono::duration<jlong, std::nano>>(c).count();
auto j = LocalRef<JniType>{jniEnv->CallStaticObjectMethod(data.clazz.get(), data.method_ofNanos, nanos)};
jniExceptionCheck(jniEnv);
return j;
}
};
struct DurationJniInfo
{
const GlobalRef<jclass> clazz { jniFindClass("java/time/Duration") };
const jmethodID method_ofNanos { jniGetStaticMethodID(clazz.get(), "ofNanos", "(J)Ljava/time/Duration;") };
const jmethodID method_toNanos { jniGetMethodID(clazz.get(), "toNanos", "()J") };
};
// This is only a helper, trying to use it as member/param will fail
template<class Ratio>
struct DurationPeriod;
using Duration_h = DurationPeriod<std::ratio<3600>>;
using Duration_min = DurationPeriod<std::ratio<60>>;
using Duration_s = DurationPeriod<std::ratio<1>>;
using Duration_ms = DurationPeriod<std::milli>;
using Duration_us = DurationPeriod<std::micro>;
using Duration_ns = DurationPeriod<std::nano>;
template<class Rep, class Period>
struct Duration;
template<class Rep, class Ratio>
struct Duration<Rep, DurationPeriod<Ratio>>
{
using CppType = std::chrono::duration<typename Rep::CppType, Ratio>;
using JniType = jobject;
using Boxed = Duration;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
const auto& data = JniClass<DurationJniInfo>::get();
assert(jniEnv->IsInstanceOf(j, data.clazz.get()));
jlong nanos = jniEnv->CallLongMethod(j, data.method_toNanos);
jniExceptionCheck(jniEnv);
return std::chrono::duration_cast<CppType>(std::chrono::duration<jlong, std::nano>{nanos});
}
static LocalRef<jobject> fromCpp(JNIEnv* jniEnv, CppType c)
{
const auto& data = JniClass<DurationJniInfo>::get();
jlong nanos = std::chrono::duration_cast<std::chrono::duration<jlong, std::nano>>(c).count();
auto j = LocalRef<JniType>{jniEnv->CallStaticObjectMethod(data.clazz.get(), data.method_ofNanos, nanos)};
jniExceptionCheck(jniEnv);
return j;
}
};
}
......@@ -5,47 +5,47 @@
namespace djinni
{
// This is only a helper, trying to use it as member/param will fail
template<class Ratio>
struct DurationPeriod;
using Duration_h = DurationPeriod<std::ratio<3600>>;
using Duration_min = DurationPeriod<std::ratio<60>>;
using Duration_s = DurationPeriod<std::ratio<1>>;
using Duration_ms = DurationPeriod<std::milli>;
using Duration_us = DurationPeriod<std::micro>;
using Duration_ns = DurationPeriod<std::nano>;
template<class Rep, class Period>
struct Duration;
// This is only a helper, trying to use it as member/param will fail
template<class Ratio>
struct DurationPeriod;
template<class Rep, class Ratio>
struct Duration<Rep, DurationPeriod<Ratio>>
{
using CppType = std::chrono::duration<typename Rep::CppType, Ratio>;
using ObjcType = NSTimeInterval;
static CppType toCpp(ObjcType dt)
{
return std::chrono::duration_cast<CppType>(std::chrono::duration<double>{dt});
}
static ObjcType fromCpp(CppType dt)
{
return std::chrono::duration_cast<std::chrono::duration<double>>(dt).count();
}
struct Boxed
{
using ObjcType = NSNumber*;
static CppType toCpp(ObjcType dt)
{
assert(dt);
return std::chrono::duration_cast<CppType>(Duration::toCpp([dt doubleValue]));
}
static ObjcType fromCpp(CppType dt)
{
return [NSNumber numberWithDouble:Duration::fromCpp(dt)];
}
};
};
using Duration_h = DurationPeriod<std::ratio<3600>>;
using Duration_min = DurationPeriod<std::ratio<60>>;
using Duration_s = DurationPeriod<std::ratio<1>>;
using Duration_ms = DurationPeriod<std::milli>;
using Duration_us = DurationPeriod<std::micro>;
using Duration_ns = DurationPeriod<std::nano>;
template<class Rep, class Period>
struct Duration;
template<class Rep, class Ratio>
struct Duration<Rep, DurationPeriod<Ratio>>
{
using CppType = std::chrono::duration<typename Rep::CppType, Ratio>;
using ObjcType = NSTimeInterval;
static CppType toCpp(ObjcType dt)
{
return std::chrono::duration_cast<CppType>(std::chrono::duration<double>{dt});
}
static ObjcType fromCpp(CppType dt)
{
return std::chrono::duration_cast<std::chrono::duration<double>>(dt).count();
}
struct Boxed
{
using ObjcType = NSNumber*;
static CppType toCpp(ObjcType dt)
{
assert(dt);
return std::chrono::duration_cast<CppType>(Duration::toCpp([dt doubleValue]));
}
static ObjcType fromCpp(CppType dt)
{
return [NSNumber numberWithDouble:Duration::fromCpp(dt)];
}
};
};
}
......@@ -4,104 +4,104 @@ namespace testsuite {
std::string TestDuration::hoursString(std::chrono::duration<int32_t, std::ratio<3600>> dt)
{
return std::to_string(dt.count());
return std::to_string(dt.count());
}
std::string TestDuration::minutesString(std::chrono::duration<int32_t, std::ratio<60>> dt)
{
return std::to_string(dt.count());
return std::to_string(dt.count());
}
std::string TestDuration::secondsString(std::chrono::duration<int32_t, std::ratio<1>> dt)
{
return std::to_string(dt.count());
return std::to_string(dt.count());
}
std::string TestDuration::millisString(std::chrono::duration<int32_t, std::milli> dt)
{
return std::to_string(dt.count());
return std::to_string(dt.count());
}
std::string TestDuration::microsString(std::chrono::duration<int32_t, std::micro> dt)
{
return std::to_string(dt.count());
return std::to_string(dt.count());
}
std::string TestDuration::nanosString(std::chrono::duration<int32_t, std::nano> dt)
{
return std::to_string(dt.count());
return std::to_string(dt.count());
}
std::chrono::duration<int32_t, std::ratio<3600>> TestDuration::hours(int32_t count)
{
return std::chrono::duration<int32_t, std::ratio<3600>>{count};
return std::chrono::duration<int32_t, std::ratio<3600>>{count};
}
std::chrono::duration<int32_t, std::ratio<60>> TestDuration::minutes(int32_t count)
{
return std::chrono::duration<int32_t, std::ratio<60>>{count};
return std::chrono::duration<int32_t, std::ratio<60>>{count};
}
std::chrono::duration<int32_t, std::ratio<1>> TestDuration::seconds(int32_t count)
{
return std::chrono::duration<int32_t, std::ratio<1>>{count};
return std::chrono::duration<int32_t, std::ratio<1>>{count};
}
std::chrono::duration<int32_t, std::milli> TestDuration::millis(int32_t count)
{
return std::chrono::duration<int32_t, std::milli>{count};
return std::chrono::duration<int32_t, std::milli>{count};
}
std::chrono::duration<int32_t, std::micro> TestDuration::micros(int32_t count)
{
return std::chrono::duration<int32_t, std::micro>{count};
return std::chrono::duration<int32_t, std::micro>{count};
}
std::chrono::duration<int32_t, std::nano> TestDuration::nanos(int32_t count)
{
return std::chrono::duration<int32_t, std::nano>{count};
return std::chrono::duration<int32_t, std::nano>{count};
}
std::chrono::duration<double, std::ratio<3600>> TestDuration::hoursf(double count)
{
return std::chrono::duration<double, std::ratio<3600>>{count};
return std::chrono::duration<double, std::ratio<3600>>{count};
}
std::chrono::duration<double, std::ratio<60>> TestDuration::minutesf(double count)
{
return std::chrono::duration<double, std::ratio<60>>{count};
return std::chrono::duration<double, std::ratio<60>>{count};
}
std::chrono::duration<double, std::ratio<1>> TestDuration::secondsf(double count)
{
return std::chrono::duration<double, std::ratio<1>>{count};
return std::chrono::duration<double, std::ratio<1>>{count};
}
std::chrono::duration<double, std::milli> TestDuration::millisf(double count)
{
return std::chrono::duration<double, std::milli>{count};
return std::chrono::duration<double, std::milli>{count};
}
std::chrono::duration<double, std::micro> TestDuration::microsf(double count)
{
return std::chrono::duration<double, std::micro>{count};
return std::chrono::duration<double, std::micro>{count};
}
std::chrono::duration<double, std::nano> TestDuration::nanosf(double count)
{
return std::chrono::duration<double, std::nano>{count};
return std::chrono::duration<double, std::nano>{count};
}
std::experimental::optional<std::chrono::duration<int64_t, std::ratio<1>>> TestDuration::box(int64_t count)
{
using D = std::chrono::duration<int64_t, std::ratio<1>>;
using O = std::experimental::optional<D>;
return count < 0 ? O{} : O{D{count}};
using D = std::chrono::duration<int64_t, std::ratio<1>>;
using O = std::experimental::optional<D>;
return count < 0 ? O{} : O{D{count}};
}
int64_t TestDuration::unbox(std::experimental::optional<std::chrono::duration<int64_t, std::ratio<1>>> dt)
{
return dt ? dt->count() : -1;
return dt ? dt->count() : -1;
}
} // namespace testsuite
......@@ -11,7 +11,7 @@ SetRecord TestHelpers::get_set_record() {
"StringA",
"StringB",
"StringC"
}, std::unordered_set<int32_t>{} };
}, std::unordered_set<int32_t>{} };
}
bool TestHelpers::check_set_record(const SetRecord & rec) {
......
......@@ -24,8 +24,8 @@ public class AllTests extends TestSuite {
return mySuite;
}
public static void main(String[] args) throws Exception {
public static void main(String[] args) throws Exception {
NativeLibLoader.loadLibs();
JUnitCore.main("com.dropbox.djinni.test.AllTests");
JUnitCore.main("com.dropbox.djinni.test.AllTests");
}
}
......@@ -8,11 +8,11 @@ public class ClientInterfaceImpl extends ClientInterface {
}
return new ClientReturnedRecord(id, utf8string, misc);
}
@Override
public double identifierCheck(byte[] data, int r, long jret)
{
return 0.0;
}
@Override
public double identifierCheck(byte[] data, int r, long jret)
{
return 0.0;
}
@Override
public String returnStr() {
return "test";
......
......@@ -7,31 +7,31 @@ import java.time.Duration;
public class DurationTest extends TestCase {
public void test() {
assertEquals(TestDuration.hoursString(Duration.ofHours(1)), "1");
assertEquals(TestDuration.minutesString(Duration.ofMinutes(1)), "1");
assertEquals(TestDuration.secondsString(Duration.ofSeconds(1)), "1");
assertEquals(TestDuration.millisString(Duration.ofMillis(1)), "1");
assertEquals(TestDuration.microsString(Duration.ofNanos(1000)), "1");
assertEquals(TestDuration.nanosString(Duration.ofNanos(1)), "1");
assertEquals(TestDuration.hours(1).toHours(), 1);
assertEquals(TestDuration.minutes(1).toMinutes(), 1);
assertEquals(TestDuration.seconds(1).getSeconds(), 1);
assertEquals(TestDuration.millis(1).toMillis(), 1);
assertEquals(TestDuration.micros(1).toNanos(), 1000);
assertEquals(TestDuration.nanos(1).toNanos(), 1);
assertEquals(TestDuration.hoursf(1.5).toMinutes(), 90);
assertEquals(TestDuration.minutesf(1.5).getSeconds(), 90);
assertEquals(TestDuration.secondsf(1.5).toMillis(), 1500);
assertEquals(TestDuration.millisf(1.5).toNanos(), 1500 * 1000);
assertEquals(TestDuration.microsf(1.5).toNanos(), 1500);
assertEquals(TestDuration.nanosf(1.0).toNanos(), 1);
assertEquals(TestDuration.box(1).getSeconds(), 1);
assertEquals(TestDuration.box(-1), null);
assertEquals(TestDuration.unbox(Duration.ofSeconds(1)), 1);
assertEquals(TestDuration.unbox(null), -1);
}
assertEquals(TestDuration.hoursString(Duration.ofHours(1)), "1");
assertEquals(TestDuration.minutesString(Duration.ofMinutes(1)), "1");
assertEquals(TestDuration.secondsString(Duration.ofSeconds(1)), "1");
assertEquals(TestDuration.millisString(Duration.ofMillis(1)), "1");
assertEquals(TestDuration.microsString(Duration.ofNanos(1000)), "1");
assertEquals(TestDuration.nanosString(Duration.ofNanos(1)), "1");
assertEquals(TestDuration.hours(1).toHours(), 1);
assertEquals(TestDuration.minutes(1).toMinutes(), 1);
assertEquals(TestDuration.seconds(1).getSeconds(), 1);
assertEquals(TestDuration.millis(1).toMillis(), 1);
assertEquals(TestDuration.micros(1).toNanos(), 1000);
assertEquals(TestDuration.nanos(1).toNanos(), 1);
assertEquals(TestDuration.hoursf(1.5).toMinutes(), 90);
assertEquals(TestDuration.minutesf(1.5).getSeconds(), 90);
assertEquals(TestDuration.secondsf(1.5).toMillis(), 1500);
assertEquals(TestDuration.millisf(1.5).toNanos(), 1500 * 1000);
assertEquals(TestDuration.microsf(1.5).toNanos(), 1500);
assertEquals(TestDuration.nanosf(1.0).toNanos(), 1);
assertEquals(TestDuration.box(1).getSeconds(), 1);
assertEquals(TestDuration.box(-1), null);
assertEquals(TestDuration.unbox(Duration.ofSeconds(1)), 1);
assertEquals(TestDuration.unbox(null), -1);
}
}
......@@ -17,7 +17,7 @@ public class SetRecordTest extends TestCase {
public void testJavaSetToCppSet() {
HashSet<String> jSet = new HashSet<String>();
HashSet<Integer> iSet = new HashSet<Integer>();
HashSet<Integer> iSet = new HashSet<Integer>();
jSet.add("StringA");
jSet.add("StringB");
jSet.add("StringC");
......
......@@ -14,10 +14,10 @@ static NSString *DBNonAscii = @"Non-ASCII / 非 ASCII 字符";
- (double)identifierCheck:(nonnull NSData *)data r:(int32_t)r jret:(int64_t)jret
{
(void)data;
(void)r;
(void)jret;
return 0.0;
(void)data;
(void)r;
(void)jret;
return 0.0;
}
- (NSString *)returnStr
......
......@@ -37,14 +37,14 @@ using namespace testsuite;
- (void)testObjcRoundTrip
{
NSDate *now = [NSDate date];
DBDateRecord *date1 = [[DBDateRecord alloc] initWithCreatedAt:now];
const auto cpp_date1 = djinni_generated::DateRecord::toCpp(date1);
DBDateRecord *date2 = djinni_generated::DateRecord::fromCpp(cpp_date1);
const auto cpp_date2 = djinni_generated::DateRecord::toCpp(date2);
DBDateRecord *date3 = djinni_generated::DateRecord::fromCpp(cpp_date2);
const auto cpp_date3 = djinni_generated::DateRecord::toCpp(date3);
const bool cpp_is_equal = cpp_date1.created_at == cpp_date2.created_at && cpp_date2.created_at == cpp_date3.created_at;
NSDate *now = [NSDate date];
DBDateRecord *date1 = [[DBDateRecord alloc] initWithCreatedAt:now];
const auto cpp_date1 = djinni_generated::DateRecord::toCpp(date1);
DBDateRecord *date2 = djinni_generated::DateRecord::fromCpp(cpp_date1);
const auto cpp_date2 = djinni_generated::DateRecord::toCpp(date2);
DBDateRecord *date3 = djinni_generated::DateRecord::fromCpp(cpp_date2);
const auto cpp_date3 = djinni_generated::DateRecord::toCpp(date3);
const bool cpp_is_equal = cpp_date1.created_at == cpp_date2.created_at && cpp_date2.created_at == cpp_date3.created_at;
// cpp is a integer representation (with less precision than NSDate), so direct comparison will work
XCTAssertTrue(cpp_is_equal);
......
......@@ -11,42 +11,42 @@
- (void)setUp
{
[super setUp];
[super setUp];
}
- (void)tearDown
{
[super tearDown];
[super tearDown];
}
- (void)test
{
XCTAssertEqual([[DBTestDuration hoursString:3600] compare:@"1"], NSOrderedSame);
XCTAssertEqual([[DBTestDuration minutesString:60] compare:@"1"], NSOrderedSame);
XCTAssertEqual([[DBTestDuration secondsString:1] compare:@"1"], NSOrderedSame);
XCTAssertEqual([[DBTestDuration millisString:0.001] compare:@"1"], NSOrderedSame);
XCTAssertEqual([[DBTestDuration microsString:0.000001] compare:@"1"], NSOrderedSame);
XCTAssertEqual([[DBTestDuration nanosString:0.000000001] compare:@"1"], NSOrderedSame);
XCTAssertEqualWithAccuracy([DBTestDuration hours:1], 3600, 0.001);
XCTAssertEqualWithAccuracy([DBTestDuration minutes:1], 60, 0.001);
XCTAssertEqualWithAccuracy([DBTestDuration seconds:1], 1, 0.001);
XCTAssertEqualWithAccuracy([DBTestDuration millis:1], 0.001, 0.000001);
XCTAssertEqualWithAccuracy([DBTestDuration micros:1], 0.000001, 0.000000001);
XCTAssertEqualWithAccuracy([DBTestDuration nanos:1], 0.000000001, 0.000000000001);
XCTAssertEqualWithAccuracy([DBTestDuration hoursf:1.5], 5400, 0.001);
XCTAssertEqualWithAccuracy([DBTestDuration minutesf:1.5], 90, 0.001);
XCTAssertEqualWithAccuracy([DBTestDuration secondsf:1.5], 1.5, 0.001);
XCTAssertEqualWithAccuracy([DBTestDuration millisf:1.5], 0.0015, 0.000001);
XCTAssertEqualWithAccuracy([DBTestDuration microsf:1.5], 0.0000015, 0.000000001);
XCTAssertEqualWithAccuracy([DBTestDuration nanosf:1.0], 0.000000001, 0.000000000001);
XCTAssertEqual([[DBTestDuration box:1.0] intValue],1);
XCTAssertEqual([DBTestDuration box:-1.0], nil);
XCTAssertEqual([DBTestDuration unbox:[NSNumber numberWithDouble:1.0]], 1);
XCTAssertEqual([DBTestDuration unbox:nil], -1);
XCTAssertEqual([[DBTestDuration hoursString:3600] compare:@"1"], NSOrderedSame);
XCTAssertEqual([[DBTestDuration minutesString:60] compare:@"1"], NSOrderedSame);
XCTAssertEqual([[DBTestDuration secondsString:1] compare:@"1"], NSOrderedSame);
XCTAssertEqual([[DBTestDuration millisString:0.001] compare:@"1"], NSOrderedSame);
XCTAssertEqual([[DBTestDuration microsString:0.000001] compare:@"1"], NSOrderedSame);
XCTAssertEqual([[DBTestDuration nanosString:0.000000001] compare:@"1"], NSOrderedSame);
XCTAssertEqualWithAccuracy([DBTestDuration hours:1], 3600, 0.001);
XCTAssertEqualWithAccuracy([DBTestDuration minutes:1], 60, 0.001);
XCTAssertEqualWithAccuracy([DBTestDuration seconds:1], 1, 0.001);
XCTAssertEqualWithAccuracy([DBTestDuration millis:1], 0.001, 0.000001);
XCTAssertEqualWithAccuracy([DBTestDuration micros:1], 0.000001, 0.000000001);
XCTAssertEqualWithAccuracy([DBTestDuration nanos:1], 0.000000001, 0.000000000001);
XCTAssertEqualWithAccuracy([DBTestDuration hoursf:1.5], 5400, 0.001);
XCTAssertEqualWithAccuracy([DBTestDuration minutesf:1.5], 90, 0.001);
XCTAssertEqualWithAccuracy([DBTestDuration secondsf:1.5], 1.5, 0.001);
XCTAssertEqualWithAccuracy([DBTestDuration millisf:1.5], 0.0015, 0.000001);
XCTAssertEqualWithAccuracy([DBTestDuration microsf:1.5], 0.0000015, 0.000000001);
XCTAssertEqualWithAccuracy([DBTestDuration nanosf:1.0], 0.000000001, 0.000000000001);
XCTAssertEqual([[DBTestDuration box:1.0] intValue],1);
XCTAssertEqual([DBTestDuration box:-1.0], nil);
XCTAssertEqual([DBTestDuration unbox:[NSNumber numberWithDouble:1.0]], 1);
XCTAssertEqual([DBTestDuration unbox:nil], -1);
}
@end
......@@ -26,21 +26,21 @@ using namespace testsuite;
- (void)testCppToObjc
{
MapRecord cppMapRecord([self getCppMap], {});
MapRecord cppMapRecord([self getCppMap], {});
DBMapRecord *objcMapRecord = djinni_generated::MapRecord::fromCpp(cppMapRecord);
[self checkObjcMap:objcMapRecord.map];
}
- (void)testObjcToCpp
{
DBMapRecord *objcMapRecord = [DBMapRecord mapRecordWithMap:[self getObjcMap] imap:[NSDictionary dictionary]];
DBMapRecord *objcMapRecord = [DBMapRecord mapRecordWithMap:[self getObjcMap] imap:[NSDictionary dictionary]];
MapRecord cppMapRecord = djinni_generated::MapRecord::toCpp(objcMapRecord);
[self checkCppMap:cppMapRecord.map];
}
- (void)testCppToObjcEmpty
{
MapRecord cppMapRecord{ {}, {} };
MapRecord cppMapRecord{ {}, {} };
DBMapRecord *objcMapRecord = djinni_generated::MapRecord::fromCpp(cppMapRecord);
XCTAssertEqual([objcMapRecord.map count], (NSUInteger)0, @"Count 0 expected, actual: %lu", (unsigned long)[objcMapRecord.map count]);
......@@ -56,7 +56,7 @@ using namespace testsuite;
- (void)testCppMapListToObjc
{
MapListRecord cppMapListRecord{ { [self getCppMap] } };
MapListRecord cppMapListRecord{ { [self getCppMap] } };
DBMapListRecord *objcMapListRecord = djinni_generated::MapListRecord::fromCpp(cppMapListRecord);
NSArray *objcMapList = objcMapListRecord.mapList;
XCTAssertEqual([objcMapList count], (NSUInteger)1, @"List with 1 map expected, actual no: %lu", (unsigned long)[objcMapList count]);
......
......@@ -25,25 +25,25 @@
- (void)testPrimitives
{
DBAssortedPrimitives * p = [DBAssortedPrimitives assortedPrimitivesWithB:YES
eight:(int8_t)123
sixteen:(int16_t)20000
thirtytwo:(int32_t)1000000000
sixtyfour:(int64_t)1234567890123456789L
fthirtytwo:(float)1.23
fsixtyfour:1.23
oB:[NSNumber numberWithBool:YES]
oEight:[NSNumber numberWithChar:123]
oSixteen:[NSNumber numberWithShort:20000]
oThirtytwo:[NSNumber numberWithInt:1000000000]
oSixtyfour:[NSNumber numberWithLongLong:1234567890123456789L]
oFthirtytwo:[NSNumber numberWithFloat:(float)123]
oFsixtyfour:[NSNumber numberWithDouble:123]];
eight:(int8_t)123
sixteen:(int16_t)20000
thirtytwo:(int32_t)1000000000
sixtyfour:(int64_t)1234567890123456789L
fthirtytwo:(float)1.23
fsixtyfour:1.23
oB:[NSNumber numberWithBool:YES]
oEight:[NSNumber numberWithChar:123]
oSixteen:[NSNumber numberWithShort:20000]
oThirtytwo:[NSNumber numberWithInt:1000000000]
oSixtyfour:[NSNumber numberWithLongLong:1234567890123456789L]
oFthirtytwo:[NSNumber numberWithFloat:(float)123]
oFsixtyfour:[NSNumber numberWithDouble:123]];
XCTAssertEqualObjects(p, [DBTestHelpers assortedPrimitivesId:p]);
}
- (void)testEmptyRecord
{
(void)[DBEmptyRecord emptyRecord];
(void)[DBEmptyRecord emptyRecord];
}
- (void)testObjcToCppConverter
......
......@@ -13,13 +13,13 @@ using namespace testsuite;
- (SetRecord)getCppSetRecord
{
return SetRecord({"StringA", "StringB", "StringC"}, {});
return SetRecord({"StringA", "StringB", "StringC"}, {});
}
- (DBSetRecord *)getObjcSetRecord
{
NSSet *set = [NSSet setWithObjects:@"StringA", @"StringB", @"StringC", nil];
DBSetRecord *objcSetRecord = [DBSetRecord setRecordWithSet:set iset:[NSSet set]];
DBSetRecord *objcSetRecord = [DBSetRecord setRecordWithSet:set iset:[NSSet set]];
return objcSetRecord;
}
......
#! /usr/bin/env bash
# This script formats sources in Djinni with standard whitespace conventions.
# Specifically, tabs are converted to spaces (2 for Scala, 4 for other languages),
# and trailing whitespace is removed.
# This script is idempotent, so can be safely run on existing code without making changes.
set -eu
# Locate the script file. Cross symlinks if necessary.
loc="$0"
while [ -h "$loc" ]; do
ls=`ls -ld "$loc"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
loc="$link" # Absolute link
else
loc="`dirname "$loc"`/$link" # Relative link
fi
done
djinni_dir=$(cd "`dirname "$loc"`" && cd .. && pwd)
# Format source types with 4-space indentation
cd "$djinni_dir" && find . '(' -name '*.[chm]' -or -name '*.[ch]pp' -or -name '*.mm' -or -name '*.java' -or -name '*.py' ')' -and -not -path './deps/*' -exec sh -c 'expand -t 4 "{}" | sed "s/ *$//" | tr -d "\r" > _tmp_ && mv _tmp_ "{}"' \;
# Format source types with 2-space indentatino
cd "$djinni_dir" && find . '(' -name '*.scala' ')' -and -not -path './deps/*' -exec sh -c 'expand -t 2 "{}" | sed "s/ *$//" | tr -d "\r" > _tmp_ && mv _tmp_ "{}"' \;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment