Commit 0866d03a authored by Davis King's avatar Davis King

Added cmake scripts and some related tooling that makes it easy to call C++

code from java.
parent 96881874
cmake_minimum_required (VERSION 2.8.12)
project (myproject)
set(java_package_name net.dlib)
set(source_files
)
include(../cmake_utils/use_cpp_11.cmake)
include(../cmake_utils/release_build_by_default)
include_directories(
.
)
# Additional dependencies
#include(../../dlib/cmake)
#set(additional_link_libraries dlib)
# tell swig to put the output files into the local folder.
set(install_target_output_folder .)
include(cmake_swig_jni)
# This file is used to create SWIG based JNI interfaces to C++ code. You use
# it by defining some CMake variables and then include(cmake_swig_jni). You
# would make a CMakeLists.txt file that looks like the following:
#
# cmake_minimum_required (VERSION 2.8.4)
# project (example)
# set(java_package_name "org.mycompany")
# set(source_files
# your_cpp_source.cpp
# more_cpp_source.cpp
# )
#
# ### We might need to link our code to some other C++ library like dlib. You
# ### can do that by setting additional_link_libraries. Here is an example of
# ### linking to dlib:
# include(../../dlib/dlib/cmake)
# set(additional_link_libraries dlib)
#
# ### tell swig to put the output files into the parent folder of your CMakeLists.txt
# ### file when you run make install.
# set(install_target_output_folder ..)
# include(cmake_swig_jni)
################################################################################
################################################################################
# IMPLEMENTATION DETAILS
################################################################################
################################################################################
cmake_minimum_required (VERSION 2.8.4)
# This block of code tries to figure out what the JAVA_HOME environment
# variable should be by looking at the folder that contains the java
# executable.
if (NOT DEFINED ENV{JAVA_HOME})
message(STATUS "JAVA_HOME environment variable not set, trying to guess it...")
find_program(JAVA_EXECUTABLE java)
# Resolve symbolic links, hopefully this will give us a path in the proper
# java home directory.
get_filename_component(JAVA_EXECUTABLE ${JAVA_EXECUTABLE} REALPATH)
# Pick out the parent directories
get_filename_component(JAVA_PATH1 ${JAVA_EXECUTABLE} PATH)
get_filename_component(JAVA_PATH2 ${JAVA_PATH1} PATH)
get_filename_component(JAVA_PATH3 ${JAVA_PATH2} PATH)
# and search them for include/jni.h. If we find that then we probably have
# a good java home candidate.
find_path(AUTO_JAVA_HOME include/jni.h
PATHS
${JAVA_PATH1}
${JAVA_PATH2}
${JAVA_PATH3}
"C:/Program Files/Java/jdk*"
"C:/Program Files (x86)/Java/jdk*"
)
if (AUTO_JAVA_HOME)
set(ENV{JAVA_HOME} ${AUTO_JAVA_HOME})
message(STATUS "Using JAVA_HOME OF " ${AUTO_JAVA_HOME})
else()
message(FATAL_ERROR "Couldn't find a folder for JAVA_HOME. You must set the JAVA_HOME environment variable before running CMake.")
endif()
endif()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_BINARY_DIR}/lib")
find_package(SWIG REQUIRED)
find_package(Java REQUIRED)
find_package(JNI REQUIRED)
include(UseSWIG)
macro (add_global_switch def_name )
if (NOT CMAKE_CXX_FLAGS MATCHES "${def_name}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${def_name}"
CACHE STRING "Flags used by the compiler during all C++ builds."
FORCE)
endif ()
if (NOT CMAKE_C_FLAGS MATCHES "${def_name}")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${def_name}"
CACHE STRING "Flags used by the compiler during all C builds."
FORCE)
endif ()
endmacro()
# SWIG doesn't work if optimizations are enabled and strict aliasing is not
# turned off. This is a little wonky but it's how SWIG is.
if (CMAKE_COMPILER_IS_GNUCXX)
add_definitions(-fno-strict-aliasing)
endif()
if (UNIX)
# we need to make sure all the code is compiled with -fPIC. In particular,
# it's important that all the code for the whole project is, not just the
# stuff immediately compiled by us in this cmake file. So we add -fPIC to
# the top level cmake flags variables.
add_global_switch(-fPIC)
endif()
string(REGEX REPLACE "\\." "/" package_path ${java_package_name})
string(REGEX REPLACE "\\..*" "" package_root_name ${java_package_name})
set(CMAKE_SWIG_FLAGS -package ${java_package_name})
set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}/lib/java_src/${package_path})
set(output_library_name ${PROJECT_NAME})
# Create the swig.i interface file that swig will run on. We do it here in
# the cmake script because this lets us automatically include the correct
# output library name into the call to System.loadLibrary().
FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/swig.i
"
// Put the global functions in our api into a java class called global.
%module global
%{
#include \"swig_api.h\"
#include <exception>
%}
// Convert all C++ exceptions into java.lang.Exception
%exception {
try {
$action
} catch(std::exception& e) {
jclass clazz = jenv->FindClass(\"java/lang/Exception\");
jenv->ThrowNew(clazz, e.what());
return $null;
}
}
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary(\"${output_library_name}\");
} catch (UnsatisfiedLinkError e) {
System.err.println(\"Native code library failed to load. \\n\" + e);
System.exit(1);
}
}
%}
%include \"swig_api.h\"
"
)
# There is a bug in CMake's Swig scripts that causes the build to fail if the
# binary folder doesn't contain a folder with the same name as the binary dir.
# So we make a subfolder of the same name to avoid that bug.
get_filename_component(binary_dir_name "${CMAKE_CURRENT_BINARY_DIR}" NAME)
FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${binary_dir_name}")
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/swig.i PROPERTIES CPLUSPLUS ON)
swig_add_module(${output_library_name} java ${CMAKE_CURRENT_BINARY_DIR}/swig.i ${source_files})
include_directories(${JNI_INCLUDE_DIRS})
swig_link_libraries(${output_library_name} ${additional_link_libraries})
# Things to delete when "make clean" is run.
set(clean_files
${CMAKE_CURRENT_BINARY_DIR}/intermediate_files_compiled
${CMAKE_CURRENT_BINARY_DIR}/lib/java_src
)
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${clean_files}")
# Compile the java files into a jar file and stick it in the lib folder.
add_custom_command(TARGET ${output_library_name}
POST_BUILD
COMMAND cmake -E echo "compiling Java files..."
COMMAND cmake -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/intermediate_files_compiled"
COMMAND ${Java_JAVAC_EXECUTABLE} ${CMAKE_SWIG_OUTDIR}/*.java -d "${CMAKE_CURRENT_BINARY_DIR}/intermediate_files_compiled"
COMMAND cmake -E echo "Making jar file..."
COMMAND ${Java_JAR_EXECUTABLE} cvf "${CMAKE_CURRENT_BINARY_DIR}/lib/${PROJECT_NAME}.jar" -C "${CMAKE_CURRENT_BINARY_DIR}/intermediate_files_compiled" ${package_root_name}
)
#if the including cmake script set the install_target_output_folder variable
#then make it so we install the compiled library and jar into that folder
if (install_target_output_folder)
# Determine the path to our CMakeLists.txt file.
# There is either a bug (or break in compatability maybe) between versions
# of cmake that cause the or expression in this regular expression to be
# necessary.
string(REGEX REPLACE "(cmake_swig_jni|CMakeLists.txt)$" "" base_path ${CMAKE_PARENT_LIST_FILE})
# The directory we will write the output files to.
set(install_dir "${base_path}${install_target_output_folder}")
set(CMAKE_INSTALL_PREFIX "${install_dir}")
set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION "${install_dir}")
install(TARGETS ${output_library_name}
DESTINATION "${install_dir}"
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib/${PROJECT_NAME}.jar
DESTINATION "${install_dir}"
)
endif()
# Copy any system libraries to the output folder. This really only matters on
# windows where it's good to have the visual studio runtime show up in the lib
# folder so that you don't forget to include it in your binary distribution.
INCLUDE(InstallRequiredSystemLibraries)
foreach (file_i ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS})
add_custom_command(TARGET ${output_library_name}
POST_BUILD
COMMAND cmake -E copy ${file_i} "${CMAKE_CURRENT_BINARY_DIR}/lib/"
)
endforeach()
// Copyright (C) 2017 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_SWIG_JVECTOR_H_
#define DLIB_SWIG_JVECTOR_H_
/*
This file defines two special classes, jvector and jvector_crit. Both of them have the
interface defined by jvector_base, that is, the interface of a simple array object like
std::vector (except without any ability to be resized). These classes are simple
interfaces to java native arrays. So for example, suppose you had an array of int in
java and you wanted to pass it to C++. You could create a C++ function like this:
void my_function(const jvector<int>& array);
and then within java you could call it with code like this:
int[] array = new int[100];
my_function(array);
and it will work just like you would expect. The jvector<int> will usually result in
the JVM doing a copy in the background. However, you can also declare your function
like this:
void my_function(const jvector_crit<int>& array);
and still call it the same way in java, however, using jvector_crit<int> will usually
not result in any copying, and is therefore very fast. jvector_crit uses the JNI
routine GetPrimitiveArrayCritical() to get a lock on the java memory underlying the
array. So it will probably prevent the garbage collector from running while your
function is executing. The JNI documentation is somewhat vague on the limitations of
GetPrimitiveArrayCritical(), saying only that you shouldn't hold the lock on the array
for "an extended period" or call back into the JVM. Deciding whether or not this
matters in your application is left as an exercise for the reader.
There are two ways you can declare your methods. Taking a const reference or a
non-const reference. E.g.:
void my_function(const jvector<int>& array);
void my_function(jvector<int>& array);
The non-const version allows you to modify the contents of the array and the
modifications will be visible to java, as you would expect.
You can also of course use functions taking many arguments, as is normally the case
with SWIG. Finally, jvector works with the following primitive types:
- int16_t
- int32_t
- int64_t
- char (corresponding to java byte)
- float
- double
*/
// ----------------------------------------------------------------------------------------
template <typename T>
class jvector_base
{
public:
jvector_base() = default;
size_t size() const { return sz; }
T* data() { return pdata; }
const T* data() const { return pdata; }
T* begin() { return pdata; }
T* end() { return pdata+sz; }
const T* begin() const { return pdata; }
const T* end() const { return pdata+sz; }
T& operator[](size_t i) { return pdata[i]; }
const T& operator[](size_t i) const { return pdata[i]; }
protected:
T* pdata = nullptr;
size_t sz = 0;
private:
// this object is non-copyable
jvector_base(const jvector_base&);
jvector_base& operator=(const jvector_base&);
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <typename T> class jvector;
#define JVECTOR_CLASS_SPEC(ctype, type, Type) \
template <> class jvector<ctype> : public jvector_base<ctype> \
{ \
public: \
~jvector() { clear(); } \
void reset(JNIEnv* jenv_, j##type##Array arr, bool mightBeModified_) { \
clear(); \
jenv = jenv_; \
oldArr = arr; \
pdata = (ctype*)jenv->Get##Type##ArrayElements(arr, 0); \
sz = jenv->GetArrayLength(arr); \
mightBeModified = mightBeModified_; \
} \
private: \
void clear() { \
if (pdata) { \
jenv->Release##Type##ArrayElements(oldArr, (j##type*)pdata, mightBeModified?0:JNI_ABORT); \
pdata = nullptr; \
} \
} \
JNIEnv* jenv = nullptr; \
j##type##Array oldArr; \
bool mightBeModified; \
};
JVECTOR_CLASS_SPEC(int16_t,short, Short)
JVECTOR_CLASS_SPEC(int32_t,int, Int)
JVECTOR_CLASS_SPEC(int64_t,long, Long)
JVECTOR_CLASS_SPEC(char,byte, Byte)
JVECTOR_CLASS_SPEC(float,float, Float)
JVECTOR_CLASS_SPEC(double,double, Double)
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <typename T, typename JARR>
class jvector_crit_base
{
public:
jvector_crit_base() = default;
size_t size() const { return sz; }
T* data() { return pdata; }
const T* data() const { return pdata; }
T* begin() { return pdata; }
T* end() { return pdata+sz; }
const T* begin() const { return pdata; }
const T* end() const { return pdata+sz; }
T& operator[](size_t i) { return pdata[i]; }
const T& operator[](size_t i) const { return pdata[i]; }
~jvector_crit_base() { clear(); }
void reset(JNIEnv* jenv_, JARR arr, bool mightBeModified_)
{
clear();
jenv = jenv_;
oldArr = arr;
pdata = (T*)jenv->GetPrimitiveArrayCritical(arr, 0);
sz = jenv->GetArrayLength(arr);
mightBeModified = mightBeModified_;
}
private:
void clear()
{
if (pdata) {
jenv->ReleasePrimitiveArrayCritical(oldArr, pdata, mightBeModified?0:JNI_ABORT);
pdata = nullptr;
}
}
// this object is non-copyable
jvector_crit_base(const jvector_crit_base&);
jvector_crit_base& operator=(const jvector_crit_base&);
T* pdata = nullptr;
size_t sz = 0;
JNIEnv* jenv = nullptr;
JARR oldArr;
bool mightBeModified;
};
template <typename T> class jvector_crit;
template <> class jvector_crit<int16_t> : public jvector_crit_base<int16_t,jshortArray> {};
template <> class jvector_crit<int32_t> : public jvector_crit_base<int32_t,jintArray> {};
template <> class jvector_crit<int64_t> : public jvector_crit_base<int64_t,jlongArray> {};
template <> class jvector_crit<char> : public jvector_crit_base<char,jbyteArray> {};
template <> class jvector_crit<float> : public jvector_crit_base<float,jfloatArray> {};
template <> class jvector_crit<double> : public jvector_crit_base<double,jdoubleArray> {};
// ----------------------------------------------------------------------------------------
// Define SWIG typemaps so SWIG will know what to do with the jvector and jvector_crit
// objects.
#ifdef SWIG
%define tostring(token)
#token
%enddef
%define define_jvector_converion(type, java_type)
// Define array conversions for non-const arrays
%typemap(jtype) (jvector<type>&) "java_type[]"
%typemap(jstype) (jvector<type>&) "java_type[]"
%typemap(jni) (jvector<type>&) tostring(j##java_type##Array)
%typemap(javain) (jvector<type>&) "$javainput"
%typemap(arginit) (jvector<type>&) { $1 = &temp$argnum; }
%typemap(in) (jvector<type>&) (jvector<type> temp) { $1->reset(jenv, $input, true); }
%typemap(jtype) (const jvector<type>&) "java_type[]"
%typemap(jstype) (const jvector<type>&) "java_type[]"
%typemap(jni) (const jvector<type>&) tostring(j##java_type##Array)
%typemap(javain) (const jvector<type>&) "$javainput"
%typemap(arginit) (const jvector<type>&) { $1 = &temp$argnum; }
%typemap(in) (const jvector<type>&) (jvector<type> temp) { $1->reset(jenv, $input, false); }
%enddef
define_jvector_converion(int16_t,short)
define_jvector_converion(int32_t,int)
define_jvector_converion(int64_t,long)
define_jvector_converion(char,byte)
define_jvector_converion(float,float)
define_jvector_converion(double,double)
%define define_jvector_crit_converion(type, java_type)
// Define array conversions for non-const arrays
%typemap(jtype) (jvector_crit<type>&) "java_type[]"
%typemap(jstype) (jvector_crit<type>&) "java_type[]"
%typemap(jni) (jvector_crit<type>&) tostring(j##java_type##Array)
%typemap(javain) (jvector_crit<type>&) "$javainput"
%typemap(arginit) (jvector_crit<type>&) { $1 = &temp$argnum; }
%typemap(in) (jvector_crit<type>&) (jvector_crit<type> temp) { $1->reset(jenv, $input, true); }
%typemap(jtype) (const jvector_crit<type>&) "java_type[]"
%typemap(jstype) (const jvector_crit<type>&) "java_type[]"
%typemap(jni) (const jvector_crit<type>&) tostring(j##java_type##Array)
%typemap(javain) (const jvector_crit<type>&) "$javainput"
%typemap(arginit) (const jvector_crit<type>&) { $1 = &temp$argnum; }
%typemap(in) (const jvector_crit<type>&) (jvector_crit<type> temp) { $1->reset(jenv, $input, false); }
%enddef
define_jvector_crit_converion(int16_t,short)
define_jvector_crit_converion(int32_t,int)
define_jvector_crit_converion(int64_t,long)
define_jvector_crit_converion(char,byte)
define_jvector_crit_converion(float,float)
define_jvector_crit_converion(double,double)
#endif // SWIG
#endif // DLIB_SWIG_JVECTOR_H_
# build the jar and shared library of C++ code needed by the JVM
mkdir build
cd build
cmake ..
cmake --build . --config Release --target install
cd ..
# setup paths so the JVM can find our jar and shared library.
export LD_LIBRARY_PATH=.
export DYLD_LIBRARY_PATH=.
export CLASSPATH=myproject.jar:.
# Now compile and run our java test that calls our C++ code.
javac swig_test.java
java swig_test
#ifndef EXAMPLE_SWIG_ApI_H_
#define EXAMPLE_SWIG_ApI_H_
// This file is essentially a small unit test for the swig cmake scripts and the jvector
// classes. All it does it define a few simple functions for writing to and summing
// arrays. The swig_test.java file then calls these C++ functions and checks if they work
// correctly.
// Let's use the jvector, a tool for efficiently binding java native arrays to C++ function
// arguments. You do this by putting this pair of include statements in your swig_api.h
// file. Then after that you can use the jvector and jvector_crit classes.
#include "jvector.h"
#ifdef SWIG
%include "jvector.h"
#endif
// ----------------------------------------------------------------------------------------
// SWIG can't expose templated functions to java. We declare these here as helper
// functions to make the non-templated routines swig will expose easier to write. You can
// see these java exposed methods below (i.e. sum(), sum_crit(), assign(), and
// assign_crit()).
template <typename T>
T tsum(const jvector_crit<T>& arr)
{
T s = 0;
for (auto& v : arr)
s += v;
return s;
}
template <typename T>
T tsum(const jvector<T>& arr)
{
T s = 0;
for (auto& v : arr)
s += v;
return s;
}
template <typename T>
void tassign(T& arr)
{
for (size_t i = 0; i < arr.size(); ++i)
arr[i] = i;
}
// ----------------------------------------------------------------------------------------
// Now write some functions SWIG will expose to java. SWIG will automatically expose
// pretty much any non-template C++ code to java. So just by defining these functions here
// we expose them to java.
//
// All global C++ functions will appear in java as static member functions of class called
// "global", which is where these sum and assign routines will appear. You can see
// examples of java code that calls them in swig_test.java.
inline int sum_crit(const jvector_crit<int16_t>& arr) { return tsum(arr); }
inline int sum(const jvector<int16_t>& arr) { return tsum(arr); }
inline void assign_crit(jvector_crit<int16_t>& arr) { tassign(arr); }
inline void assign(jvector<int16_t>& arr) { tassign(arr); }
inline int sum_crit(const jvector_crit<int32_t>& arr) { return tsum(arr); }
inline int sum(const jvector<int32_t>& arr) { return tsum(arr); }
inline void assign_crit(jvector_crit<int32_t>& arr) { tassign(arr); }
inline void assign(jvector<int32_t>& arr) { tassign(arr); }
inline int sum_crit(const jvector_crit<int64_t>& arr) { return tsum(arr); }
inline int sum(const jvector<int64_t>& arr) { return tsum(arr); }
inline void assign_crit(jvector_crit<int64_t>& arr) { tassign(arr); }
inline void assign(jvector<int64_t>& arr) { tassign(arr); }
inline int sum_crit(const jvector_crit<char>& arr) { return tsum(arr); }
inline int sum(const jvector<char>& arr) { return tsum(arr); }
inline void assign_crit(jvector_crit<char>& arr) { tassign(arr); }
inline void assign(jvector<char>& arr) { tassign(arr); }
inline double sum_crit(const jvector_crit<double>& arr) { return tsum(arr); }
inline double sum(const jvector<double>& arr) { return tsum(arr); }
inline void assign_crit(jvector_crit<double>& arr) { tassign(arr); }
inline void assign(jvector<double>& arr) { tassign(arr); }
inline float sum_crit(const jvector_crit<float>& arr) { return tsum(arr); }
inline float sum(const jvector<float>& arr) { return tsum(arr); }
inline void assign_crit(jvector_crit<float>& arr) { tassign(arr); }
inline void assign(jvector<float>& arr) { tassign(arr); }
// ----------------------------------------------------------------------------------------
#endif // EXAMPLE_SWIG_ApI_H_
/*
This file tests all the ways of using jvector and jvector_crit.
*/
import net.dlib.*;
public class swig_test
{
public static int sum(long[] arr)
{
int s = 0;
for (int i = 0; i < arr.length; ++i)
s += arr[i];
return s;
}
public static void zero(long[] arr)
{
for (int i = 0; i < arr.length; ++i)
arr[i] = 0;
}
public static int sum(byte[] arr)
{
int s = 0;
for (int i = 0; i < arr.length; ++i)
s += arr[i];
return s;
}
public static void zero(byte[] arr)
{
for (int i = 0; i < arr.length; ++i)
arr[i] = 0;
}
public static int sum(short[] arr)
{
int s = 0;
for (int i = 0; i < arr.length; ++i)
s += arr[i];
return s;
}
public static void zero(short[] arr)
{
for (int i = 0; i < arr.length; ++i)
arr[i] = 0;
}
public static int sum(int[] arr)
{
int s = 0;
for (int i = 0; i < arr.length; ++i)
s += arr[i];
return s;
}
public static void zero(int[] arr)
{
for (int i = 0; i < arr.length; ++i)
arr[i] = 0;
}
public static void assertIs28(int val)
{
if (val != 28)
{
throw new RuntimeException("Test failed " + val);
}
}
public static double sum(double[] arr)
{
double s = 0;
for (int i = 0; i < arr.length; ++i)
s += arr[i];
return s;
}
public static void zero(double[] arr)
{
for (int i = 0; i < arr.length; ++i)
arr[i] = 0;
}
public static void assertIs28(double val)
{
if (val != 28)
{
throw new RuntimeException("Test failed " + val);
}
}
public static float sum(float[] arr)
{
float s = 0;
for (int i = 0; i < arr.length; ++i)
s += arr[i];
return s;
}
public static void zero(float[] arr)
{
for (int i = 0; i < arr.length; ++i)
arr[i] = 0;
}
public static void assertIs28(float val)
{
if (val != 28)
{
throw new RuntimeException("Test failed " + val);
}
}
public static void main(String[] args)
{
{
float[] arr = new float[8];
for (int round = 0; round < 100; ++round)
{
zero(arr); global.assign(arr);
assertIs28(sum(arr));
zero(arr); global.assign_crit(arr);
assertIs28(sum(arr));
}
for (int round = 0; round < 100; ++round)
{
zero(arr); global.assign(arr);
assertIs28(sum(arr));
assertIs28(global.sum(arr));
zero(arr); global.assign_crit(arr);
assertIs28(sum(arr));
assertIs28(global.sum_crit(arr));
}
}
{
double[] arr = new double[8];
for (int round = 0; round < 100; ++round)
{
zero(arr); global.assign(arr);
assertIs28(sum(arr));
zero(arr); global.assign_crit(arr);
assertIs28(sum(arr));
}
for (int round = 0; round < 100; ++round)
{
zero(arr); global.assign(arr);
assertIs28(sum(arr));
assertIs28(global.sum(arr));
zero(arr); global.assign_crit(arr);
assertIs28(sum(arr));
assertIs28(global.sum_crit(arr));
}
}
{
byte[] arr = new byte[8];
for (int round = 0; round < 100; ++round)
{
zero(arr); global.assign(arr);
assertIs28(sum(arr));
zero(arr); global.assign_crit(arr);
assertIs28(sum(arr));
}
for (int round = 0; round < 100; ++round)
{
zero(arr); global.assign(arr);
assertIs28(sum(arr));
assertIs28(global.sum(arr));
zero(arr); global.assign_crit(arr);
assertIs28(sum(arr));
assertIs28(global.sum_crit(arr));
}
}
{
long[] arr = new long[8];
for (int round = 0; round < 100; ++round)
{
zero(arr); global.assign(arr);
assertIs28(sum(arr));
zero(arr); global.assign_crit(arr);
assertIs28(sum(arr));
}
for (int round = 0; round < 100; ++round)
{
zero(arr); global.assign(arr);
assertIs28(sum(arr));
assertIs28(global.sum(arr));
zero(arr); global.assign_crit(arr);
assertIs28(sum(arr));
assertIs28(global.sum_crit(arr));
}
}
{
short[] arr = new short[8];
for (int round = 0; round < 100; ++round)
{
zero(arr); global.assign(arr);
assertIs28(sum(arr));
zero(arr); global.assign_crit(arr);
assertIs28(sum(arr));
}
for (int round = 0; round < 100; ++round)
{
zero(arr); global.assign(arr);
assertIs28(sum(arr));
assertIs28(global.sum(arr));
zero(arr); global.assign_crit(arr);
assertIs28(sum(arr));
assertIs28(global.sum_crit(arr));
}
}
{
int[] arr = new int[8];
for (int round = 0; round < 100; ++round)
{
zero(arr); global.assign(arr);
assertIs28(sum(arr));
zero(arr); global.assign_crit(arr);
assertIs28(sum(arr));
}
for (int round = 0; round < 100; ++round)
{
zero(arr); global.assign(arr);
assertIs28(sum(arr));
assertIs28(global.sum(arr));
zero(arr); global.assign_crit(arr);
assertIs28(sum(arr));
assertIs28(global.sum_crit(arr));
}
}
System.out.println("\n\n ALL TESTS COMPLETED SUCCESSFULLY\n");
}
}
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