SciRuby/nmatrix

View on GitHub
ext/nmatrix/data/data.cpp

Summary

Maintainability
Test Coverage
/////////////////////////////////////////////////////////////////////
// = NMatrix
//
// A linear algebra library for scientific computation in Ruby.
// NMatrix is part of SciRuby.
//
// NMatrix was originally inspired by and derived from NArray, by
// Masahiro Tanaka: http://narray.rubyforge.org
//
// == Copyright Information
//
// SciRuby is Copyright (c) 2010 - 2014, Ruby Science Foundation
// NMatrix is Copyright (c) 2012 - 2014, John Woods and the Ruby Science Foundation
//
// Please see LICENSE.txt for additional copyright notices.
//
// == Contributing
//
// By contributing source code to SciRuby, you agree to be bound by
// our Contributor Agreement:
//
// * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
//
// == data.cpp
//
// Functions and data for dealing the data types.

/*
 * Standard Includes
 */

#include <ruby.h>
#include <stdexcept>

/*
 * Project Includes
 */

#include "types.h"
#include "data.h"

/*
 * Global Variables
 */

namespace nm {
  const char* const EWOP_OPS[nm::NUM_EWOPS] = {
    "+",
    "-",
    "*",
    "/",
    "**",
    "%",
    "==",
    "!=",
    "<",
    ">",
    "<=",
    ">="
  };

  const std::string EWOP_NAMES[nm::NUM_EWOPS] = {
    "add",
    "sub",
    "mul",
    "div",
    "pow",
    "mod",
    "eqeq",
    "neq",
    "lt",
    "gt",
    "leq",
    "geq"
  };

  const std::string NONCOM_EWOP_NAMES[nm::NUM_NONCOM_EWOPS] = {
    "atan2",
    "ldexp",
    "hypot"
  };

  const std::string UNARYOPS[nm::NUM_UNARYOPS] = {
    "sin", "cos", "tan",
    "asin", "acos", "atan",
    "sinh", "cosh", "tanh",
    "asinh", "acosh", "atanh",
    "exp", "log2", 
    "log10", "sqrt", "erf", 
    "erfc", "cbrt", "gamma",
    "negate", "floor", "ceil", "round"
  };


  /*
   * Create a RubyObject from a regular C value (given a dtype). Does not return a VALUE! To get a VALUE, you need to
   * look at the rval property of what this function returns.
   */
  nm::RubyObject rubyobj_from_cval(void* val, nm::dtype_t dtype) {
    using namespace nm;
    switch (dtype) {
      case BYTE:
        return RubyObject(*reinterpret_cast<uint8_t*>(val));

      case INT8:
        return RubyObject(*reinterpret_cast<int8_t*>(val));

      case INT16:
        return RubyObject(*reinterpret_cast<int16_t*>(val));

      case INT32:
        return RubyObject(*reinterpret_cast<int32_t*>(val));

      case INT64:
        return RubyObject(*reinterpret_cast<int64_t*>(val));

      case FLOAT32:
        return RubyObject(*reinterpret_cast<float32_t*>(val));

      case FLOAT64:
        return RubyObject(*reinterpret_cast<float64_t*>(val));

      case COMPLEX64:
        return RubyObject(*reinterpret_cast<Complex64*>(val));

      case COMPLEX128:
        return RubyObject(*reinterpret_cast<Complex128*>(val));

      default:
        try {
          throw std::logic_error("Cannot create ruby object");
        }
        catch (std::logic_error err) {
          printf("%s\n", err.what());
        }

        rb_raise(nm_eDataTypeError, "Conversion to RubyObject requested from unknown/invalid data type (did you try to convert from a VALUE?)");
    }
    return Qnil;
  }
} // end of namespace nm

