Exception handling¶
CppBind supports exception handling by catching thrown exception objects in C++ and rethrowing them in a target language. The user must specify the list of possible thrown exception classes in throws variable. Let's take a look at the following example demonstrating exception handling:
Note
CppBind uses pybind library to generate Python bindings, which already has own mechanism for exception handling. Pybind translates C++ standard exceptions to their Python analogs using an exception correspondence map. Pybind translates all user-defined exceptions to Python RuntimeError. This also sets some constraints on CppBind, so currently, CppBind doesn't support Python exceptions as it's done for other target languages. The user-defined exceptions list is not relevant for Python, and is ignored. The user still must define the throws variable with a placeholder value. no_throw value works fine in this case. This requirement keeps API annotations style convenient between all target languages.
/**
* __API__
* action: gen_constructor
* throws:
* - std::invalid_argument
*/
ThrowExc(bool do_throw=false) {
if (do_throw) throw std::invalid_argument("inv_arg");
}
/**
* __API__
* action: gen_method
* throws:
* - std::out_of_range
* - cppbind::example::SystemError
*/
static int getByKey(const std::map<int, int>& m, int key) {
return m.at(key);
}
/**
* Throws exception with return value of type string.
* __API__
* action: gen_method
* throws: std::invalid_argument
*/
static std::string throwsWithReturnValueString() {
throw std::invalid_argument("return value error");
}
/**
* Throws exception with return value of cppbind type.
* __API__
* action: gen_method
* throws: std::invalid_argument
*/
static cppbind::example::Task* throwsWithReturnValuePtr() {
throw std::invalid_argument("return value error");
}
throws variable is mandatory for methods, constructors, and functions (also for getters and setters). If a method doesn't throw an exception, the user must set the variable to a special no_throw value. This is done as a requirement so that the user does not forget about the ability of a method to throw an exception. An example of an empty exception list looks like this:
/**
* __API__
* action: gen_method
* throws: no_throw
*/
virtual int errNum() {
return err_num;
}
Note
The order of listed exception classes in the throws variable is important. CppBind preserves user-defined order when catching/rethrowing exceptions.
Note
Swift language doesn't support exception throwing from getter/setter, so the user should set the value of the throws variable to no_throw for getter/setter functions. CppBind will give an error otherwise.
The throws list accepts API annotated standard and user-defined exception classes. On a target language side, CppBind keeps correspondence between those classes. CppBind generates bindings for standard exceptions by providing binding predefined rules for std::exception and its descendant classes. The binding rules for standard exceptions are defined in "std_exc_api.yaml" config file, which looks like this:
CppBind API config for standard exceptions
# Copyright (c) 2022 PicsArt, Inc.
# All rights reserved. Use of this source code is governed by a
# MIT-style license that can be found in the LICENSE file.
- type: "std::exception"
vars:
kotlin.action: gen_class
swift.action: gen_class
python.action:
name: StdException
package_prefix: "{{helpers_package_prefix}}"
package: "{{exception_helpers_package}}"
file: "{{exception_file_name}}"
is_exception: True
include_cxx:
- <stdexcept>
- <new>
- <typeinfo>
- type: "std::exception::what()"
vars:
kotlin.action: gen_method
swift.action: gen_method
python.action:
throws: no_throw
- type: "std::runtime_error"
vars:
kotlin.action: gen_class
swift.action: gen_class
python.action:
name: StdRuntimeError
package_prefix: "{{helpers_package_prefix}}"
package: "{{exception_helpers_package}}"
file: "{{exception_file_name}}"
- type: "std::logic_error"
vars:
kotlin.action: gen_class
swift.action: gen_class
python.action:
name: StdLogicError
package_prefix: "{{helpers_package_prefix}}"
package: "{{exception_helpers_package}}"
file: "{{exception_file_name}}"
- type: "std::bad_alloc"
vars:
kotlin.action: gen_class
swift.action: gen_class
python.action:
name: StdBadAlloc
package_prefix: "{{helpers_package_prefix}}"
package: "{{exception_helpers_package}}"
file: "{{exception_file_name}}"
- type: "std::bad_cast"
vars:
kotlin.action: gen_class
swift.action: gen_class
python.action:
name: StdBadCast
package_prefix: "{{helpers_package_prefix}}"
package: "{{exception_helpers_package}}"
file: "{{exception_file_name}}"
- type: "std::bad_typeid"
vars:
kotlin.action: gen_class
swift.action: gen_class
python.action:
name: StdBadTypeId
package_prefix: "{{helpers_package_prefix}}"
package: "{{exception_helpers_package}}"
file: "{{exception_file_name}}"
- type: "std::overflow_error"
vars:
kotlin.action: gen_class
swift.action: gen_class
python.action:
name: StdOverflowError
package_prefix: "{{helpers_package_prefix}}"
package: "{{exception_helpers_package}}"
file: "{{exception_file_name}}"
- type: "std::range_error"
vars:
kotlin.action: gen_class
swift.action: gen_class
python.action:
name: StdRangeError
package_prefix: "{{helpers_package_prefix}}"
package: "{{exception_helpers_package}}"
file: "{{exception_file_name}}"
- type: "std::underflow_error"
vars:
kotlin.action: gen_class
swift.action: gen_class
python.action:
name: StdUnderflowError
package_prefix: "{{helpers_package_prefix}}"
package: "{{exception_helpers_package}}"
file: "{{exception_file_name}}"
- type: "std::invalid_argument"
vars:
kotlin.action: gen_class
swift.action: gen_class
python.action:
name: StdInvalidArgument
package_prefix: "{{helpers_package_prefix}}"
package: "{{exception_helpers_package}}"
file: "{{exception_file_name}}"
- type: "std::length_error"
vars:
swift.action: gen_class
kotlin.action: gen_class
python.action:
name: StdLengthError
package_prefix: "{{helpers_package_prefix}}"
package: "{{exception_helpers_package}}"
file: "{{exception_file_name}}"
- type: "std::out_of_range"
vars:
swift.action: gen_class
kotlin.action: gen_class
python.action:
name: StdOutOfRange
package_prefix: "{{helpers_package_prefix}}"
package: "{{exception_helpers_package}}"
file: "{{exception_file_name}}"
- type: "std::domain_error"
vars:
swift.action: gen_class
kotlin.action: gen_class
python.action:
name: StdDomainError
package_prefix: "{{helpers_package_prefix}}"
package: "{{exception_helpers_package}}"
file: "{{exception_file_name}}"
Note
Since CppBind generate try/catch blocks in C bindings for catching an exception, it uses C++ std exception classes, and therefore we need to include the header files where std exceptions are defined. Those header files are included via the include_cxx variable (see the example above). Here is the list of required includes:
#include <stdexcept>
#include <new>
#include <typeinfo>
If a user-defined exception is derived from std::exception, it is automatically throwable in a target language. If the user wants a class to be throwable in a target language and not to be derived from std::exception, the is_exception variable for that class must be set to True (default value is False).
Note
User-defined exception classes must have a copy constructor since CppBind copies the exception object before rethrowing it in a target language. CppBind needs a copy object since the original exception object is deleted when its lifetime is ended.
If CppBind catches an exception not from the user-defined list, it
throws an unexpected exception and calls an uncaught exception handler
callback. CppBind defines ExceptionHandler
class in a utility package
(one for each target language) to handle uncaught exceptions. The
default handler aborts program execution immediately, but the user can
set a custom callback, which will be called when an unhandled exception
is detected, to change this behaviour. The mentioned package looks like
following:
/**
* ______ .______ .______ .______ __ .__ __. _______
* / || _ \ | _ \ | _ \ | | | \ | | | \
* | ,----'| |_) | | |_) | | |_) | | | | \| | | .--. |
* | | | ___/ | ___/ | _ < | | | . ` | | | | |
* | `----.| | | | | |_) | | | | |\ | | '--' |
* \______|| _| | _| |______/ |__| |__| \__| |_______/
*
* This file is generated by cppbind on 06/23/2021-14:46.
* Please do not change it manually.
*/
package com.examples.cppbind
import kotlin.system.exitProcess
public class ExceptionHandler {
companion object {
private var uncaughtExceptionHandler = {errMsg: String -> defaultHandler(errMsg)}
fun defaultHandler(errMsg: String) {
println("Uncaught exception is found: ${errMsg}")
exitProcess(1)
}
@JvmStatic
fun handleUncaughtException(errMsg: String) {
uncaughtExceptionHandler(errMsg)
}
fun setUncaughtExceptionHandler(handler: (String) -> Unit) {
uncaughtExceptionHandler = {errMsg: String -> handler(errMsg)}
}
fun unsetUncaughtExceptionHandler() {
uncaughtExceptionHandler = {errMsg: String -> defaultHandler(errMsg)}
}
}
}
/**
* ______ .______ .______ .______ __ .__ __. _______
* / || _ \ | _ \ | _ \ | | | \ | | | \
* | ,----'| |_) | | |_) | | |_) | | | | \| | | .--. |
* | | | ___/ | ___/ | _ < | | | . ` | | | | |
* | `----.| | | | | |_) | | | | |\ | | '--' |
* \______|| _| | _| |______/ |__| |__| \__| |_______/
*
* This file is generated by cppbind on 07/21/2021-07:17.
* Please do not change it manually.
*/
public class ExceptionHandler {
static var uncaughtExceptionHandler = defaultHandler
static func defaultHandler(_ err_msg: String) -> Never {
print("Uncaught exception is found: \(err_msg)")
fatalError("Unexpected Exception")
}
static func handleUncaughtException(_ err_msg : String) -> Never {
uncaughtExceptionHandler(err_msg)
}
public static func setUncaughtExceptionHandler(_ handler: @escaping (String) -> Never) {
uncaughtExceptionHandler = handler
}
public static func unsetUncaughtExceptionHandler() {
uncaughtExceptionHandler = defaultHandler
}
}
CppBind always catches std::exception before catching all (catch(...)) exceptions to have a more informative error message when the exception class is derived from std::exception.
After generating bindings for a target language, we can call methods that can throw an exception and test results with catch blocks:
try {
ThrowExc.getByKey(mapOf(1 to 1), 0)
} catch (e: StdOutOfRange) {
assert(e.what().contains("map::at"))
} catch (e: Exception) {
assert(false)
}
// assert everything is ok for returned pointer value when an exception is raised
try {
ThrowExc.throwsWithReturnValuePtr()
} catch (e: StdInvalidArgument) {
assert(e.what() == "return value error")
} catch (e: Exception) {
assert(false)
}
// assert everything is ok for returned string value when an exception is raised
try {
ThrowExc.throwsWithReturnValueString()
} catch (e: StdInvalidArgument) {
assert(e.what() == "return value error")
} catch (e: Exception) {
assert(false)
}
// checking throwing constructor
try {
ThrowExc(true)
assert(false)
} catch (e: StdInvalidArgument) {
assert(e.what() == "inv_arg")
} catch (e: Exception) {
assert(false)
}
try {
MiscExc.returnInteger(true)
assert(false)
} catch (e: StdOutOfRange) {
assert(e.what() == "error")
} catch (e: Exception) {
assert(false)
}
try {
MiscExc.raiseErrorByType("simple_child")
} catch (e: SimpleChildException) {
assert(e.errNum() == 100)
} catch (e: Exception) {
assert(false)
}
let result = try? ThrowExc.getByKey(m: [1 : 1], key: 0)
assert(result == nil)
do {
let _ = try ThrowExc.getByKey(m: [1 : 1], key: 0)
} catch is StdOutOfRange {
} catch {
assert(false)
}
// assert everything is ok for returned pointer value when an exception is raised
do {
let _ = try ThrowExc.throwsWithReturnValuePtr()
} catch let err as StdInvalidArgument {
assert(err.what() == "return value error")
} catch {
assert(false)
}
// assert everything is ok for returned string value when an exception is raised
do {
let _ = try ThrowExc.throwsWithReturnValueString()
} catch let err as StdInvalidArgument {
assert(err.what() == "return value error")
} catch {
assert(false)
}
// checking throwing constructor
do {
let _ = try ThrowExc(doThrow: true)
} catch let err as StdInvalidArgument {
assert(err.what() == "inv_arg")
} catch {
assert(false)
}
do {
let _ = try MiscExc.returnInteger(doThrow: true)
assert(false)
} catch is StdOutOfRange {
} catch {
assert(false)
}
do {
try MiscExc.raiseErrorByType(errType: "simple_child")
} catch let err as SimpleChildException {
assert(err.errNum() == 100)
} catch {
assert(false)
}
Note
In the last usage example, you can notice that we called the custom
exception class SimpleChildException
method errNum
when an exception
was caught. As the custom exception class and its methods have API
annotations, we have corresponding bindings generated, and thus we can
use class methods.
Binding codes when "throws" exception list is not empty
/**
* ______ .______ .______ .______ __ .__ __. _______
* / || _ \ | _ \ | _ \ | | | \ | | | \
* | ,----'| |_) | | |_) | | |_) | | | | \| | | .--. |
* | | | ___/ | ___/ | _ < | | | . ` | | | | |
* | `----.| | | | | |_) | | | | |\ | | '--' |
* \______|| _| | _| |______/ |__| |__| \__| |_______/
*
* This file is generated by cppbind on 11/10/2022-06:59.
* Please do not change it manually.
*/
package com.examples.exceptions
import com.examples.cppbind.*
import com.examples.cppbind.exceptions.*
import com.examples.simple.task.Task
private val INIT = run {
System.loadLibrary("wrapper_jni");
}
/**
* An example of a global function throwing an exception.
*/
fun throwExc(do_throw: Boolean = false): Unit {
val result = jThrowexc(do_throw)
return result
}
open class ThrowExc
internal constructor(obj: CppBindObject) : AutoCloseable {
companion object {
init {
System.loadLibrary("wrapper_jni")
}
protected fun constructHelper(do_throw: Boolean): Long {
val id = jConstructor(do_throw)
return id
}
@JvmStatic
private external fun jConstructor(do_throw: Boolean, vararg extraObjs: Any?): Long
fun getByKey(m: Map<Int, Int>, key: Int): Int {
val tmpKeyKotlintojdkm = IntArray(m.size)
val tmpValKotlintojdkm = IntArray(m.size)
val kotlintojdkm = Pair<IntArray, IntArray>(tmpKeyKotlintojdkm, tmpValKotlintojdkm)
var indexM = 0
for ((keyM, valueM) in m) {
tmpKeyKotlintojdkm[indexM] = keyM
tmpValKotlintojdkm[indexM] = valueM
++indexM
}
val result = jGetbykey(kotlintojdkm, key, m)
return result
}
@JvmStatic
private external fun jGetbykey(m: Pair<IntArray, IntArray>, key: Int, vararg extraObjs: Any?): Int
/**
* Throws exception with return value of type string.
*/
fun throwsWithReturnValueString(): String {
val result = jThrowswithreturnvaluestring()
return result
}
@JvmStatic
private external fun jThrowswithreturnvaluestring(): String
/**
* Throws exception with return value of cppbind type.
*/
fun throwsWithReturnValuePtr(): Task {
val result = jThrowswithreturnvalueptr()
val jdktokotlinresult = Task(CppBindObject(result, true))
return jdktokotlinresult
}
@JvmStatic
private external fun jThrowswithreturnvalueptr(): Long
/**
* An internal property to keep an information about the underlying C++ object type.
* It is intended to be used by the generated code.
*/
const val cppbindCxxTypeName: String = "cppbind::exceptions::ThrowExc"
}
protected var cppbindObj = obj
private var refs: MutableList<Any> = mutableListOf()
/**
* An internal method to bind the lifetimes of the current and another object.
* It is intended to be used by the generated code.
*/
fun keepCppBindReference(ref: Any) {
refs.add(ref)
}
/**
* An internal getter to get the id of an object.
* It is intended to be used by the generated code.
*/
open val cppbindObjId: Long
get() {
if (cppbindObj.id == 0L) {
throw RuntimeException("Object is not allocated")
}
return cppbindObj.id
}
/**
* An internal property returning underlying C++ object id.
* It is intended to be used by the generated code.
*/
internal val cxxId: Long by lazy {
jGetcxxid(cppbindObj.id)
}
/**
* An internal property returning underlying C++ type name.
* It is intended to be used by the generated code.
*/
internal val cxxTypeName: String by lazy {
jGettypebyid(cppbindObj.id)
}
constructor(do_throw: Boolean = false): this(CppBindObject(constructHelper(do_throw), true)) {
}
var prop: String
get() {
val result = jProp(cppbindObjId)
return result
}
set(value) {
jSetprop(cppbindObjId, value, value)
}
/**
* An example of a getter/setter pair with the different 'throws' lists (for checking Kotlin getter/setter exception handling).
*/
var prop2: String
get() {
val result = jProp2(cppbindObjId)
return result
}
set(value) {
jSetprop2(cppbindObjId, value, value)
}
/**
* CppBind generated hashCode method returning the hash of underlying C++ object id.
*/
override fun hashCode(): Int {
return cxxId.hashCode()
}
/**
* CppBind generated equals method comparing the underlying C++ object ids.
*/
override fun equals(other: Any?): Boolean {
other as ThrowExc
return cxxId == other.cxxId
}
/**
* CppBind generated toString method returning underlying C++ object type and id.
*/
override fun toString(): String {
return "<0x$cxxId: $cxxTypeName>"
}
override fun close() {
if (cppbindObj.owner && cppbindObj.id != 0L) {
jFinalize(cppbindObj.id)
cppbindObj.id = 0L
}
}
/**
* Finalize and deletes the object
*/
protected fun finalize() {
close()
}
///// External wrapper functions ////////////
private external fun jProp(id: Long): String
private external fun jSetprop(id: Long, value: String, valueObj: Any?): Unit
private external fun jProp2(id: Long): String
private external fun jSetprop2(id: Long, value: String, valueObj: Any?): Unit
private external fun jFinalize(id: Long): Unit
private external fun jGetcxxid(id: Long): Long
}
private external fun jThrowexc(do_throw: Boolean, vararg extraObjs: Any?): Unit
private external fun jGettypebyid(id: Long): String
/**
* ______ .______ .______ .______ __ .__ __. _______
* / || _ \ | _ \ | _ \ | | | \ | | | \
* | ,----'| |_) | | |_) | | |_) | | | | \| | | .--. |
* | | | ___/ | ___/ | _ < | | | . ` | | | | |
* | `----.| | | | | |_) | | | | |\ | | '--' |
* \______|| _| | _| |______/ |__| |__| \__| |_______/
*
* This file is generated by cppbind on 08/14/2022-10:58.
* Please do not change it manually.
*/
import CWrapper
import Foundation
/// An example of a global function throwing an exception.
public func throwExc(doThrow: Bool = false) throws -> Void {
var cppbindErr = CppBindCObject()
_func_CppbindExceptions_throwExc(doThrow, &cppbindErr)
if cppbindErr.type != nil {
let errorType = String(cString: cppbindErr.type!)
switch errorType {
case ("std::invalid_argument"):
throw StdInvalidArgument(cppbindErr, true)
case ("std::exception"):
let excObj = StdException(cppbindErr, true)
ExceptionHandler.handleUncaughtException(excObj.what())
default:
cppbindErr.type.deallocate()
ExceptionHandler.handleUncaughtException("Uncaught Exception")
}
}
}
public class ThrowExc {
/// An internal property to keep a reference to the original C++ object.
/// It is intended to be used by the generated code.
public let cself: CppBindCObject
/// An internal property to keep track whether Swift is responsible for deallocating the underlying C++ object or not.
/// It is intended to be used by the generated code.
public let owner: Bool
private var refs: [Any]
/// internal main initializer
internal required init(_ _cself: CppBindCObject, _ _owner: Bool = false) {
self.cself = _cself
self.owner = _owner
self.refs = []
}
deinit {
release_CppbindExceptions_ThrowExc(cself, owner)
}
/// An internal method to bind the lifetimes of the current and another object.
/// It is intended to be used by the generated code.
public func keepCppBindReference(_ object: Any) {
self.refs.append(object)
}
public convenience init(doThrow: Bool = false) throws {
var cppbindErr = CppBindCObject()
self.init(create_CppbindExceptions_ThrowExc(doThrow, &cppbindErr), true)
if cppbindErr.type != nil {
let errorType = String(cString: cppbindErr.type!)
switch errorType {
case ("std::invalid_argument"):
throw StdInvalidArgument(cppbindErr, true)
case ("std::exception"):
let excObj = StdException(cppbindErr, true)
ExceptionHandler.handleUncaughtException(excObj.what())
default:
cppbindErr.type.deallocate()
ExceptionHandler.handleUncaughtException("Uncaught Exception")
}
}
}
/// An example to check swift throwing property getter
public var prop1: String {
get {
var cppbindErr = CppBindCObject()
let result = _prop_get_CppbindExceptions_ThrowExc_prop1(cself, &cppbindErr)
if cppbindErr.type != nil {
let errorType = String(cString: cppbindErr.type!)
switch errorType {
case ("std::exception"):
let excObj = StdException(cppbindErr, true)
ExceptionHandler.handleUncaughtException(excObj.what())
default:
cppbindErr.type.deallocate()
ExceptionHandler.handleUncaughtException("Uncaught Exception")
}
}
let sctoswiftresult = String(cString: result)
defer {
result.deallocate()
}
return sctoswiftresult
}
set(value) {
let swifttoscvalue = strdup(value)!
var cppbindErr = CppBindCObject()
_prop_set_CppbindExceptions_ThrowExc_prop1(cself, swifttoscvalue, &cppbindErr)
if cppbindErr.type != nil {
let errorType = String(cString: cppbindErr.type!)
switch errorType {
case ("std::exception"):
let excObj = StdException(cppbindErr, true)
ExceptionHandler.handleUncaughtException(excObj.what())
default:
cppbindErr.type.deallocate()
ExceptionHandler.handleUncaughtException("Uncaught Exception")
}
}
}
}
public static func getByKey(m: Dictionary<Int, Int>, key: Int) throws -> Int {
let _swifttoscmKey = UnsafeMutablePointer<CInt>.allocate(
capacity: m.count)
let _swifttoscmVal = UnsafeMutablePointer<CInt>.allocate(
capacity: m.count)
var swifttoscm = CppBindCDataMap()
swifttoscm.keys = UnsafeMutableRawPointer(_swifttoscmKey)
swifttoscm.values = UnsafeMutableRawPointer(_swifttoscmVal)
swifttoscm.size = Int64(m.count)
var mIdx = 0
for (mKey, mVal) in m {
let swifttoscmKey = CInt(mKey)
let swifttoscmVal = CInt(mVal)
_swifttoscmKey[mIdx] = swifttoscmKey
_swifttoscmVal[mIdx] = swifttoscmVal
mIdx += 1
}
let swifttosckey = CInt(key)
var cppbindErr = CppBindCObject()
let result = _func_CppbindExceptions_ThrowExc_getByKey(swifttoscm, swifttosckey, &cppbindErr)
swifttoscm.keys.deallocate()
swifttoscm.values.deallocate()
if cppbindErr.type != nil {
let errorType = String(cString: cppbindErr.type!)
switch errorType {
case ("std::out_of_range"):
throw StdOutOfRange(cppbindErr, true)
case ("cppbind::example::SystemError"):
throw SystemError(cppbindErr, true)
case ("std::exception"):
let excObj = StdException(cppbindErr, true)
ExceptionHandler.handleUncaughtException(excObj.what())
default:
cppbindErr.type.deallocate()
ExceptionHandler.handleUncaughtException("Uncaught Exception")
}
}
let sctoswiftresult = Int(result)
return sctoswiftresult
}
/// Throws exception with return value of type string.
public static func throwsWithReturnValueString() throws -> String {
var cppbindErr = CppBindCObject()
let result = _func_CppbindExceptions_ThrowExc_throwsWithReturnValueString(&cppbindErr)
if cppbindErr.type != nil {
let errorType = String(cString: cppbindErr.type!)
switch errorType {
case ("std::invalid_argument"):
throw StdInvalidArgument(cppbindErr, true)
case ("std::exception"):
let excObj = StdException(cppbindErr, true)
ExceptionHandler.handleUncaughtException(excObj.what())
default:
cppbindErr.type.deallocate()
ExceptionHandler.handleUncaughtException("Uncaught Exception")
}
}
let sctoswiftresult = String(cString: result)
defer {
result.deallocate()
}
return sctoswiftresult
}
/// Throws exception with return value of cppbind type.
public static func throwsWithReturnValuePtr() throws -> Task {
var cppbindErr = CppBindCObject()
let result = _func_CppbindExceptions_ThrowExc_throwsWithReturnValuePtr(&cppbindErr)
if cppbindErr.type != nil {
let errorType = String(cString: cppbindErr.type!)
switch errorType {
case ("std::invalid_argument"):
throw StdInvalidArgument(cppbindErr, true)
case ("std::exception"):
let excObj = StdException(cppbindErr, true)
ExceptionHandler.handleUncaughtException(excObj.what())
default:
cppbindErr.type.deallocate()
ExceptionHandler.handleUncaughtException("Uncaught Exception")
}
}
var sctoswiftresult: Task
sctoswiftresult = Task(result, true)
return sctoswiftresult
}
/// An internal property to keep an information about the underlying C++ object type.
/// It is intended to be used by the generated code.
class var cppbindCxxTypeName : String { return "cppbind::exceptions::ThrowExc" }
}
Binding codes when exception list is empty (throws=True)
/**
* ______ .______ .______ .______ __ .__ __. _______
* / || _ \ | _ \ | _ \ | | | \ | | | \
* | ,----'| |_) | | |_) | | |_) | | | | \| | | .--. |
* | | | ___/ | ___/ | _ < | | | . ` | | | | |
* | `----.| | | | | |_) | | | | |\ | | '--' |
* \______|| _| | _| |______/ |__| |__| \__| |_______/
*
* This file is generated by cppbind on 08/18/2022-11:02.
* Please do not change it manually.
*/
package com.examples.exceptions
import com.examples.cppbind.*
import com.examples.cppbind.exceptions.*
open class NoThrowExc
internal constructor(obj: CppBindObject) : AutoCloseable {
companion object {
init {
System.loadLibrary("wrapper_jni")
}
protected fun constructHelper(do_throw: Boolean): Long {
val id = jConstructor(do_throw)
return id
}
@JvmStatic
private external fun jConstructor(do_throw: Boolean, vararg extraObjs: Any?): Long
fun noop(): Unit {
val result = jNoop()
return result
}
@JvmStatic
private external fun jNoop(): Unit
/**
* An internal property to keep an information about the underlying C++ object type.
* It is intended to be used by the generated code.
*/
const val cppbindCxxTypeName: String = "cppbind::exceptions::NoThrowExc"
}
protected var cppbindObj = obj
private var refs: MutableList<Any> = mutableListOf()
/**
* An internal method to bind the lifetimes of the current and another object.
* It is intended to be used by the generated code.
*/
fun keepCppBindReference(ref: Any) {
refs.add(ref)
}
/**
* An internal getter to get the id of an object.
* It is intended to be used by the generated code.
*/
open val cppbindObjId: Long
get() {
if (cppbindObj.id == 0L) {
throw RuntimeException("Object is not allocated")
}
return cppbindObj.id
}
/**
* An internal property returning underlying C++ object id.
* It is intended to be used by the generated code.
*/
internal val cxxId: Long by lazy {
jGetcxxid(cppbindObj.id)
}
/**
* An internal property returning underlying C++ type name.
* It is intended to be used by the generated code.
*/
internal val cxxTypeName: String by lazy {
jGettypebyid(cppbindObj.id)
}
constructor(do_throw: Boolean = false): this(CppBindObject(constructHelper(do_throw), true)) {
}
var prop: String
get() {
val result = jProp(cppbindObjId)
return result
}
set(value) {
jSetprop(cppbindObjId, value, value)
}
/**
* CppBind generated hashCode method returning the hash of underlying C++ object id.
*/
override fun hashCode(): Int {
return cxxId.hashCode()
}
/**
* CppBind generated equals method comparing the underlying C++ object ids.
*/
override fun equals(other: Any?): Boolean {
other as NoThrowExc
return cxxId == other.cxxId
}
/**
* CppBind generated toString method returning underlying C++ object type and id.
*/
override fun toString(): String {
return "<0x$cxxId: $cxxTypeName>"
}
override fun close() {
if (cppbindObj.owner && cppbindObj.id != 0L) {
jFinalize(cppbindObj.id)
cppbindObj.id = 0L
}
}
/**
* Finalize and deletes the object
*/
protected fun finalize() {
close()
}
///// External wrapper functions ////////////
private external fun jProp(id: Long): String
private external fun jSetprop(id: Long, value: String, valueObj: Any?): Unit
private external fun jFinalize(id: Long): Unit
private external fun jGetcxxid(id: Long): Long
}
private external fun jGettypebyid(id: Long): String
Note
For Kotlin we rethrow caught exception from C binding via JNI special functions. It means that exception handling section of code is written in C binding file. Here is an example of C binding file.
/**
* ______ .______ .______ .______ __ .__ __. _______
* / || _ \ | _ \ | _ \ | | | \ | | | \
* | ,----'| |_) | | |_) | | |_) | | | | \| | | .--. |
* | | | ___/ | ___/ | _ < | | | . ` | | | | |
* | `----.| | | | | |_) | | | | |\ | | '--' |
* \______|| _| | _| |______/ |__| |__| \__| |_______/
*
* This file is generated by cppbind on 08/14/2022-10:58.
* Please do not change it manually.
*/
import CWrapper
import Foundation
public class NoThrowExc {
/// An internal property to keep a reference to the original C++ object.
/// It is intended to be used by the generated code.
public let cself: CppBindCObject
/// An internal property to keep track whether Swift is responsible for deallocating the underlying C++ object or not.
/// It is intended to be used by the generated code.
public let owner: Bool
private var refs: [Any]
/// internal main initializer
internal required init(_ _cself: CppBindCObject, _ _owner: Bool = false) {
self.cself = _cself
self.owner = _owner
self.refs = []
}
deinit {
release_CppbindExceptions_NoThrowExc(cself, owner)
}
/// An internal method to bind the lifetimes of the current and another object.
/// It is intended to be used by the generated code.
public func keepCppBindReference(_ object: Any) {
self.refs.append(object)
}
public convenience init(doThrow: Bool = false) {
var cppbindErr = CppBindCObject()
self.init(create_CppbindExceptions_NoThrowExc(doThrow, &cppbindErr), true)
if cppbindErr.type != nil {
let errorType = String(cString: cppbindErr.type!)
switch errorType {
case ("std::exception"):
let excObj = StdException(cppbindErr, true)
ExceptionHandler.handleUncaughtException(excObj.what())
default:
cppbindErr.type.deallocate()
ExceptionHandler.handleUncaughtException("Uncaught Exception")
}
}
}
public var prop: String {
get {
var cppbindErr = CppBindCObject()
let result = _prop_get_CppbindExceptions_NoThrowExc_prop(cself, &cppbindErr)
if cppbindErr.type != nil {
let errorType = String(cString: cppbindErr.type!)
switch errorType {
case ("std::exception"):
let excObj = StdException(cppbindErr, true)
ExceptionHandler.handleUncaughtException(excObj.what())
default:
cppbindErr.type.deallocate()
ExceptionHandler.handleUncaughtException("Uncaught Exception")
}
}
let sctoswiftresult = String(cString: result)
defer {
result.deallocate()
}
return sctoswiftresult
}
set(value) {
let swifttoscvalue = strdup(value)!
var cppbindErr = CppBindCObject()
_prop_set_CppbindExceptions_NoThrowExc_prop(cself, swifttoscvalue, &cppbindErr)
if cppbindErr.type != nil {
let errorType = String(cString: cppbindErr.type!)
switch errorType {
case ("std::exception"):
let excObj = StdException(cppbindErr, true)
ExceptionHandler.handleUncaughtException(excObj.what())
default:
cppbindErr.type.deallocate()
ExceptionHandler.handleUncaughtException("Uncaught Exception")
}
}
}
}
public static func noop() -> Void {
var cppbindErr = CppBindCObject()
_func_CppbindExceptions_NoThrowExc_noop(&cppbindErr)
if cppbindErr.type != nil {
let errorType = String(cString: cppbindErr.type!)
switch errorType {
case ("std::exception"):
let excObj = StdException(cppbindErr, true)
ExceptionHandler.handleUncaughtException(excObj.what())
default:
cppbindErr.type.deallocate()
ExceptionHandler.handleUncaughtException("Uncaught Exception")
}
}
}
/// An internal property to keep an information about the underlying C++ object type.
/// It is intended to be used by the generated code.
class var cppbindCxxTypeName : String { return "cppbind::exceptions::NoThrowExc" }
}