Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project aspires to adhere to [Semantic Versioning](https://semver.org/s
### Changed
#### Conduit
- Changed Conduit memory handler callbacks from function pointers to `std::function` objects, allowing users more flexibility in dealing with different memory spaces.
- Added element stride helper methods to the DataType class.

#### Relay
- Ported relay and blueprint zfp support to use zfp 1.0 api. Added extra meta data to zfparray blueprint protocol to support roundtrip wrapping and unwrapping with zfp 1.0 api.
Expand Down
4 changes: 4 additions & 0 deletions src/libs/conduit/c/conduit_datatype.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ CONDUIT_API int conduit_datatype_is_little_endian(const conduit_datatype *cdatat
CONDUIT_API int conduit_datatype_is_big_endian(const conduit_datatype *cdatatype);
CONDUIT_API int conduit_datatype_endianness_matches_machine(const conduit_datatype *cdatatype);

CONDUIT_API conduit_index_t conduit_datatype_element_stride(const conduit_datatype *cdatatype);
CONDUIT_API int conduit_datatype_is_stride_element_aligned(const conduit_datatype *cdatatype);
CONDUIT_API int conduit_datatype_is_stride_aligned(const conduit_datatype *cdatatype, conduit_index_t nbytes);

#ifdef __cplusplus
}
#endif
Expand Down
15 changes: 15 additions & 0 deletions src/libs/conduit/c/conduit_datatype_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,21 @@ int conduit_datatype_endianness_matches_machine(const conduit_datatype *cdatatyp
return cpp_datatype_ref(cdatatype).endianness_matches_machine() ? 1 : 0;
}

conduit_index_t conduit_datatype_element_stride(const conduit_datatype *cdatatype)
{
return cpp_datatype_ref(cdatatype).element_stride();
}

int conduit_datatype_is_stride_element_aligned(const conduit_datatype *cdatatype)
{
return cpp_datatype_ref(cdatatype).is_stride_element_aligned() ? 1 : 0;
}

int conduit_datatype_is_stride_aligned(const conduit_datatype *cdatatype, conduit_index_t nbytes)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

int return is consistent with other c api functions that provide boolean answers

{
return cpp_datatype_ref(cdatatype).is_stride_aligned(nbytes) ? 1 : 0;
}

}
//-----------------------------------------------------------------------------
// -- end extern C
Expand Down
47 changes: 47 additions & 0 deletions src/libs/conduit/conduit_data_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,53 @@ DataType::element_index(conduit::index_t idx) const
return m_offset + m_stride * idx;
}

//---------------------------------------------------------------------------//
conduit::index_t
DataType::element_stride() const
{
// Check for zero to avoid division by zero
if(m_ele_bytes == 0)
{
return 0;
}

return m_stride / m_ele_bytes;
}

//---------------------------------------------------------------------------//
bool
DataType::is_stride_element_aligned() const
{
// If element_bytes is zero, we can't determine alignment
if(m_ele_bytes == 0)
{
return false;
}

// Test if stride is a multiple of element_bytes
return (m_stride % m_ele_bytes) == 0;
}

//---------------------------------------------------------------------------//
bool
DataType::is_stride_aligned(conduit::index_t nbytes) const
{
// If nbytes is zero, we can't determine alignment
if(nbytes == 0)
{
return false;
}

// For zero stride (empty case), consider it aligned with everything
if(m_stride == 0)
{
return true;
}

// Test if stride is a multiple of nbytes
return (m_stride % nbytes) == 0;
}

//-----------------------------------------------------------------------------
// TypeID to string and string to TypeId
//-----------------------------------------------------------------------------
Expand Down
7 changes: 7 additions & 0 deletions src/libs/conduit/conduit_data_type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,13 @@ class CONDUIT_API DataType
conduit::index_t element_bytes() const { return m_ele_bytes;}
conduit::index_t endianness() const { return m_endianness;}
conduit::index_t element_index(conduit::index_t idx) const;

/// Returns the stride in elements (stride in bytes / element_bytes)
conduit::index_t element_stride() const;
/// Tests if stride is aligned with element boundaries (stride % element_bytes == 0)
bool is_stride_element_aligned() const;
/// Tests if stride is a multiple of given bytes
bool is_stride_aligned(conduit::index_t nbytes) const;

/// strided bytes = stride() * (number_of_elements() -1) + element_bytes()
conduit::index_t strided_bytes() const;
Expand Down
28 changes: 28 additions & 0 deletions src/libs/conduit/fortran/conduit_fortran.F90
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,15 @@ pure function conduit_datatype_element_bytes(cdatatype) result(res) &
integer(kind(F_CONDUIT_INDEX_ID)) :: res
end function conduit_datatype_element_bytes