extern "C" {

const char* const DTYPE_NAMES[nm::NUM_DTYPES] = {
  "byte",
  "int8",
  "int16",
  "int32",
  "int64",
  "float32",
  "float64",
  "complex64",
  "complex128",
  "object"
};


const size_t DTYPE_SIZES[nm::NUM_DTYPES] = {
  sizeof(uint8_t),
  sizeof(int8_t),
  sizeof(int16_t),
  sizeof(int32_t),
  sizeof(int64_t),
  sizeof(float32_t),
  sizeof(float64_t),
  sizeof(nm::Complex64),
  sizeof(nm::Complex128),
  sizeof(nm::RubyObject)
};


const nm::dtype_t Upcast[nm::NUM_DTYPES][nm::NUM_DTYPES] = {
  { nm::BYTE, nm::INT16, nm::INT16, nm::INT32, nm::INT64, nm::FLOAT32, nm::FLOAT64, nm::COMPLEX64, nm::COMPLEX128, nm::RUBYOBJ},
  { nm::INT16, nm::INT8, nm::INT16, nm::INT32, nm::INT64, nm::FLOAT32, nm::FLOAT64, nm::COMPLEX64, nm::COMPLEX128, nm::RUBYOBJ},
  { nm::INT16, nm::INT16, nm::INT16, nm::INT32, nm::INT64, nm::FLOAT32, nm::FLOAT64, nm::COMPLEX64, nm::COMPLEX128, nm::RUBYOBJ},
  { nm::INT32, nm::INT32, nm::INT32, nm::INT32, nm::INT64, nm::FLOAT32, nm::FLOAT64, nm::COMPLEX64, nm::COMPLEX128, nm::RUBYOBJ},
  { nm::INT64, nm::INT64, nm::INT64, nm::INT64, nm::INT64, nm::FLOAT32, nm::FLOAT64, nm::COMPLEX64, nm::COMPLEX128, nm::RUBYOBJ},
  { nm::FLOAT32, nm::FLOAT32, nm::FLOAT32, nm::FLOAT32, nm::FLOAT32, nm::FLOAT32, nm::FLOAT64, nm::COMPLEX64, nm::COMPLEX128, nm::RUBYOBJ},
  { nm::FLOAT64, nm::FLOAT64, nm::FLOAT64, nm::FLOAT64, nm::FLOAT64, nm::FLOAT64, nm::FLOAT64, nm::COMPLEX128, nm::COMPLEX128, nm::RUBYOBJ},
  { nm::COMPLEX64, nm::COMPLEX64, nm::COMPLEX64, nm::COMPLEX64, nm::COMPLEX64, nm::COMPLEX64, nm::COMPLEX128, nm::COMPLEX64, nm::COMPLEX128, nm::RUBYOBJ},
  { nm::COMPLEX128, nm::COMPLEX128, nm::COMPLEX128, nm::COMPLEX128, nm::COMPLEX128, nm::COMPLEX128, nm::COMPLEX128, nm::COMPLEX128, nm::COMPLEX128, nm::RUBYOBJ},
  { nm::RUBYOBJ, nm::RUBYOBJ, nm::RUBYOBJ, nm::RUBYOBJ, nm::RUBYOBJ, nm::RUBYOBJ, nm::RUBYOBJ, nm::RUBYOBJ, nm::RUBYOBJ, nm::RUBYOBJ}
};


/*
 * Forward Declarations
 */

/*
 * Functions
 */

/*
 * Converts a RubyObject
 */
void rubyval_to_cval(VALUE val, nm::dtype_t dtype, void* loc) {
  using namespace nm;
  switch (dtype) {
    case nm::BYTE:
      *reinterpret_cast<uint8_t*>(loc)      = static_cast<uint8_t>(RubyObject(val));
      break;

    case nm::INT8:
      *reinterpret_cast<int8_t*>(loc)        = static_cast<int8_t>(RubyObject(val));
      break;

    case nm::INT16:
      *reinterpret_cast<int16_t*>(loc)      = static_cast<int16_t>(RubyObject(val));
      break;

    case nm::INT32:
      *reinterpret_cast<int32_t*>(loc)      = static_cast<int32_t>(RubyObject(val));
      break;

    case nm::INT64:
      *reinterpret_cast<int64_t*>(loc)      = static_cast<int64_t>(RubyObject(val));
      break;

    case nm::FLOAT32:
      *reinterpret_cast<float32_t*>(loc)    = static_cast<float32_t>(RubyObject(val));
      break;

    case nm::FLOAT64:
      *reinterpret_cast<float64_t*>(loc)    = static_cast<float64_t>(RubyObject(val));
      break;

    case nm::COMPLEX64:
      *reinterpret_cast<Complex64*>(loc)    = RubyObject(val).to<Complex64>();
      break;

    case nm::COMPLEX128:
      *reinterpret_cast<Complex128*>(loc)    = RubyObject(val).to<Complex128>();
      break;

    case RUBYOBJ:
      *reinterpret_cast<VALUE*>(loc)        = val;
      //rb_raise(rb_eTypeError, "Attempting a bad conversion from a Ruby value.");
      break;

    default:
      rb_raise(rb_eTypeError, "Attempting a bad conversion.");
      break;
  }
}




/*
 * Allocate and return a piece of data of the correct dtype, converted from a
 * given RubyObject.
 */
void* rubyobj_to_cval(VALUE val, nm::dtype_t dtype) {
  size_t size =  DTYPE_SIZES[dtype];
  NM_CONSERVATIVE(nm_register_value(&val));
  void* ret_val = NM_ALLOC_N(char, size);

  rubyval_to_cval(val, dtype, ret_val);
  NM_CONSERVATIVE(nm_unregister_value(&val));
  return ret_val;
}


void nm_init_data() {
  volatile VALUE t = INT2FIX(1);
  volatile nm::RubyObject obj(t);
  volatile nm::Complex64 a(const_cast<nm::RubyObject&>(obj));
  volatile nm::Complex128 b(const_cast<nm::RubyObject&>(obj));
}


} // end of extern "C" block