diff --git a/include/mujoco/mjxmacro.h b/include/mujoco/mjxmacro.h index 606b4752..32cec8e6 100644 --- a/include/mujoco/mjxmacro.h +++ b/include/mujoco/mjxmacro.h @@ -387,20 +387,17 @@ X ( float, flex_texcoord, nflextexcoord, 2 ) \ X ( int, mesh_vertadr, nmesh, 1 ) \ X ( int, mesh_vertnum, nmesh, 1 ) \ - X ( int, mesh_normaladr, nmesh, 1 ) \ - X ( int, mesh_normalnum, nmesh, 1 ) \ - X ( int, mesh_texcoordadr, nmesh, 1 ) \ - X ( int, mesh_texcoordnum, nmesh, 1 ) \ X ( int, mesh_faceadr, nmesh, 1 ) \ X ( int, mesh_facenum, nmesh, 1 ) \ X ( int, mesh_bvhadr, nmesh, 1 ) \ X ( int, mesh_bvhnum, nmesh, 1 ) \ X ( int, mesh_octadr, nmesh, 1 ) \ X ( int, mesh_octnum, nmesh, 1 ) \ + X ( int, mesh_normaladr, nmesh, 1 ) \ + X ( int, mesh_normalnum, nmesh, 1 ) \ + X ( int, mesh_texcoordadr, nmesh, 1 ) \ + X ( int, mesh_texcoordnum, nmesh, 1 ) \ X ( int, mesh_graphadr, nmesh, 1 ) \ - X ( mjtNum, mesh_scale, nmesh, 3 ) \ - X ( mjtNum, mesh_pos, nmesh, 3 ) \ - X ( mjtNum, mesh_quat, nmesh, 4 ) \ XNV ( float, mesh_vert, nmeshvert, 3 ) \ XNV ( float, mesh_normal, nmeshnormal, 3 ) \ XNV ( float, mesh_texcoord, nmeshtexcoord, 2 ) \ @@ -408,6 +405,9 @@ XNV ( int, mesh_facenormal, nmeshface, 3 ) \ XNV ( int, mesh_facetexcoord, nmeshface, 3 ) \ XNV ( int, mesh_graph, nmeshgraph, 1 ) \ + X ( mjtNum, mesh_scale, nmesh, 3 ) \ + X ( mjtNum, mesh_pos, nmesh, 3 ) \ + X ( mjtNum, mesh_quat, nmesh, 4 ) \ X ( int, mesh_pathadr, nmesh, 1 ) \ XNV ( int, mesh_polynum, nmesh, 1 ) \ XNV ( int, mesh_polyadr, nmesh, 1 ) \ @@ -670,8 +670,8 @@ X ( int, ten_J_rownnz, ntendon, 1 ) \ X ( int, ten_J_rowadr, ntendon, 1 ) \ X ( int, ten_J_colind, ntendon, MJ_M(nv) ) \ - X ( mjtNum, ten_length, ntendon, 1 ) \ X ( mjtNum, ten_J, ntendon, MJ_M(nv) ) \ + X ( mjtNum, ten_length, ntendon, 1 ) \ X ( int, wrap_obj, nwrap, 2 ) \ X ( mjtNum, wrap_xpos, nwrap, 6 ) \ X ( mjtNum, actuator_length, nu, 1 ) \ @@ -741,8 +741,8 @@ X ( mjtNum, efc_vel, MJ_D(nefc), 1 ) \ X ( mjtNum, efc_aref, MJ_D(nefc), 1 ) \ X ( mjtNum, efc_b, MJ_D(nefc), 1 ) \ - X ( mjtNum, efc_force, MJ_D(nefc), 1 ) \ - X ( int, efc_state, MJ_D(nefc), 1 ) + X ( int, efc_state, MJ_D(nefc), 1 ) \ + X ( mjtNum, efc_force, MJ_D(nefc), 1 ) // array fields of mjData that are used in the dual problem #define MJDATA_ARENA_POINTERS_DUAL \ @@ -826,12 +826,12 @@ // vector fields of mjData #define MJDATA_VECTOR \ X( size_t, maxuse_threadstack, mjMAXTHREAD, 1 ) \ - X( mjWarningStat, warning, mjNWARNING, 1 ) \ - X( mjTimerStat, timer, mjNTIMER, 1 ) \ X( mjSolverStat, solver, mjNISLAND, mjNSOLVER ) \ X( int, solver_niter, mjNISLAND, 1 ) \ X( int, solver_nnz, mjNISLAND, 1 ) \ X( mjtNum, solver_fwdinv, 2, 1 ) \ + X( mjWarningStat, warning, mjNWARNING, 1 ) \ + X( mjTimerStat, timer, mjNTIMER, 1 ) \ X( mjtNum, energy, 2, 1 ) // alias XNV to be the same as X diff --git a/python/mujoco/structs.h b/python/mujoco/structs.h index 418bb879..18d306ad 100644 --- a/python/mujoco/structs.h +++ b/python/mujoco/structs.h @@ -667,12 +667,12 @@ class MjWrapper: public WrapperBase { py_array_or_tuple_t contact; py_array_or_tuple_t maxuse_threadstack; - py_array_or_tuple_t warning; - py_array_or_tuple_t timer; py_array_or_tuple_t solver; py_array_or_tuple_t solver_niter; py_array_or_tuple_t solver_nnz; py_array_or_tuple_t solver_fwdinv; + py_array_or_tuple_t warning; + py_array_or_tuple_t timer; py_array_or_tuple_t energy; protected: diff --git a/test/header_test.cc b/test/header_test.cc index ff1369a9..83c79fcc 100644 --- a/test/header_test.cc +++ b/test/header_test.cc @@ -15,20 +15,33 @@ // Tests for structures in the public headers. #include -#include -#include - +#include +#include +#include #include #include #include #include #include #include +#include #include "test/fixture.h" namespace mujoco { namespace { +// check that a vector of named pointers are ordered by address +void CheckAddressOrdering( + const std::vector>& pointers, + const char* category_name) { + for (size_t i = 0; i < pointers.size() - 1; ++i) { + EXPECT_LT(reinterpret_cast(pointers[i].first), + reinterpret_cast(pointers[i + 1].first)) + << category_name << " '" << pointers[i].second + << "' should be declared before '" << pointers[i + 1].second << "'."; + } +} + using HeaderTest = MujocoTest; TEST_F(HeaderTest, IntsHave4Bytes) { @@ -84,5 +97,145 @@ TEST_F(HeaderTest, EnumsAreInts) { EXPECT_EQ(sizeof(mjtStereo), sizeof(int)); } +TEST_F(HeaderTest, MjOptionFloatsOrdered) { + mjOption o; + std::vector> floats; + +#define X(type, name) \ + floats.push_back({static_cast(&o.name), #name}); + MJOPTION_FLOATS +#undef X + + CheckAddressOrdering(floats, "MJOPTION_FLOATS"); +} + +TEST_F(HeaderTest, MjOptionVectorsOrdered) { + mjOption o; + std::vector> vectors; + +#define X(name, dim) \ + vectors.push_back({static_cast(&o.name), #name}); + MJOPTION_VECTORS +#undef X + + CheckAddressOrdering(vectors, "MJOPTION_VECTORS"); +} + +TEST_F(HeaderTest, MjModelIntsOrdered) { + mjModel m; + std::vector> ints; + +#define X(name) ints.push_back({static_cast(&m.name), #name}); + MJMODEL_INTS +#undef X + + CheckAddressOrdering(ints, "MJMODEL_INT"); +} + +TEST_F(HeaderTest, MjModelPointersOrdered) { + mjModel m; + std::vector> pointers; + +#define X(type, name, dim1, dim2) \ + pointers.push_back({static_cast(&m.name), #name}); +#define XNV X + MJMODEL_POINTERS +#undef XNV +#undef X + + CheckAddressOrdering(pointers, "MJMODEL_POINTER"); +} + + +TEST_F(HeaderTest, MjDataPointersOrdered) { + mjData d; + std::vector> pointers; + +#define X(type, name, dim1, dim2) \ + pointers.push_back({static_cast(&d.name), #name}); +#define XNV X + MJDATA_POINTERS +#undef XNV +#undef X + + CheckAddressOrdering(pointers, "mjData pointer"); +} + +TEST_F(HeaderTest, MjDataArenaPointersSolverOrdered) { + mjData d; + std::vector> pointers; + +#define X(type, name, dim1, dim2) \ + pointers.push_back({static_cast(&d.name), #name}); +#define XNV X +#undef MJ_D +#define MJ_D(n) 0 + MJDATA_ARENA_POINTERS_SOLVER +#undef MJ_D +#define MJ_D(n) n +#undef XNV +#undef X + + CheckAddressOrdering(pointers, "MJDATA_ARENA_POINTERS_SOLVER"); +} + +TEST_F(HeaderTest, MjDataArenaPointersDualOrdered) { + mjData d; + std::vector> pointers; + +#define X(type, name, dim1, dim2) \ + pointers.push_back({static_cast(&d.name), #name}); +#define XNV X +#undef MJ_D +#define MJ_D(n) 0 + MJDATA_ARENA_POINTERS_DUAL +#undef MJ_D +#define MJ_D(n) n +#undef XNV +#undef X + + CheckAddressOrdering(pointers, "MJDATA_ARENA_POINTERS_DUAL"); +} + +TEST_F(HeaderTest, MjDataArenaPointersIslandOrdered) { + mjData d; + std::vector> pointers; + +#define X(type, name, dim1, dim2) \ + pointers.push_back({static_cast(&d.name), #name}); +#define XNV X +#undef MJ_D +#define MJ_D(n) 0 + MJDATA_ARENA_POINTERS_ISLAND +#undef MJ_D +#define MJ_D(n) n +#undef XNV +#undef X + + CheckAddressOrdering(pointers, "MJDATA_ARENA_POINTERS_ISLAND"); +} + +TEST_F(HeaderTest, MjDataScalarsOrdered) { + mjData d; + std::vector> scalars; + +#define X(type, name) \ + scalars.push_back({static_cast(&d.name), #name}); + MJDATA_SCALAR +#undef X + CheckAddressOrdering(scalars, "mjData scalar"); +} + +TEST_F(HeaderTest, MjDataVectorsOrdered) { + mjData d; + std::vector> vectors; + +#define X(type, name, dim1, dim2) \ + vectors.push_back({static_cast(&d.name), #name}); + MJDATA_VECTOR +#undef X + CheckAddressOrdering(vectors, "mjData vector"); +} + } // namespace } // namespace mujoco