!--------------------------------------------------------------------------
pure function conduit_datatype_element_stride(cdatatype) result(res) &
bind(C, name="conduit_datatype_element_stride")
use iso_c_binding
implicit none
type(C_PTR), value, intent(IN) :: cdatatype
integer(kind(F_CONDUIT_INDEX_ID)) :: res
end function conduit_datatype_element_stride

!--------------------------------------------------------------------------
pure function conduit_datatype_endianness(cdatatype) result(res) &
bind(C, name="conduit_datatype_endianness")
Expand Down Expand Up @@ -1705,6 +1714,25 @@ pure function c_conduit_datatype_endianness_matches_machine(cdatatype) result(re
type(C_PTR), value, intent(IN) :: cdatatype
integer(C_INT) :: res
end function c_conduit_datatype_endianness_matches_machine

!--------------------------------------------------------------------------
pure function c_conduit_datatype_is_stride_element_aligned(cdatatype) result(res) &
bind(C, name="conduit_datatype_is_stride_element_aligned")
use iso_c_binding
implicit none
type(C_PTR), value, intent(IN) :: cdatatype
integer(C_INT) :: res
end function c_conduit_datatype_is_stride_element_aligned

!--------------------------------------------------------------------------
pure function c_conduit_datatype_is_stride_aligned(cdatatype, nbytes) result(res) &
bind(C, name="conduit_datatype_is_stride_aligned")
use iso_c_binding
implicit none
type(C_PTR), value, intent(IN) :: cdatatype
integer(kind(F_CONDUIT_INDEX_ID)), value, intent(IN) :: nbytes
integer(C_INT) :: res
end function c_conduit_datatype_is_stride_aligned


!--------------------------------------------------------------------------
Expand Down
58 changes: 58 additions & 0 deletions src/libs/conduit/python/conduit_python.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2656,6 +2656,49 @@ PyConduit_DataType_float64_id(PyObject *) // unused
return PyLong_FromSsize_t(DataType::FLOAT64_ID);
}

//-----------------------------------------------------------------------------
static PyObject *
PyConduit_DataType_element_stride(PyConduit_DataType *self)
{
return PyLong_FromSsize_t(self->dtype.element_stride());
}

//-----------------------------------------------------------------------------
static PyObject *
PyConduit_DataType_is_stride_element_aligned(PyConduit_DataType *self)
{
if(self->dtype.is_stride_element_aligned())
{
Py_RETURN_TRUE;
}
else
{
Py_RETURN_FALSE;
}
}

//-----------------------------------------------------------------------------
static PyObject *
PyConduit_DataType_is_stride_aligned(PyConduit_DataType *self,
PyObject *args)
{
Py_ssize_t nbytes;
if (!PyArg_ParseTuple(args, "n", &nbytes))
{
PyErr_SetString(PyExc_TypeError,
"nbytes must be an integer");
return NULL;
}

if(self->dtype.is_stride_aligned((index_t)nbytes))
{
Py_RETURN_TRUE;
}
else
{
Py_RETURN_FALSE;
}
}

//----------------------------------------------------------------------------//
// DataType methods table
Expand Down Expand Up @@ -2726,6 +2769,21 @@ static PyMethodDef PyConduit_DataType_METHODS[] = {
METH_NOARGS,
"Returns the number of bytes per element property of this DataType"},
//-----------------------------------------------------------------------//
{"element_stride",
(PyCFunction)PyConduit_DataType_element_stride,
METH_NOARGS,
"Returns the element stride (stride / element_bytes) property of this DataType"},
//-----------------------------------------------------------------------//
{"is_stride_element_aligned",
(PyCFunction)PyConduit_DataType_is_stride_element_aligned,
METH_NOARGS,
"Returns whether the stride is aligned with element boundaries (stride % element_bytes == 0)"},
//-----------------------------------------------------------------------//
{"is_stride_aligned",
(PyCFunction)PyConduit_DataType_is_stride_aligned,
METH_VARARGS,
"Returns whether the stride is aligned with the given number of bytes (stride % nbytes == 0)"},
//-----------------------------------------------------------------------//
{"endianness",
(PyCFunction)PyConduit_DataType_endianness,
METH_NOARGS,
Expand Down
32 changes: 32 additions & 0 deletions src/tests/conduit/c/t_c_conduit_datatype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,35 @@ TEST(c_conduit_datatype, sizeof_index_t)

}

