extern crate libc;
use self::libc::{c_char, c_int, c_longlong, c_uint, c_void};
use crate::defines::{AfError, Backend, DType};
use crate::dim4::Dim4;
use crate::error::HANDLE_ERROR;
use crate::util::{AfArray, DimT, HasAfEnum, MutAfArray, MutVoidPtr};
use std::ffi::CString;
use std::marker::PhantomData;
#[allow(dead_code)]
extern "C" {
fn af_create_array(
out: MutAfArray,
data: *const c_void,
ndims: c_uint,
dims: *const DimT,
aftype: c_uint,
) -> c_int;
fn af_create_handle(out: MutAfArray, ndims: c_uint, dims: *const DimT, aftype: c_uint)
-> c_int;
fn af_get_elements(out: MutAfArray, arr: AfArray) -> c_int;
fn af_get_type(out: *mut c_uint, arr: AfArray) -> c_int;
fn af_get_dims(
dim0: *mut c_longlong,
dim1: *mut c_longlong,
dim2: *mut c_longlong,
dim3: *mut c_longlong,
arr: AfArray,
) -> c_int;
fn af_get_numdims(result: *mut c_uint, arr: AfArray) -> c_int;
fn af_is_empty(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_scalar(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_row(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_column(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_vector(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_complex(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_real(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_double(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_single(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_realfloating(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_floating(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_integer(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_bool(result: *mut c_int, arr: AfArray) -> c_int;
fn af_get_data_ptr(data: *mut c_void, arr: AfArray) -> c_int;
fn af_eval(arr: AfArray) -> c_int;
fn af_eval_multiple(num: c_int, arrays: *const AfArray) -> c_int;
fn af_set_manual_eval_flag(flag: c_int) -> c_int;
fn af_get_manual_eval_flag(flag: *mut c_int) -> c_int;
fn af_retain_array(out: MutAfArray, arr: AfArray) -> c_int;
fn af_copy_array(out: MutAfArray, arr: AfArray) -> c_int;
fn af_release_array(arr: AfArray) -> c_int;
fn af_print_array(arr: AfArray) -> c_int;
fn af_print_array_gen(exp: *const c_char, arr: AfArray, precision: c_int) -> c_int;
fn af_cast(out: MutAfArray, arr: AfArray, aftype: c_uint) -> c_int;
fn af_get_backend_id(backend: *mut c_uint, input: AfArray) -> c_int;
fn af_get_device_id(device: *mut c_int, input: AfArray) -> c_int;
fn af_create_strided_array(
arr: MutAfArray,
data: *const c_void,
offset: DimT,
ndims: c_uint,
dims: *const DimT,
strides: *const DimT,
aftype: c_uint,
stype: c_uint,
) -> c_int;
fn af_get_strides(
s0: *mut DimT,
s1: *mut DimT,
s2: *mut DimT,
s3: *mut DimT,
arr: AfArray,
) -> c_int;
fn af_get_offset(offset: *mut DimT, arr: AfArray) -> c_int;
fn af_is_linear(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_owner(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_sparse(result: *mut c_int, arr: AfArray) -> c_int;
fn af_lock_array(arr: AfArray) -> c_int;
fn af_unlock_array(arr: AfArray) -> c_int;
fn af_get_device_ptr(ptr: MutVoidPtr, arr: AfArray) -> c_int;
fn af_get_allocated_bytes(result: *mut usize, arr: AfArray) -> c_int;
}
pub struct Array<T: HasAfEnum> {
handle: i64,
_marker: PhantomData<T>,
}
macro_rules! is_func {
($doc_str: expr, $fn_name: ident, $ffi_fn: ident) => (
#[doc=$doc_str]
pub fn $fn_name(&self) -> bool {
unsafe {
let mut ret_val: i32 = 0;
let err_val = $ffi_fn(&mut ret_val as *mut c_int, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
ret_val>0
}
}
)
}
impl<T> Array<T>
where
T: HasAfEnum,
{
#[allow(unused_mut)]
pub fn new(slice: &[T], dims: Dim4) -> Self {
let aftype = T::get_af_dtype();
let mut temp: i64 = 0;
unsafe {
let err_val = af_create_array(
&mut temp as MutAfArray,
slice.as_ptr() as *const c_void,
dims.ndims() as c_uint,
dims.get().as_ptr() as *const c_longlong,
aftype as c_uint,
);
HANDLE_ERROR(AfError::from(err_val));
}
temp.into()
}
#[allow(unused_mut)]
pub fn new_strided(slice: &[T], offset: i64, dims: Dim4, strides: Dim4) -> Self {
let aftype = T::get_af_dtype();
let mut temp: i64 = 0;
unsafe {
let err_val = af_create_strided_array(
&mut temp as MutAfArray,
slice.as_ptr() as *const c_void,
offset as DimT,
dims.ndims() as c_uint,
dims.get().as_ptr() as *const c_longlong,
strides.get().as_ptr() as *const c_longlong,
aftype as c_uint,
1 as c_uint,
);
HANDLE_ERROR(AfError::from(err_val));
}
temp.into()
}
#[allow(unused_mut)]
pub fn new_empty(dims: Dim4) -> Self {
let aftype = T::get_af_dtype();
unsafe {
let mut temp: i64 = 0;
let err_val = af_create_handle(
&mut temp as MutAfArray,
dims.ndims() as c_uint,
dims.get().as_ptr() as *const c_longlong,
aftype as c_uint,
);
HANDLE_ERROR(AfError::from(err_val));
temp.into()
}
}
pub fn get_backend(&self) -> Backend {
unsafe {
let mut ret_val: u32 = 0;
let err_val = af_get_backend_id(&mut ret_val as *mut c_uint, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
match (err_val, ret_val) {
(0, 1) => Backend::CPU,
(0, 2) => Backend::CUDA,
(0, 3) => Backend::OPENCL,
_ => Backend::DEFAULT,
}
}
}
pub fn get_device_id(&self) -> i32 {
unsafe {
let mut ret_val: i32 = 0;
let err_val = af_get_device_id(&mut ret_val as *mut c_int, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
ret_val
}
}
pub fn elements(&self) -> usize {
unsafe {
let mut ret_val: i64 = 0;
let err_val = af_get_elements(&mut ret_val as MutAfArray, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
ret_val as usize
}
}
pub fn get_type(&self) -> DType {
unsafe {
let mut ret_val: u32 = 0;
let err_val = af_get_type(&mut ret_val as *mut c_uint, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
DType::from(ret_val)
}
}
pub fn dims(&self) -> Dim4 {
unsafe {
let mut ret0: i64 = 0;
let mut ret1: i64 = 0;
let mut ret2: i64 = 0;
let mut ret3: i64 = 0;
let err_val = af_get_dims(
&mut ret0 as *mut DimT,
&mut ret1 as *mut DimT,
&mut ret2 as *mut DimT,
&mut ret3 as *mut DimT,
self.handle as AfArray,
);
HANDLE_ERROR(AfError::from(err_val));
Dim4::new(&[ret0 as u64, ret1 as u64, ret2 as u64, ret3 as u64])
}
}
pub fn strides(&self) -> Dim4 {
unsafe {
let mut ret0: i64 = 0;
let mut ret1: i64 = 0;
let mut ret2: i64 = 0;
let mut ret3: i64 = 0;
let err_val = af_get_strides(
&mut ret0 as *mut DimT,
&mut ret1 as *mut DimT,
&mut ret2 as *mut DimT,
&mut ret3 as *mut DimT,
self.handle as AfArray,
);
HANDLE_ERROR(AfError::from(err_val));
Dim4::new(&[ret0 as u64, ret1 as u64, ret2 as u64, ret3 as u64])
}
}
pub fn numdims(&self) -> u32 {
unsafe {
let mut ret_val: u32 = 0;
let err_val = af_get_numdims(&mut ret_val as *mut c_uint, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
ret_val
}
}
pub fn offset(&self) -> i64 {
unsafe {
let mut ret_val: i64 = 0;
let err_val = af_get_offset(&mut ret_val as *mut DimT, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
ret_val
}
}
pub fn get(&self) -> i64 {
self.handle
}
pub fn host<O: HasAfEnum>(&self, data: &mut [O]) {
if data.len() != self.elements() {
HANDLE_ERROR(AfError::ERR_SIZE);
}
unsafe {
let err_val = af_get_data_ptr(data.as_mut_ptr() as *mut c_void, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn eval(&self) {
unsafe {
let err_val = af_eval(self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn copy(&self) -> Self {
unsafe {
let mut temp: i64 = 0;
let err_val = af_copy_array(&mut temp as MutAfArray, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
temp.into()
}
}
is_func!("Check if Array is empty", is_empty, af_is_empty);
is_func!("Check if Array is scalar", is_scalar, af_is_scalar);
is_func!("Check if Array is a row", is_row, af_is_row);
is_func!("Check if Array is a column", is_column, af_is_column);
is_func!("Check if Array is a vector", is_vector, af_is_vector);
is_func!(
"Check if Array is of complex type",
is_complex,
af_is_complex
);
is_func!(
"Check if Array's numerical type is of double precision",
is_double,
af_is_double
);
is_func!(
"Check if Array's numerical type is of single precision",
is_single,
af_is_single
);
is_func!("Check if Array is of real type", is_real, af_is_real);
is_func!(
"Check if Array is of single precision",
is_floating,
af_is_floating
);
is_func!(
"Check if Array is of integral type",
is_integer,
af_is_integer
);
is_func!("Check if Array is of boolean type", is_bool, af_is_bool);
is_func!(
"Check if Array's memory layout is continuous and one dimensional",
is_linear,
af_is_linear
);
is_func!(
"Check if Array's memory is owned by it and not a view of another Array",
is_owner,
af_is_owner
);
pub fn cast<O: HasAfEnum>(&self) -> Array<O> {
let trgt_type = O::get_af_dtype();
let mut temp: i64 = 0;
unsafe {
let err_val = af_cast(
&mut temp as MutAfArray,
self.handle as AfArray,
trgt_type as c_uint,
);
HANDLE_ERROR(AfError::from(err_val));
}
temp.into()
}
pub fn is_sparse(&self) -> bool {
unsafe {
let mut temp: i32 = 0;
let err_val = af_is_sparse(&mut temp as *mut c_int, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
temp > 0
}
}
pub fn lock(&self) {
unsafe {
let err_val = af_lock_array(self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn unlock(&self) {
unsafe {
let err_val = af_unlock_array(self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn device_ptr(&self) -> u64 {
unsafe {
let mut temp: u64 = 0;
let err_val = af_get_device_ptr(&mut temp as MutVoidPtr, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
temp
}
}
pub fn get_allocated_bytes(&self) -> usize {
unsafe {
let mut temp: usize = 0;
let err_val = af_get_allocated_bytes(&mut temp as *mut usize, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
temp
}
}
}
impl<T: HasAfEnum> Into<Array<T>> for i64 {
fn into(self) -> Array<T> {
Array {
handle: self,
_marker: PhantomData,
}
}
}
impl<T> Clone for Array<T>
where
T: HasAfEnum,
{
fn clone(&self) -> Self {
unsafe {
let mut temp: i64 = 0;
let ret_val = af_retain_array(&mut temp as MutAfArray, self.handle as AfArray);
match ret_val {
0 => temp.into(),
_ => panic!("Weak copy of Array failed with error code: {}", ret_val),
}
}
}
}
impl<T> Drop for Array<T>
where
T: HasAfEnum,
{
fn drop(&mut self) {
unsafe {
let ret_val = af_release_array(self.handle);
match ret_val {
0 => (),
_ => panic!("Array<T> drop failed with error code: {}", ret_val),
}
}
}
}
pub fn print<T: HasAfEnum>(input: &Array<T>) {
let emptystring = CString::new("").unwrap();
unsafe {
let err_val = af_print_array_gen(
emptystring.to_bytes_with_nul().as_ptr() as *const c_char,
input.get() as AfArray,
4,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn print_gen<T: HasAfEnum>(msg: String, input: &Array<T>, precision: Option<i32>) {
let emptystring = CString::new(msg.as_bytes()).unwrap();
unsafe {
let err_val = af_print_array_gen(
emptystring.to_bytes_with_nul().as_ptr() as *const c_char,
input.get() as AfArray,
match precision {
Some(p) => p,
None => 4,
} as c_int,
);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn eval_multiple<T: HasAfEnum>(inputs: Vec<&Array<T>>) {
unsafe {
let mut v = Vec::new();
for i in inputs {
v.push(i.get());
}
let err_val = af_eval_multiple(v.len() as c_int, v.as_ptr() as *const AfArray);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn set_manual_eval(flag: bool) {
unsafe {
let err_val = af_set_manual_eval_flag(flag as c_int);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn is_eval_manual() -> bool {
unsafe {
let mut ret_val: i32 = 0;
let err_val = af_get_manual_eval_flag(&mut ret_val as *mut c_int);
HANDLE_ERROR(AfError::from(err_val));
ret_val > 0
}
}