[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/arrayfire/arrayfire-js/master/src/arraywrapper.cpp [Back]  [Original]

/*
Copyright (c) 2014-2015, ArrayFire
Copyright (c) 2015 Gbor Mez aka unbornchikken (gabor.mezo@outlook.com)
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice, this
  list of conditions and the following disclaimer in the documentation and/or
  other materials provided with the distribution.

* Neither the name of the ArrayFire nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "ext.h"
#include "arraywrapper.h"
#include "helpers.h"
#include "guard.h"
#include "worker.h"
#include "errors.h"
#include "symbols.h"

using namespace v8;
using namespace std;
using namespace node;

Nan::Persistent ArrayWrapper::constructor;

int GetMemSize(const af::array* array)
{
    // Make GC aware of device memory.
    // Event it's VRAM this should keep the usage on low (few hundred megabytes),
    // so we won't triggrer out of memory errors.
    return static_cast(sizeof(af::array)) + static_cast(sizeof(ArrayWrapper)) + static_cast(array->bytes());
}

ArrayWrapper::ArrayWrapper(af::array* array) :
    _array(array)
{
    assert(array);
    Nan::AdjustExternalMemory(GetMemSize(array));
}

ArrayWrapper::~ArrayWrapper()
{
    Free();
}

void ArrayWrapper::Free()
{
    if (_array)
    {
        Nan::AdjustExternalMemory(-GetMemSize(_array));
        delete _array;
        _array = nullptr;
    }
}

NAN_MODULE_INIT(ArrayWrapper::Init)
{
    Nan::HandleScope scope;

    auto tmpl = Nan::New(New);
    tmpl->SetClassName(Nan::New("AFArray").ToLocalChecked());

    int noOfMethods = 21;
    tmpl->InstanceTemplate()->SetInternalFieldCount(noOfMethods);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("free").ToLocalChecked(), Nan::New(V8Free), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("elements").ToLocalChecked(), Nan::New(Elements), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("host").ToLocalChecked(), Nan::New(Host), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("copyToHost").ToLocalChecked(), Nan::New(Host), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("scalar").ToLocalChecked(), Nan::New(Scalar), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("value").ToLocalChecked(), Nan::New(Scalar), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("write").ToLocalChecked(), Nan::New(Write), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("type").ToLocalChecked(), Nan::New(Type), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("dims").ToLocalChecked(), Nan::New(Dims), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("numdims").ToLocalChecked(), Nan::New(NumDims), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("numDims").ToLocalChecked(), Nan::New(NumDims), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("bytes").ToLocalChecked(), Nan::New(Bytes), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("copy").ToLocalChecked(), Nan::New(Copy), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isempty").ToLocalChecked(), Nan::New(IsEmpty), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isEmpty").ToLocalChecked(), Nan::New(IsEmpty), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isscalar").ToLocalChecked(), Nan::New(IsScalar), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isScalar").ToLocalChecked(), Nan::New(IsScalar), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isvector").ToLocalChecked(), Nan::New(IsVector), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isVector").ToLocalChecked(), Nan::New(IsVector), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isrow").ToLocalChecked(), Nan::New(IsRow), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isRow").ToLocalChecked(), Nan::New(IsRow), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("iscolumn").ToLocalChecked(), Nan::New(IsColumn), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isColumn").ToLocalChecked(), Nan::New(IsColumn), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("iscomplex").ToLocalChecked(), Nan::New(IsComplex), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isComplex").ToLocalChecked(), Nan::New(IsComplex), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isreal").ToLocalChecked(), Nan::New(IsReal), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isReal").ToLocalChecked(), Nan::New(IsReal), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isdouble").ToLocalChecked(), Nan::New(IsDouble), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isDouble").ToLocalChecked(), Nan::New(IsDouble), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("issingle").ToLocalChecked(), Nan::New(IsSingle), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isSingle").ToLocalChecked(), Nan::New(IsSingle), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isrealfloating").ToLocalChecked(), Nan::New(IsRealFloating), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isRealFloating").ToLocalChecked(), Nan::New(IsRealFloating), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isfloating").ToLocalChecked(), Nan::New(IsFloating), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isFloating").ToLocalChecked(), Nan::New(IsFloating), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isinteger").ToLocalChecked(), Nan::New(IsInteger), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isInteger").ToLocalChecked(), Nan::New(IsInteger), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isbool").ToLocalChecked(), Nan::New(IsBool), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("isBool").ToLocalChecked(), Nan::New(IsBool), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("afEval").ToLocalChecked(), Nan::New(Eval), v8::None);

    Nan::SetPrototypeTemplate(tmpl, Nan::New("at").ToLocalChecked(), Nan::New(At), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("row").ToLocalChecked(), Nan::New(Row), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("col").ToLocalChecked(), Nan::New(Col), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("slice").ToLocalChecked(), Nan::New(Slice), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rows").ToLocalChecked(), Nan::New(Rows), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("cols").ToLocalChecked(), Nan::New(Cols), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("slices").ToLocalChecked(), Nan::New(Slices), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("as").ToLocalChecked(), Nan::New(As), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("assign").ToLocalChecked(), Nan::New(Assign), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("set").ToLocalChecked(), Nan::New(Assign), v8::None);

    Nan::SetPrototypeTemplate(tmpl, Nan::New("add").ToLocalChecked(), Nan::New(Add), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("addAssign").ToLocalChecked(), Nan::New(AddAssign), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("sub").ToLocalChecked(), Nan::New(Sub), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("subAssign").ToLocalChecked(), Nan::New(SubAssign), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("mul").ToLocalChecked(), Nan::New(Mul), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("mulAssign").ToLocalChecked(), Nan::New(MulAssign), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("div").ToLocalChecked(), Nan::New(Div), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("divAssign").ToLocalChecked(), Nan::New(DivAssign), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("bitshiftl").ToLocalChecked(), Nan::New(BitShiftL), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("bitShiftL").ToLocalChecked(), Nan::New(BitShiftL), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("bitshiftr").ToLocalChecked(), Nan::New(BitShiftR), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("bitShiftR").ToLocalChecked(), Nan::New(BitShiftR), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("lt").ToLocalChecked(), Nan::New(Lt), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("gt").ToLocalChecked(), Nan::New(Gt), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("le").ToLocalChecked(), Nan::New(Le), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("ge").ToLocalChecked(), Nan::New(Ge), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("eq").ToLocalChecked(), Nan::New(Eq), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("neq").ToLocalChecked(), Nan::New(Neq), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("and").ToLocalChecked(), Nan::New(And), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("or").ToLocalChecked(), Nan::New(Or), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("bitAnd").ToLocalChecked(), Nan::New(BitAnd), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("bitOr").ToLocalChecked(), Nan::New(BitOr), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("bitXor").ToLocalChecked(), Nan::New(BitXor), v8::None);

    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsAdd").ToLocalChecked(), Nan::New(RhsAdd), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsSub").ToLocalChecked(), Nan::New(RhsSub), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsMul").ToLocalChecked(), Nan::New(RhsMul), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsDiv").ToLocalChecked(), Nan::New(RhsDiv), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsBitshiftl").ToLocalChecked(), Nan::New(RhsBitShiftL), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsBitShiftL").ToLocalChecked(), Nan::New(RhsBitShiftL), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsBitshiftr").ToLocalChecked(), Nan::New(RhsBitShiftR), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsBitShiftR").ToLocalChecked(), Nan::New(RhsBitShiftR), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsLt").ToLocalChecked(), Nan::New(RhsLt), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsGt").ToLocalChecked(), Nan::New(RhsGt), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsLe").ToLocalChecked(), Nan::New(RhsLe), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsGe").ToLocalChecked(), Nan::New(RhsGe), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsEq").ToLocalChecked(), Nan::New(RhsEq), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsNeq").ToLocalChecked(), Nan::New(RhsNeq), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsAnd").ToLocalChecked(), Nan::New(RhsAnd), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsOr").ToLocalChecked(), Nan::New(RhsOr), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsBitAnd").ToLocalChecked(), Nan::New(RhsBitAnd), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsBitOr").ToLocalChecked(), Nan::New(RhsBitOr), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("rhsBitXor").ToLocalChecked(), Nan::New(RhsBitXor), v8::None);

    Nan::SetPrototypeTemplate(tmpl, Nan::New("neg").ToLocalChecked(), Nan::New(Neg), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("not").ToLocalChecked(), Nan::New(Not), v8::None);

    Nan::SetPrototypeTemplate(tmpl, Nan::New("T").ToLocalChecked(), Nan::New(AFT), v8::None);
    Nan::SetPrototypeTemplate(tmpl, Nan::New("S").ToLocalChecked(), Nan::New(AFH), v8::None);

    auto f = tmpl->GetFunction();
    f->Set(Nan::New("create").ToLocalChecked(), Nan::New(Create)->GetFunction());
    constructor.Reset(f);
    Nan::Set(target, Nan::New("AFArray").ToLocalChecked(), f);
}

v8::Local ArrayWrapper::New(const af::array& array)
{
    return New(new af::array(array));
}

v8::Local ArrayWrapper::New(af::array* array)
{
    Nan::EscapableHandleScope scope;
    assert(array);
    Local info[] = { WrapPointer(array) };
    auto c = Nan::New(constructor);
    auto inst = c->NewInstance(1, info);
    assert(ObjectWrap::Unwrap(inst)->_array == array);
    return scope.Escape(inst);
}

void ArrayWrapper::NewAsync(const Nan::FunctionCallbackInfo& info, const std::function& arrayFactory)
{
    if (info.Length() >= 1 && info[info.Length() - 1]->IsFunction())
    {
        auto callback = new Nan::Callback(info[info.Length() - 1].As());
        auto worker = new Worker(callback, arrayFactory, [](Worker* w, af::array* a){ return ArrayWrapper::New(a); });
        Nan::AsyncQueueWorker(worker);
        info.GetReturnValue().SetUndefined();
    }
    else
    {
        NAN_THROW("Last argument have to be a callback!");
    }
}

af::array* ArrayWrapper::GetArray(v8::Local value)
{
    auto array = TryGetArray(value);
    if (array) return array;
    ARRAYFIRE_THROW("Argument is not an AFArray instance or wrapped array has been destroyed by calling its free() method.");
}

af::array* ArrayWrapper::TryGetArray(v8::Local value)
{
    try
    {
        if (value->IsObject())
        {
            auto obj = value.As();
            if (obj->GetConstructorName()->Equals(Nan::New(Symbols::AFArrayClass)))
            {
                auto wrapper = ObjectWrap::Unwrap(value.As());
                return wrapper->_array;
            }
        }
    }
    catch (...)
    {
    }
    return nullptr;
}

af::array* ArrayWrapper::GetArray(v8::Local value)
{
    auto array = TryGetArray(value);
    if (array) return array;
    ARRAYFIRE_THROW("Argument is not an AFArray instance or wrapped array has been destroyed by calling its free() method.");
}

af::array* ArrayWrapper::TryGetArray(v8::Local value)
{
    try
    {
        auto wrapper = ObjectWrap::Unwrap(value.As());
        if (wrapper) return wrapper->_array;
    }
    catch (...)
    {
    }
    return nullptr;
}

af::array* ArrayWrapper::GetArrayAt(const Nan::FunctionCallbackInfo& info, int index)
{
    auto array = TryGetArrayAt(info, index);
    if (array) return array;
    stringstream ss;
    ss IsNumber())
            {
                src = (af_source)(info[buffIdx + 2]->Int32Value());
            }
            auto buffObj = info[buffIdx]->ToObject();
            char* ptr = Buffer::Data(buffObj);
            auto dimAndType = ParseDimAndTypeArgs(info, buffIdx);
            switch (dimAndType.second)
            {
                case f32:
                    factory = [=]() { return CreateArray(ptr, src, dimAndType.first); };
                    break;
                case f64:
                    factory = [=]() { return CreateArray(ptr, src, dimAndType.first); };
                    break;
                case s32:
                    factory = [=]() { return CreateArray(ptr, src, dimAndType.first); };
                    break;
                case u32:
                    factory = [=]() { return CreateArray(ptr, src, dimAndType.first); };
                    break;
                case u8:
                    factory = [=]() { return CreateArray(ptr, src, dimAndType.first ); };
                    break;
                case c32:
                    factory = [=]() { return CreateArray(ptr, src, dimAndType.first); };
                    break;
                case c64:
                    factory = [=]() { return CreateArray(ptr, src, dimAndType.first); };
                    break;
                case b8:
                    factory = [=]() { return CreateArray(ptr, src, dimAndType.first); };
                    break;
                case s64:
                    factory = [=]() { return CreateArray(ptr, src, dimAndType.first); };
                    break;
                case u64:
                    factory = [=]() { return CreateArray(ptr, src, dimAndType.first); };
                    break;
                default:
                    assert(false);
            }
        }

        if (!factory)
        {
            return NAN_THROW_INVALID_ARGS();
        }

        auto conv = [](Worker* w, af::array* a)
        {
            return New(a);
        };
        auto worker = new Worker(GetCallback(info), move(factory), move(conv));
        worker->SaveToPersistent("data", info[buffIdx]->ToObject());

        Nan::AsyncQueueWorker(worker);
        info.GetReturnValue().SetUndefined();
    }
    ARRAYFIRE_CATCH
}

void ArrayWrapper::RegisterInTmp(v8::Local instance)
{
    Local args[] = { instance };
    auto scope = Nan::New(constructor)->Get(Nan::New("scope").ToLocalChecked()).As();
    auto reg = scope->Get(Nan::New("register").ToLocalChecked());
    auto regF = reg.As().As();
    regF->Call(scope, 1, args);
}

NAN_METHOD(ArrayWrapper::Elements)
{
    try
    {
        Guard guard;
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->elements()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::Host)
{
    try
    {
        ARGS_LEN(1)

        char* buffData;
        auto pArray = GetArray(info.This());

        if (Buffer::HasInstance(info[0]))
        {
            buffData = Buffer::Data(info[0]);

            if (Buffer::Length(info[0]) < pArray->bytes())
            {
                return NAN_THROW("Buffer is too small to hold values.");
            }

            af::array array(*pArray);
            auto exec = [=]()
            {
                Guard guard;
                array.host(buffData);
            };
            auto worker = new Worker(GetCallback(info), move(exec));
            worker->SaveToPersistent("data", info[0]->ToObject());

            Nan::AsyncQueueWorker(worker);
            info.GetReturnValue().SetUndefined();
        }
        else
        {
            size_t size = pArray->elements() * GetDTypeInfo(pArray->type()).second;
            buffData = new char[size];
            try
            {
                af::array array(*pArray);
                auto exec = [=]()
                {
                    Guard guard;
                    array.host(buffData);
                    return buffData;
                };
                auto conv = [=](Worker* w, char* data)
                {
                    Nan::EscapableHandleScope scope;
                    return scope.Escape(Nan::NewBuffer(data, size, [](char* data, void* hint) { delete[] data; }, nullptr).ToLocalChecked());
                };
                auto worker = new Worker(GetCallback(info), move(exec), move(conv));
                Nan::AsyncQueueWorker(worker);
                info.GetReturnValue().SetUndefined();
            }
            catch (...)
            {
                delete[] buffData;
                throw;
            }
        }
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::Scalar)
{
    try
    {
        Guard guard;
        auto pArray = GetArray(info.This());
        switch (pArray->type())
        {
            case f32:
                info.GetReturnValue().Set(Nan::New(pArray->scalar()));
                break;
            case f64:
                info.GetReturnValue().Set(Nan::New(pArray->scalar()));
                break;
            case s32:
                info.GetReturnValue().Set(Nan::New(pArray->scalar()));
                break;
            case u32:
                info.GetReturnValue().Set(Nan::New(pArray->scalar()));
                break;
            case u8:
                info.GetReturnValue().Set(Nan::New(pArray->scalar()));
                break;
            case b8:
                info.GetReturnValue().Set(Nan::New(pArray->scalar()));
                break;
            case c32:
                info.GetReturnValue().Set(ToV8Complex(pArray->scalar()));
                break;
            case c64:
                info.GetReturnValue().Set(ToV8Complex(pArray->scalar()));
                break;
            case s64:
                info.GetReturnValue().Set(Nan::New(to_string(pArray->scalar()).c_str()).ToLocalChecked());
                break;
            case u64:
                info.GetReturnValue().Set(Nan::New(to_string(pArray->scalar()).c_str()).ToLocalChecked());
                break;
            default:
                NAN_THROW_INVALID_ARGS();
        }
    }
    ARRAYFIRE_CATCH
}


NAN_METHOD(ArrayWrapper::Write)
{
    try
    {
        ARGS_LEN(3)

        char* buffData;
        auto pArray = GetArray(info.This());

        if (Buffer::HasInstance(info[0]))
        {
            buffData = Buffer::Data(info[0]);
        }
        else
        {
            return NAN_THROW("First argument is no a Buffer.");
        }

        unsigned bytes = info[1]->Uint32Value();
        af_source src = afHost;
        if (info.Length() > 3)
        {
            src = (af_source)(info[2]->Int32Value());
        }

        af::array array(*pArray);
        auto exec = [=]()
        {
            Guard guard;
            af_write_array(array.get(), buffData, bytes, src);
        };
        auto worker = new Worker(GetCallback(info), move(exec));
        worker->SaveToPersistent("data", info[0]->ToObject());

        Nan::AsyncQueueWorker(worker);
        info.GetReturnValue().SetUndefined();
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::Type)
{
    try
    {
        info.GetReturnValue().Set(GetArray(info.This())->type());
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::Dims)
{
    try
    {
        auto pArray = GetArray(info.This());
        if (!info.Length())
        {
            auto dims = pArray->dims();
            auto jsDims = Nan::New();
            jsDims->Set(Nan::New(Symbols::Elements), Nan::New(dims.elements()));
            jsDims->Set(Nan::New(Symbols::Ndims), Nan::New(dims.ndims()));
            jsDims->Set(Nan::New(Symbols::NDims), Nan::New(dims.ndims()));
            auto pDims = Nan::New(4);
            pDims->Set(0, Nan::New(dims[0]));
            pDims->Set(1, Nan::New(dims[1]));
            pDims->Set(2, Nan::New(dims[2]));
            pDims->Set(3, Nan::New(dims[3]));
            jsDims->Set(Nan::New(Symbols::Values), pDims);

            info.GetReturnValue().Set(jsDims);
        }
        else
        {
            info.GetReturnValue().Set(Nan::New(pArray->dims(info[0]->Uint32Value())));
        }
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::NumDims)
{
    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->numdims()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::Bytes)
{
    try
    {
        info.GetReturnValue().Set(Nan::New((unsigned)GetArray(info.This())->bytes()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::Copy)
{
    try
    {
        Guard guard;
        info.GetReturnValue().Set(New(GetArray(info.This())->copy()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::IsEmpty)
{
    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->isempty()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::IsScalar)
{
    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->isscalar()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::IsVector)
{
    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->isvector()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::IsRow)
{
    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->isrow()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::IsColumn)
{
    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->iscolumn()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::IsComplex)
{


    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->iscomplex()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::IsReal)
{


    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->isreal()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::IsDouble)
{


    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->isdouble()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::IsSingle)
{


    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->issingle()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::IsRealFloating)
{


    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->isrealfloating()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::IsFloating)
{


    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->isfloating()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::IsInteger)
{


    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->isinteger()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::IsBool)
{


    try
    {
        info.GetReturnValue().Set(Nan::New(GetArray(info.This())->type() == b8));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::Eval)
{


    try
    {
        Guard guard;
        GetArray(info.This())->eval();
        info.GetReturnValue().SetUndefined();
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::At)
{
    // Aka "indexing"


    try
    {
        ARGS_LEN(1)

        Guard guard;

        if (info.Length() == 1)
        {
            auto ri = ToRegionIndex(info[0]);
            switch (get(ri))
            {
                case Region::Row:
                    info.GetReturnValue().Set(New(GetArray(info.This())->row(get(ri))));
                    break;
                case Region::Rows:
                    info.GetReturnValue().Set(New(GetArray(info.This())->rows(get(ri), get(ri))));
                    break;
                case Region::Col:
                    info.GetReturnValue().Set(New(GetArray(info.This())->col(get(ri))));
                    break;
                case Region::Cols:
                    info.GetReturnValue().Set(New(GetArray(info.This())->cols(get(ri), get(ri))));
                    break;
                case Region::Slice:
                    info.GetReturnValue().Set(New(GetArray(info.This())->slice(get(ri))));
                    break;
                case Region::Slices:
                    info.GetReturnValue().Set(New(GetArray(info.This())->slices(get(ri), get(ri))));
                    break;
                default:
                    info.GetReturnValue().Set(New(GetArray(info.This())->operator()(ToIndex(info[0]))));
                    break;
            }
        }
        else if (info.Length() == 2)
        {
            info.GetReturnValue().Set(New(GetArray(info.This())->operator()(ToIndex(info[0]), ToIndex(info[1]))));
        }
        else if (info.Length() == 3)
        {
            info.GetReturnValue().Set(New(GetArray(info.This())->operator()(ToIndex(info[0]), ToIndex(info[1]), ToIndex(info[2]))));
        }
        else
        {
            info.GetReturnValue().Set(New(GetArray(info.This())->operator()(ToIndex(info[0]), ToIndex(info[1]), ToIndex(info[2]), ToIndex(info[3]))));
        }
    }
    ARRAYFIRE_CATCH
}

#define AFARRAY_IMPL_IDX1(F, f)\
NAN_METHOD(ArrayWrapper::F)\
{\
    \
    try\
    {\
        ARGS_LEN(1)\
        Guard guard;\
        auto pArray = GetArray(info.This());\
        info.GetReturnValue().Set(New(pArray->f(info[0]->Int32Value())));\
    }\
    ARRAYFIRE_CATCH\
}

AFARRAY_IMPL_IDX1(Row, row)
AFARRAY_IMPL_IDX1(Col, col)
AFARRAY_IMPL_IDX1(Slice, slice)
#undef AFARRAY_IMPL_IDX1

#define AFARRAY_IMPL_IDX2(F, f)\
NAN_METHOD(ArrayWrapper::F)\
{\
    \
    try\
    {\
        ARGS_LEN(2);\
        Guard guard;\
        auto pArray = GetArray(info.This());\
        info.GetReturnValue().Set(New(pArray->f(info[0]->Int32Value(), info[1]->Int32Value())));\
    }\
    ARRAYFIRE_CATCH\
}

AFARRAY_IMPL_IDX2(Rows, rows)
AFARRAY_IMPL_IDX2(Cols, cols)
AFARRAY_IMPL_IDX2(Slices, slices)
#undef AFARRAY_IMPL_IDX2

NAN_METHOD(ArrayWrapper::As)
{

    try
    {
        ARGS_LEN(1);
        af::dtype type = GetDTypeInfo(info[0]->Uint32Value()).first;
        Guard guard;
        info.GetReturnValue().Set(New(GetArray(info.This())->as(type)));
    }
    ARRAYFIRE_CATCH
}

#define AFARRAY_IMPL_ASSIGN(F, Op)\
NAN_METHOD(ArrayWrapper::F)\
{\
    \
    \
    try\
    {\
        auto pArray = GetArray(info.This());\
        auto& array = *pArray;\
        bool isDouble = NeedsDouble(array);\
        ARGS_LEN(1)\
        if (info.Length() == 1)\
        {\
            auto value = info[0];\
            auto pOtherArray = TryGetArray(value);\
            Guard guard;\
            if (pOtherArray)\
            {\
                auto& otherArray = *pOtherArray;\
                array Op otherArray;\
            }\
            else if (value->IsNumber())\
            {\
                double v = value->NumberValue();\
                if (floor(v) == v)\
                {\
                    array Op value->Int32Value();\
                }\
                else if (isDouble)\
                {\
                    array Op v;\
                }\
                else\
                {\
                    array Op (float)v;\
                }\
            }\
            else if (value->IsObject())\
            {\
                if (isDouble)\
                {\
                    auto v = ToDComplex(value);\
                    array Op v;\
                }\
                else\
                {\
                    auto v = ToFComplex(value);\
                    array Op v;\
                }\
            }\
            else if (value->IsString())\
            {\
                String::Utf8Value str(value);\
                long long v = strtoll(*str, nullptr, 10);\
                array Op v;\
            }\
            else\
            {\
                return NAN_THROW_INVALID_ARGS();\
            }\
        }\
        else if (info.Length() == 2)\
        {\
            auto regIdx = ToRegionIndex(info[0]);\
            auto reg = get(regIdx);\
            auto value = info[1];\
            auto pOtherArray = TryGetArray(value);\
            switch(reg)\
            {\
                case Region::None:\
                    {\
                        auto idx0 = ToIndex(info[0]);\
                        Guard guard;\
                        if (pOtherArray)\
                        {\
                            auto& otherArray = *pOtherArray;\
                            array(idx0) Op otherArray;\
                        }\
                        else if (value->IsNumber())\
                        {\
                            double v = value->NumberValue();\
                            if (floor(v) == v)\
                            {\
                                array(idx0) Op value->Int32Value();\
                            }\
                            else if (isDouble)\
                            {\
                                array(idx0) Op v;\
                            }\
                            else\
                            {\
                                array(idx0) Op (float)v;\
                            }\
                        }\
                        else if (value->IsObject())\
                        {\
                            if (isDouble)\
                            {\
                                auto v = ToDComplex(value);\
                                array(idx0) Op v;\
                            }\
                            else\
                            {\
                                auto v = ToFComplex(value);\
                                array(idx0) Op v;\
                            }\
                        }\
                        else if (value->IsString())\
                        {\
                            String::Utf8Value str(value);\
                            long long v = strtoll(*str, nullptr, 10);\
                            array(idx0) Op v;\
                        }\
                        else\
                        {\
                            return NAN_THROW_INVALID_ARGS();\
                        }\
                    }\
                    break;\
                case Region::Row:\
                    {\
                        Guard guard;\
                        if (pOtherArray)\
                        {\
                            auto& otherArray = *pOtherArray;\
                            array.row(get(regIdx)) Op otherArray;\
                        }\
                        else if (value->IsNumber())\
                        {\
                            double v = value->NumberValue();\
                            if (floor(v) == v)\
                            {\
                                array.row(get(regIdx)) Op value->Int32Value();\
                            }\
                            else if (isDouble)\
                            {\
                                array.row(get(regIdx)) Op v;\
                            }\
                            else\
                            {\
                                array.row(get(regIdx)) Op (float)v;\
                            }\
                        }\
                        else if (value->IsObject())\
                        {\
                            if (isDouble)\
                            {\
                                auto v = ToDComplex(value);\
                                array.row(get(regIdx)) Op v;\
                            }\
                            else\
                            {\
                                auto v = ToFComplex(value);\
                                array.row(get(regIdx)) Op v;\
                            }\
                        }\
                        else if (value->IsString())\
                        {\
                            String::Utf8Value str(value);\
                            long long v = strtoll(*str, nullptr, 10);\
                            array.row(get(regIdx)) Op v;\
                        }\
                        else\
                        {\
                            return NAN_THROW_INVALID_ARGS();\
                        }\
                    }\
                    break;\
                case Region::Rows:\
                    {\
                        Guard guard;\
                        if (pOtherArray)\
                        {\
                            auto& otherArray = *pOtherArray;\
                            array.rows(get(regIdx), get(regIdx)) Op otherArray;\
                        }\
                        else if (value->IsNumber())\
                        {\
                            double v = value->NumberValue();\
                            if (floor(v) == v)\
                            {\
                                array.rows(get(regIdx), get(regIdx)) Op value->Int32Value();\
                            }\
                            else if (isDouble)\
                            {\
                                array.rows(get(regIdx), get(regIdx)) Op v;\
                            }\
                            else\
                            {\
                                array.rows(get(regIdx), get(regIdx)) Op (float)v;\
                            }\
                        }\
                        else if (value->IsObject())\
                        {\
                            if (isDouble)\
                            {\
                                auto v = ToDComplex(value);\
                                array.rows(get(regIdx), get(regIdx)) Op v;\
                            }\
                            else\
                            {\
                                auto v = ToFComplex(value);\
                                array.rows(get(regIdx), get(regIdx)) Op v;\
                            }\
                        }\
                        else if (value->IsString())\
                        {\
                            String::Utf8Value str(value);\
                            long long v = strtoll(*str, nullptr, 10);\
                            array.rows(get(regIdx), get(regIdx)) Op v;\
                        }\
                        else\
                        {\
                            return NAN_THROW_INVALID_ARGS();\
                        }\
                    }\
                    break;\
                case Region::Col:\
                    {\
                        Guard guard;\
                        if (pOtherArray)\
                        {\
                            auto& otherArray = *pOtherArray;\
                            array.col(get(regIdx)) Op otherArray;\
                        }\
                        else if (value->IsNumber())\
                        {\
                            double v = value->NumberValue();\
                            if (floor(v) == v)\
                            {\
                                array.col(get(regIdx)) Op value->Int32Value();\
                            }\
                            else if (isDouble)\
                            {\
                                array.col(get(regIdx)) Op v;\
                            }\
                            else\
                            {\
                                array.col(get(regIdx)) Op (float)v;\
                            }\
                        }\
                        else if (value->IsObject())\
                        {\
                            if (isDouble)\
                            {\
                                auto v = ToDComplex(value);\
                                array.col(get(regIdx)) Op v;\
                            }\
                            else\
                            {\
                                auto v = ToFComplex(value);\
                                array.col(get(regIdx)) Op v;\
                            }\
                        }\
                        else if (value->IsString())\
                        {\
                            String::Utf8Value str(value);\
                            long long v = strtoll(*str, nullptr, 10);\
                            array.col(get(regIdx)) Op v;\
                        }\
                        else\
                        {\
                            return NAN_THROW_INVALID_ARGS();\
                        }\
                    }\
                    break;\
                case Region::Cols:\
                    {\
                        Guard guard;\
                        if (pOtherArray)\
                        {\
                            auto& otherArray = *pOtherArray;\
                            array.cols(get(regIdx), get(regIdx)) Op otherArray;\
                        }\
                        else if (value->IsNumber())\
                        {\
                            double v = value->NumberValue();\
                            if (floor(v) == v)\
                            {\
                                array.cols(get(regIdx), get(regIdx)) Op value->Int32Value();\
                            }\
                            else if (isDouble)\
                            {\
                                array.cols(get(regIdx), get(regIdx)) Op v;\
                            }\
                            else\
                            {\
                                array.cols(get(regIdx), get(regIdx)) Op (float)v;\
                            }\
                        }\
                        else if (value->IsObject())\
                        {\
                            if (isDouble)\
                            {\
                                auto v = ToDComplex(value);\
                                array.cols(get(regIdx), get(regIdx)) Op v;\
                            }\
                            else\
                            {\
                                auto v = ToFComplex(value);\
                                array.cols(get(regIdx), get(regIdx)) Op v;\
                            }\
                        }\
                        else if (value->IsString())\
                        {\
                            String::Utf8Value str(value);\
                            long long v = strtoll(*str, nullptr, 10);\
                            array.cols(get(regIdx), get(regIdx)) Op v;\
                        }\
                        else\
                        {\
                            return NAN_THROW_INVALID_ARGS();\
                        }\
                    }\
                    break;\
                case Region::Slice:\
                    {\
                        Guard guard;\
                        if (pOtherArray)\
                        {\
                            auto& otherArray = *pOtherArray;\
                            array.slice(get(regIdx)) Op otherArray;\
                        }\
                        else if (value->IsNumber())\
                        {\
                            double v = value->NumberValue();\
                            if (floor(v) == v)\
                            {\
                                array.slice(get(regIdx)) Op value->Int32Value();\
                            }\
                            else if (isDouble)\
                            {\
                                array.slice(get(regIdx)) Op v;\
                            }\
                            else\
                            {\
                                array.slice(get(regIdx)) Op (float)v;\
                            }\
                        }\
                        else if (value->IsObject())\
                        {\
                            if (isDouble)\
                            {\
                                auto v = ToDComplex(value);\
                                array.slice(get(regIdx)) Op v;\
                            }\
                            else\
                            {\
                                auto v = ToFComplex(value);\
                                array.slice(get(regIdx)) Op v;\
                            }\
                        }\
                        else if (value->IsString())\
                        {\
                            String::Utf8Value str(value);\
                            long long v = strtoll(*str, nullptr, 10);\
                            array.slice(get(regIdx)) Op v;\
                        }\
                        else\
                        {\
                            return NAN_THROW_INVALID_ARGS();\
                        }\
                    }\
                    break;\
                case Region::Slices:\
                    {\
                        Guard guard;\
                        if (pOtherArray)\
                        {\
                            auto& otherArray = *pOtherArray;\
                            array.slices(get(regIdx), get(regIdx)) Op otherArray;\
                        }\
                        else if (value->IsNumber())\
                        {\
                            double v = value->NumberValue();\
                            if (floor(v) == v)\
                            {\
                                array.slices(get(regIdx), get(regIdx)) Op value->Int32Value();\
                            }\
                            else if (isDouble)\
                            {\
                                array.slices(get(regIdx), get(regIdx)) Op v;\
                            }\
                            else\
                            {\
                                array.slices(get(regIdx), get(regIdx)) Op (float)v;\
                            }\
                        }\
                        else if (value->IsObject())\
                        {\
                            if (isDouble)\
                            {\
                                auto v = ToDComplex(value);\
                                array.slices(get(regIdx), get(regIdx)) Op v;\
                            }\
                            else\
                            {\
                                auto v = ToFComplex(value);\
                                array.slices(get(regIdx), get(regIdx)) Op v;\
                            }\
                        }\
                        else if (value->IsString())\
                        {\
                            String::Utf8Value str(value);\
                            long long v = strtoll(*str, nullptr, 10);\
                            array.slices(get(regIdx), get(regIdx)) Op v;\
                        }\
                        else\
                        {\
                            return NAN_THROW_INVALID_ARGS();\
                        }\
                    }\
                    break;\
            }\
        }\
        else if (info.Length() == 3)\
        {\
            auto idx0 = ToIndex(info[0]);\
            auto idx1 = ToIndex(info[1]);\
            auto value = info[2];\
            auto pOtherArray = TryGetArray(value);\
            Guard guard;\
            if (pOtherArray)\
            {\
                auto& otherArray = *pOtherArray;\
                array(idx0, idx1) Op otherArray;\
            }\
            else if (value->IsNumber())\
            {\
                double v = value->NumberValue();\
                if (floor(v) == v)\
                {\
                    array(idx0, idx1) Op value->Int32Value();\
                }\
                else if (isDouble)\
                {\
                    array(idx0, idx1) Op v;\
                }\
                else\
                {\
                    array(idx0, idx1) Op (float)v;\
                }\
            }\
            else if (value->IsObject())\
            {\
                if (isDouble)\
                {\
                    auto v = ToDComplex(value);\
                    array(idx0, idx1) Op v;\
                }\
                else\
                {\
                    auto v = ToFComplex(value);\
                    array(idx0, idx1) Op v;\
                }\
            }\
            else if (value->IsString())\
            {\
                String::Utf8Value str(value);\
                long long v = strtoll(*str, nullptr, 10);\
                array(idx0, idx1) Op v;\
            }\
            else\
            {\
                return NAN_THROW_INVALID_ARGS();\
            }\
        }\
        else if (info.Length() == 4)\
        {\
            auto idx0 = ToIndex(info[0]);\
            auto idx1 = ToIndex(info[1]);\
            auto idx2 = ToIndex(info[2]);\
            auto value = info[3];\
            auto pOtherArray = TryGetArray(value);\
            Guard guard;\
            if (pOtherArray)\
            {\
                auto& otherArray = *pOtherArray;\
                array(idx0, idx1, idx2) Op otherArray;\
            }\
            else if (value->IsNumber())\
            {\
                double v = value->NumberValue();\
                if (floor(v) == v)\
                {\
                    array(idx0, idx1, idx2) Op value->Int32Value();\
                }\
                else if (isDouble)\
                {\
                    array(idx0, idx1, idx2) Op v;\
                }\
                else\
                {\
                    array(idx0, idx1, idx2) Op (float)v;\
                }\
            }\
            else if (value->IsObject())\
            {\
                if (isDouble)\
                {\
                    auto v = ToDComplex(value);\
                    array(idx0, idx1, idx2) Op v;\
                }\
                else\
                {\
                    auto v = ToFComplex(value);\
                    array(idx0, idx1, idx2) Op v;\
                }\
            }\
            else if (value->IsString())\
            {\
                String::Utf8Value str(value);\
                long long v = strtoll(*str, nullptr, 10);\
                array(idx0, idx1, idx2) Op v;\
            }\
            else\
            {\
                return NAN_THROW_INVALID_ARGS();\
            }\
        }\
        else\
        {\
            auto idx0 = ToIndex(info[0]);\
            auto idx1 = ToIndex(info[1]);\
            auto idx2 = ToIndex(info[2]);\
            auto idx3 = ToIndex(info[3]);\
            auto value = info[4];\
            auto pOtherArray = TryGetArray(value);\
            Guard guard;\
            if (pOtherArray)\
            {\
                auto& otherArray = *pOtherArray;\
                array(idx0, idx1, idx2, idx3) Op otherArray;\
            }\
            else if (value->IsNumber())\
            {\
                double v = value->NumberValue();\
                if (floor(v) == v)\
                {\
                    array(idx0, idx1, idx2, idx3) Op value->Int32Value();\
                }\
                else if (isDouble)\
                {\
                    array(idx0, idx1, idx2, idx3) Op v;\
                }\
                else\
                {\
                    array(idx0, idx1, idx2, idx3) Op (float)v;\
                }\
            }\
            else if (value->IsObject())\
            {\
                if (isDouble)\
                {\
                    auto v = ToDComplex(value);\
                    array(idx0, idx1, idx2, idx3) Op v;\
                }\
                else\
                {\
                    auto v = ToFComplex(value);\
                    array(idx0, idx1, idx2, idx3) Op v;\
                }\
            }\
            else if (value->IsString())\
            {\
                String::Utf8Value str(value);\
                long long v = strtoll(*str, nullptr, 10);\
                array(idx0, idx1, idx2, idx3) Op v;\
            }\
            else\
            {\
                return NAN_THROW_INVALID_ARGS();\
            }\
        }\
        \
        info.GetReturnValue().Set(info.This());\
    }\
    ARRAYFIRE_CATCH\
}

AFARRAY_IMPL_ASSIGN(Assign, =)
AFARRAY_IMPL_ASSIGN(AddAssign, +=)
AFARRAY_IMPL_ASSIGN(SubAssign, -=)
AFARRAY_IMPL_ASSIGN(MulAssign, *=)
AFARRAY_IMPL_ASSIGN(DivAssign, /=)
#undef AFARRAY_IMPL_ASSIGN

#define AFARRAY_IMPL_BINOP(F, Op)\
NAN_METHOD(ArrayWrapper::F)\
{\
    \
    \
    try\
    {\
        auto& array = *GetArray(info.This());\
        bool isDouble = NeedsDouble(array);\
        ARGS_LEN(1)\
        auto value = info[0];\
        auto pOtherArray = TryGetArray(value);\
        af::array* result = nullptr;\
        Guard guard;\
        if (pOtherArray)\
        {\
            auto& otherArray = *pOtherArray;\
            result = new af::array(array Op otherArray);\
        }\
        else if (value->IsNumber())\
        {\
            double v = value->NumberValue();\
            if (floor(v) == v)\
            {\
                result = new af::array(array Op value->Int32Value());\
            }\
            else if (isDouble)\
            {\
                result = new af::array(array Op v);\
            }\
            else\
            {\
                result = new af::array(array Op (float)v);\
            }\
        }\
        else if (value->IsObject())\
        {\
            if (isDouble)\
            {\
                auto v = ToDComplex(value);\
                result = new af::array(array Op v);\
            }\
            else\
            {\
                auto v = ToFComplex(value);\
                result = new af::array(array Op v);\
            }\
        }\
        else if (value->IsString())\
        {\
            String::Utf8Value str(value);\
            intl v = strtoll(*str, nullptr, 10);\
            result = new af::array(array Op v);\
        }\
        else\
        {\
            return NAN_THROW_INVALID_ARGS();\
        }\
        \
        info.GetReturnValue().Set(New(result));\
    }\
    ARRAYFIRE_CATCH\
}

AFARRAY_IMPL_BINOP(Add, +)
AFARRAY_IMPL_BINOP(Sub, -)
AFARRAY_IMPL_BINOP(Mul, *)
AFARRAY_IMPL_BINOP(Div, /)
AFARRAY_IMPL_BINOP(BitShiftL, )

AFARRAY_IMPL_BINOP(Lt, )
AFARRAY_IMPL_BINOP(Le, =)
AFARRAY_IMPL_BINOP(Eq, ==)
AFARRAY_IMPL_BINOP(Neq, !=)
AFARRAY_IMPL_BINOP(And, &&)
AFARRAY_IMPL_BINOP(Or, ||)
AFARRAY_IMPL_BINOP(BitAnd, &)
AFARRAY_IMPL_BINOP(BitOr, |)
AFARRAY_IMPL_BINOP(BitXor, ^)
#undef AFARRAY_IMPL_BINOP

#define AFARRAY_IMPL_BINOP(F, Op)\
NAN_METHOD(ArrayWrapper::F)\
{\
    \
    \
    try\
    {\
        auto& array = *GetArray(info.This());\
        bool isDouble = NeedsDouble(array);\
        ARGS_LEN(1)\
        auto value = info[0];\
        auto pOtherArray = TryGetArray(value);\
        af::array* result = nullptr;\
        Guard guard;\
        if (pOtherArray)\
        {\
            auto& otherArray = *pOtherArray;\
            result = new af::array(otherArray Op array);\
        }\
        else if (value->IsNumber())\
        {\
            double v = value->NumberValue();\
            if (floor(v) == v)\
            {\
                result = new af::array(value->Int32Value() Op array);\
            }\
            else if (isDouble)\
            {\
                result = new af::array(v Op array);\
            }\
            else\
            {\
                result = new af::array((float)v Op array);\
            }\
        }\
        else if (value->IsObject())\
        {\
            if (isDouble)\
            {\
                auto v = ToDComplex(value);\
                result = new af::array(v Op array);\
            }\
            else\
            {\
                auto v = ToFComplex(value);\
                result = new af::array(v Op array);\
            }\
        }\
        else if (value->IsString())\
        {\
            String::Utf8Value str(value);\
            intl v = strtoll(*str, nullptr, 10);\
            result = new af::array(v Op array);\
        }\
        else\
        {\
            return NAN_THROW_INVALID_ARGS();\
        }\
        \
        info.GetReturnValue().Set(New(result));\
    }\
    ARRAYFIRE_CATCH\
}

AFARRAY_IMPL_BINOP(RhsAdd, +)
AFARRAY_IMPL_BINOP(RhsSub, -)
AFARRAY_IMPL_BINOP(RhsMul, *)
AFARRAY_IMPL_BINOP(RhsDiv, /)
AFARRAY_IMPL_BINOP(RhsBitShiftL, )

AFARRAY_IMPL_BINOP(RhsLt, )
AFARRAY_IMPL_BINOP(RhsLe, =)
AFARRAY_IMPL_BINOP(RhsEq, ==)
AFARRAY_IMPL_BINOP(RhsNeq, !=)
AFARRAY_IMPL_BINOP(RhsAnd, &&)
AFARRAY_IMPL_BINOP(RhsOr, ||)
AFARRAY_IMPL_BINOP(RhsBitAnd, &)
AFARRAY_IMPL_BINOP(RhsBitOr, |)
AFARRAY_IMPL_BINOP(RhsBitXor, ^)
#undef AFARRAY_IMPL_BINOP

#define AFARRAY_IMPL_UNOP(F, Op)\
NAN_METHOD(ArrayWrapper::F)\
{\
    \
    \
    try\
    {\
        auto& array = *GetArray(info.This());\
        Guard guard;\
        info.GetReturnValue().Set(New(array.operator Op()));\
    }\
    ARRAYFIRE_CATCH\
}

AFARRAY_IMPL_UNOP(Neg, -)
AFARRAY_IMPL_UNOP(Not, !)
#undef AFARRAY_IMPL_UNOP

NAN_METHOD(ArrayWrapper::AFT)
{
    try
    {
        Guard guard;
        info.GetReturnValue().Set(New(GetArray(info.This())->T()));
    }
    ARRAYFIRE_CATCH
}

NAN_METHOD(ArrayWrapper::AFH)
{
    try
    {
        Guard guard;
        info.GetReturnValue().Set(New(GetArray(info.This())->H()));
    }
    ARRAYFIRE_CATCH
}

Web Proxy Viewer  |  New URL  |  Original Page