Buffers

Buffers are often used in C and C++ APIs. Examples include:

  • Buffers of fundamental types

  • Pointers to arrays of fundamental type or C++ objects

  • Pointer to a fundamental type (often used to support function parameters used to return values)

Rice supports these uses cases via its Buffer class. The following buffer types are provided out of the box:

Bufferbool
Bufferunsigned char
Bufferunsigned char*
Buffersigned char
Buffersigned char*
Bufferchar
Bufferchar*
Bufferunsigned short
Bufferunsigned short*
Buffershort
Buffershort*
Bufferunsigned int
Bufferunsigned int*
Bufferint
Bufferint*
Bufferfloat
Bufferfloat*
Bufferdouble
Bufferdouble*
Bufferunsigned long
Bufferunsigned long*
Bufferlong
Bufferlong*
Bufferunsigned long long
Bufferunsigned long long*
Bufferlong long
Bufferlong long*
Buffervoid

However, to use them you need to register them. To do that add the following code to your bindings:

Rice::init();

Fundamental Types

It is common for C and C++ APIs to take pointers to blocks of memory consisting of fundamental types like unsigned chars. For example, the OpenCV library includes an API to create a Mat instance like this:

Matrix(int rows, int columns, void uint8_t* data)

data is a pointer to a buffer consisting of uint_8 values.

To call this API from Ruby, first create a Buffer from a Ruby array like this:

data = [1, 2, 3, 4]
buffer = Rice::Bufferunsigned char.new(data)
mat = Matrix.new(2, 2, buffer)

It is your responsibility to manage the memory of the buffer. When the buffer variable goes out of scope, Ruby will garbage collect it which will free the underlying buffer. In most cases, the target API will immediately use the buffer so this is not a problem. In cases where API takes ownership of the buffer then make sure to use takeOwnership as explained in the Memory Management section:

rb_cMatrix = define_class<Matrix>("Matrix").
  define_constructor(Constructor<Matrix, int, int, uint8_t*>(),
    Arg("rows"), Arg("columns"), Arg("data").takeOwnership();

Array of Objects

C++ APIs can also take a pointer to an array of objects. For example:

Matrix Matrix::operator()(const Range* ranges) const

This code creates a view onto an existing Matrix based on an array of Range objects. The length of the array is equal to the Matrix’s number of dimensions.

To call this from Ruby:

data = [Cv::Range.new(0, 10), Cv::Range(30, 40)]
buffer = Rice::BufferCv::Range.new(data)

matrix = Matrix.new(100, 100)
matrix[buffer]

Array of Pointers

The above example also works with an array of pointers. In that case:

Matrix Matrix::operator()(const Range** ranges) const

Notice the ranges parameter is now a ** - or an array of pointers. You would call this method from Ruby in the exact same way as the example above.

Out Parameters

C and C++ APIs sometimes return values via function parameters. For example, from OpenCV:

void cv::minMaxLoc(cv::InputArray src,
              double*         minVal,
              double*         maxVal = 0,
              Point*          minLoc = 0,
              Point*          maxLoc = 0,
              cv::InputArray  mask = cv::noArray())

All of minVal, maxVal, minLoc and maxLoc are out parameters designed to return values.

One way to wrap this code is to return a tuple as explained in Out Parameters. An alternative is to use Buffers like this:

min_val = Rice::Bufferdouble.new()
max_val = Rice::Bufferdouble.new()
min_loc = Cv::Point.new
max_loc = Cv::Point.new
CV::min_max_loc(min_val, max_val, min_loc, max_loc)

# Read the min_val
puts min_val[0]