Accessing Numeric Data¶
Accessing Scalars and Arrays¶
You can access leaf types (numeric scalars or arrays) using Node’s as_{type} methods.
Node n;
int64 val = 100;
n = val;
std::cout << n.as_int64() << std::endl;
100
Or you can use Node::value(), which can infer the correct return type via a cast.
Node n;
int64 val = 100;
n = val;
int64 my_val = n.value();
std::cout << my_val << std::endl;
100
Accessing array data via pointers works the same way, using Node’s as_{type} methods.
int64 vals[4] = {100,200,300,400};
Node n;
n.set(vals,4);
int64 *my_vals = n.as_int64_ptr();
for(index_t i=0; i < 4; i++)
{
std::cout << "my_vals[" << i << "] = " << my_vals[i] << std::endl;
}
my_vals[0] = 100
my_vals[1] = 200
my_vals[2] = 300
my_vals[3] = 400
Or using Node::value():
int64 vals[4] = {100,200,300,400};
Node n;
n.set(vals,4);
int64 *my_vals = n.value();
for(index_t i=0; i < 4; i++)
{
std::cout << "my_vals[" << i << "] = " << my_vals[i] << std::endl;
}
my_vals[0] = 100
my_vals[1] = 200
my_vals[2] = 300
my_vals[3] = 400
For non-contiguous arrays, direct pointer access is complex due to the indexing required. Conduit provides a simple DataArray class that handles per-element indexing for all types of arrays.
int64 vals[4] = {100,200,300,400};
Node n;
n.set(vals,2, // # of elements
0, // offset in bytes
sizeof(int64)*2); // stride in bytes
int64_array my_vals = n.value();
for(index_t i=0; i < 2; i++)
{
std::cout << "my_vals[" << i << "] = " << my_vals[i] << std::endl;
}
my_vals.print();
my_vals[0] = 100
my_vals[1] = 300
[100, 300]
C++11 Initializer Lists¶
When C++11 support is enabled you can set Node values using initializer lists with numeric literals.
Node n;
// set with integer c++11 initializer list
n.set({100,200,300});
n.print();
// assign with integer c++11 initializer list
n = {100,200,300};
n.print();
// set with floating point c++11 initializer list
n.set({1.0,2.0,3.0});
n.print();
// assign with floating point c++11 initializer list
n = {1.0,2.0,3.0};
n.print();
[100, 200, 300]
[100, 200, 300]
[1.0, 2.0, 3.0]
[1.0, 2.0, 3.0]
Using Introspection and Conversion¶
In this example, we have an array in a node that we are interested in processing using an existing function that only handles doubles. We ensure the node is compatible with the function, or transform it to a contiguous double array.
//-----------------------------------------------------------------------------
void must_have_doubles_function(double *vals,index_t num_vals)
{
for(int i = 0; i < num_vals; i++)
{
std::cout << "vals[" << i << "] = " << vals[i] << std::endl;
}
}
//-----------------------------------------------------------------------------
void process_doubles(Node & n)
{
Node res;
// We have a node that we are interested in processing with
// and existing function that only handles doubles.
if( n.dtype().is_double() && n.dtype().is_compact() )
{
std::cout << " using existing buffer" << std::endl;
// we already have a contiguous double array
res.set_external(n);
}
else
{
std::cout << " converting to temporary double array " << std::endl;
// Create a compact double array with the values of the input.
// Standard casts are used to convert each source element to
// a double in the new array.
n.to_double_array(res);
}
res.print();
double *dbl_vals = res.value();
index_t num_vals = res.dtype().number_of_elements();
must_have_doubles_function(dbl_vals,num_vals);
}
//-----------------------------------------------------------------------------
TEST(conduit_tutorial, numeric_double_conversion)
{
float32 f32_vals[4] = {100.0,200.0,300.0,400.0};
double d_vals[4] = {1000.0,2000.0,3000.0,4000.0};
Node n;
n["float32_vals"].set(f32_vals,4);
n["double_vals"].set(d_vals,4);
std::cout << "float32 case: " << std::endl;
process_doubles(n["float32_vals"]);
std::cout << "double case: " << std::endl;
process_doubles(n["double_vals"]);
}
[ OK ] conduit_tutorial.numeric_double_conversion_start (0 ms)
[ RUN ] conduit_tutorial.numeric_double_conversion
float32 case:
converting to temporary double array
[100.0, 200.0, 300.0, 400.0]
vals[0] = 100
vals[1] = 200
vals[2] = 300
vals[3] = 400
double case:
using existing buffer
[1000.0, 2000.0, 3000.0, 4000.0]
vals[0] = 1000
vals[1] = 2000
vals[2] = 3000
vals[3] = 4000
[ OK ] conduit_tutorial.numeric_double_conversion (0 ms)
[ RUN ] conduit_tutorial.numeric_double_conversion_end