//-----------------------------------------------------------------------------
TEST(c_conduit_datatype, stride_methods)
{
conduit_node *n = conduit_node_create();

// Create a simple array with stride = element_bytes
conduit_float64 arr_vals[] = {10.0, 20.0, 30.0, 40.0, 50.0};
conduit_node_set_external_float64_ptr(n, arr_vals, 5);

// Get the datatype
const conduit_datatype *dt = conduit_node_dtype(n);

// Check stride-related properties
conduit_index_t stride = conduit_datatype_stride(dt);
conduit_index_t element_bytes = conduit_datatype_element_bytes(dt);
conduit_index_t element_stride = conduit_datatype_element_stride(dt);

// Verify that stride / element_bytes = element_stride
EXPECT_EQ(stride / element_bytes, element_stride);

// Since this is an array with standard layout, stride should be aligned with element bytes
EXPECT_EQ(conduit_datatype_is_stride_element_aligned(dt), 1);

// Test stride aligned with various byte sizes
EXPECT_EQ(conduit_datatype_is_stride_aligned(dt, 8), 1); // Stride should be aligned with 8 bytes
EXPECT_EQ(conduit_datatype_is_stride_aligned(dt, 4), 1); // Stride should be aligned with 4 bytes
EXPECT_EQ(conduit_datatype_is_stride_aligned(dt, 2), 1); // Stride should be aligned with 2 bytes

// Clean up
conduit_node_destroy(n);
}

8 changes: 8 additions & 0 deletions src/tests/conduit/fortran/t_f_conduit_node_datatype.f90
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,14 @@ subroutine t_node_datatype_ids
call assert_true( conduit_datatype_element_bytes(dataType) == 8)
call assert_true( conduit_datatype_stride(dataType) == 8)
call assert_true( conduit_datatype_offset(dataType) == 0)

! Test the new element stride methods
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
! Test the new element stride methods
! Test the element stride methods

call assert_true( conduit_datatype_element_stride(dataType) == 1) ! 8/8 = 1
call assert_true( c_conduit_datatype_is_stride_element_aligned(dataType) == 1) ! 8 % 8 = 0
call assert_true( c_conduit_datatype_is_stride_aligned(dataType, 8) == 1) ! 8 % 8 = 0
call assert_true( c_conduit_datatype_is_stride_aligned(dataType, 4) == 1) ! 8 % 4 = 0
call assert_true( c_conduit_datatype_is_stride_aligned(dataType, 2) == 1) ! 8 % 2 = 0

call assert_true( c_conduit_datatype_is_number(dataType) == 1)
call assert_true( c_conduit_datatype_is_integer(dataType) == 0)
call assert_true( c_conduit_datatype_is_signed_integer(dataType) == 0)
Expand Down
52 changes: 51 additions & 1 deletion src/tests/conduit/python/t_python_conduit_datatype.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,57 @@ def test_to_string_and_friends(self):
self.assertEqual(d.to_string("yaml"),d.to_yaml())
self.assertEqual(d.to_string("json"),d.to_json())


def test_stride_methods(self):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def test_stride_methods(self):
def test_element_stride_methods(self):

# Regular and aligned stride case
dt = DataType()
dt.set(dtype_id = DataType.name_to_id("uint32"),
num_elements = 10,
offset = 0,
stride = 8,
element_bytes = 4)

# Element stride should be stride / element_bytes (8 / 4 = 2)
self.assertEqual(dt.element_stride(), 2)
# Stride is aligned with element boundaries (8 % 4 = 0)
self.assertTrue(dt.is_stride_element_aligned())
# Stride is aligned with 2-byte boundary (8 % 2 = 0)
self.assertTrue(dt.is_stride_aligned(2))
# Stride is aligned with 4-byte boundary (8 % 4 = 0)
self.assertTrue(dt.is_stride_aligned(4))
# Stride is not aligned with 3-byte boundary (8 % 3 != 0)
self.assertFalse(dt.is_stride_aligned(3))

# Non-aligned stride case
dt.set_stride(6)
# Element stride should be integer division (6 / 4 = 1)
self.assertEqual(dt.element_stride(), 1)
# Stride is not aligned with element boundaries (6 % 4 != 0)
self.assertFalse(dt.is_stride_element_aligned())
# Stride is aligned with 2-byte boundary (6 % 2 = 0)
self.assertTrue(dt.is_stride_aligned(2))
# Stride is aligned with 3-byte boundary (6 % 3 = 0)
self.assertTrue(dt.is_stride_aligned(3))
# Stride is not aligned with 4-byte boundary (6 % 4 != 0)
self.assertFalse(dt.is_stride_aligned(4))

# Special case - zero stride
dt.set_stride(0)
# Element stride should be 0 for zero stride (0 / 4 = 0)
self.assertEqual(dt.element_stride(), 0)
# Zero stride is considered element aligned
self.assertTrue(dt.is_stride_element_aligned())
# Zero stride is aligned with any byte boundary
self.assertTrue(dt.is_stride_aligned(4))
self.assertTrue(dt.is_stride_aligned(3))
self.assertTrue(dt.is_stride_aligned(2))

# Special case - zero element_bytes
dt.set_stride(8)
dt.set_element_bytes(0)
# Element stride is currently defined to return 0 for zero element_bytes case
self.assertEqual(dt.element_stride(), 0)
# Element alignment is currently defined to return true for zero element_bytes
self.assertTrue(dt.is_stride_element_aligned())


if __name__ == '__main__':
Expand Down
Loading
Loading