Refactor mjXUtil::WriteAttr using templates.

PiperOrigin-RevId: 453848941
Change-Id: I1f87f0c20f0c89caab89ea4891aee7583a92534e
This commit is contained in:
Alessio Quaglino
2022-06-08 23:33:04 -07:00
committed by Copybara-Service
parent 066367fcc8
commit c7c765b6eb
4 changed files with 58 additions and 183 deletions
+3 -3
View File
@@ -17,14 +17,14 @@
namespace mujoco { namespace mujoco {
namespace { namespace {
thread_local const char* precision = "%g"; thread_local int precision = 6;
} }
const char* _mjPRIVATE__get_xml_precision() { int _mjPRIVATE__get_xml_precision() {
return precision; return precision;
} }
void _mjPRIVATE__set_xml_precision(const char* new_precision) { void _mjPRIVATE__set_xml_precision(const int new_precision) {
precision = new_precision; precision = new_precision;
} }
+4 -4
View File
@@ -20,15 +20,15 @@
namespace mujoco { namespace mujoco {
extern "C" { extern "C" {
MJAPI const char* _mjPRIVATE__get_xml_precision(); MJAPI int _mjPRIVATE__get_xml_precision();
MJAPI void _mjPRIVATE__set_xml_precision(const char* precision); MJAPI void _mjPRIVATE__set_xml_precision(const int precision);
} }
// Full precision printing of floating point numbers in saved XMLs, useful for testing // Full precision printing of floating point numbers in saved XMLs, useful for testing
class FullFloatPrecision { class FullFloatPrecision {
public: public:
FullFloatPrecision() { _mjPRIVATE__set_xml_precision("%.17g");} FullFloatPrecision() { _mjPRIVATE__set_xml_precision(17);}
~FullFloatPrecision() { _mjPRIVATE__set_xml_precision("%g");} ~FullFloatPrecision() { _mjPRIVATE__set_xml_precision(6);}
}; };
} // namespace mujoco } // namespace mujoco
+45 -159
View File
@@ -19,8 +19,10 @@
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <limits>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <type_traits>
#include <vector> #include <vector>
#include "cc/array_safety.h" #include "cc/array_safety.h"
@@ -483,33 +485,16 @@ XMLElement* mjXSchema::Check(XMLElement* elem, int level) {
//---------------------------------- class mjXUtil implementation ---------------------------------- //---------------------------------- class mjXUtil implementation ----------------------------------
// compare two vectors: double // compare two vectors
bool mjXUtil::SameVector(const double* vec1, const double* vec2, int n) { template<typename T>
bool mjXUtil::SameVector(const T* vec1, const T* vec2, int n) {
if (!vec1 || !vec2) { if (!vec1 || !vec2) {
return false; return false;
} }
bool same = true; bool same = true;
for (int i=0; i<n; i++) { for (int i=0; i<n; i++) {
if (fabs(vec1[i] - vec2[i]) > 1E-10) { if (fabs(vec1[i] - vec2[i]) > std::numeric_limits<T>::epsilon()) {
same = false;
}
}
return same;
}
// compare two vectors: double
bool mjXUtil::SameVector(const float* vec1, const float* vec2, int n) {
if (!vec1 || !vec2) {
return false;
}
bool same = true;
for (int i=0; i<n; i++) {
if (fabs(vec1[i] - vec2[i]) > 1E-7) {
same = false; same = false;
} }
} }
@@ -517,6 +502,10 @@ bool mjXUtil::SameVector(const float* vec1, const float* vec2, int n) {
return same; return same;
} }
template bool mjXUtil::SameVector(const double* vec1, const double* vec2, int n);
template bool mjXUtil::SameVector(const float* vec1, const float* vec2, int n);
template bool mjXUtil::SameVector(const int* vec1, const int* vec2, int n);
template bool mjXUtil::SameVector(const mjtByte* vec1, const mjtByte* vec2, int n);
// find string in map, return corresponding integer (-1: not found) // find string in map, return corresponding integer (-1: not found)
@@ -808,163 +797,60 @@ static int Round(double x) {
} }
// write attribute- double // write attribute
void mjXUtil::WriteAttr(XMLElement* elem, string name, int n, double* data, template<typename T>
const double* def) { void mjXUtil::WriteAttr(XMLElement* elem, string name, int n, T* data, const T* def) {
char buf[100];
string value;
value.clear();
// make sure all are defined // make sure all are defined
for (int i=0; i<n; i++) { if constexpr (std::is_floating_point_v<T>) {
if (std::isnan(data[i])) {
return;
}
}
// skip default attributes
if (SameVector(data, def, n)) {
return;
}
// process all numbers
for (int i=0; i<n; i++) {
// add space between numbers
if (i>0) {
value = value + " ";
}
// write integer or float
if (isint(data[i])) {
mju::sprintf_arr(buf, "%d", Round(data[i]));
} else {
mju::sprintf_arr(buf, mujoco::_mjPRIVATE__get_xml_precision(), data[i]);
}
// append number
value = value + buf;
}
// set attribute as string
WriteAttrTxt(elem, name, value);
}
// write attribute- float
void mjXUtil::WriteAttr(XMLElement* elem, string name, int n, float* data,
const float* def) {
char buf[100];
string value;
value.clear();
// skip default attributes
if (SameVector(data, def, n)) {
return;
}
// process all numbers
for (int i=0; i<n; i++) {
// add space between numbers
if (i>0) {
value = value + " ";
}
// write integer or float
if (isint(data[i])) {
mju::sprintf_arr(buf, "%d", Round(data[i]));
} else {
mju::sprintf_arr(buf, "%g", data[i]);
}
// append number
value = value + buf;
}
// set attribute as string
WriteAttrTxt(elem, name, value);
}
// write attribute- byte
void mjXUtil::WriteAttr(XMLElement* elem, string name, int n, mjtByte* data,
const mjtByte* def) {
char buf[100];
string value;
value.clear();
// skip default attributes
if (def) {
bool skip = true;
for (int i=0; i<n; i++)
if (data[i] != def[i]) {
skip = false;
}
if (skip) {
return;
}
}
// process all numbers
for (int i=0; i<n; i++) {
// add space between numbers
if (i>0) {
value = value + " ";
}
// write integer
mju::sprintf_arr(buf, "%d", data[i]);
// append number
value = value + buf;
}
// set attribute as string
WriteAttrTxt(elem, name, value);
}
// write attribute- int
void mjXUtil::WriteAttr(XMLElement* elem, string name, int n, int* data,
const int* def) {
char buf[100];
string value;
value.clear();
// skip default attributes
if (def) {
bool skip = true;
for (int i=0; i<n; i++) { for (int i=0; i<n; i++) {
if (data[i] != def[i]) { if (std::isnan(data[i])) {
skip = false; return;
} }
} }
if (skip) {
return;
}
} }
// skip default attributes
if (SameVector(data, def, n)) {
return;
}
// increase precision for testing
stringstream stream;
stream.precision(mujoco::_mjPRIVATE__get_xml_precision());
// process all numbers // process all numbers
for (int i=0; i<n; i++) { for (int i=0; i<n; i++) {
// add space between numbers // add space between numbers
if (i>0) { if (i>0) {
value = value + " "; stream << " ";
} }
// write integer
mju::sprintf_arr(buf, "%d", data[i]);
// append number // append number
value = value + buf; if (isint(data[i])) {
stream << Round(data[i]);
} else {
stream << data[i];
}
} }
// set attribute as string // set attribute as string
WriteAttrTxt(elem, name, value); WriteAttrTxt(elem, name, stream.str());
} }
template void mjXUtil::WriteAttr(XMLElement* elem, string name, int n,
double* data, const double* def);
template void mjXUtil::WriteAttr(XMLElement* elem, string name, int n,
float* data, const float* def);
template void mjXUtil::WriteAttr(XMLElement* elem, string name, int n,
int* data, const int* def);
template void mjXUtil::WriteAttr(XMLElement* elem, string name, int n,
mjtByte* data, const mjtByte* def);
// write vector<double> attribute, default = zero array // write vector<double> attribute, default = zero array
void mjXUtil::WriteVector(XMLElement* elem, string name, vector<double>& vec) { void mjXUtil::WriteVector(XMLElement* elem, string name, vector<double>& vec) {
// proceed only if non-zero found // proceed only if non-zero found
+6 -17
View File
@@ -89,8 +89,8 @@ class mjXUtil {
virtual ~mjXUtil() = default; virtual ~mjXUtil() = default;
// compare two vectors // compare two vectors
static bool SameVector(const double* vec1, const double* vec2, int n); template<typename T>
static bool SameVector(const float* vec1, const float* vec2, int n); static bool SameVector(const T* vec1, const T* vec2, int n);
// find key in map, return value (-1: not found) // find key in map, return value (-1: not found)
static int FindKey(const mjMap* map, int mapsz, std::string key); static int FindKey(const mjMap* map, int mapsz, std::string key);
@@ -136,21 +136,10 @@ class mjXUtil {
static bool MapValue(tinyxml2::XMLElement* elem, const char* attr, int* data, static bool MapValue(tinyxml2::XMLElement* elem, const char* attr, int* data,
const mjMap* map, int mapSz, bool required = false); const mjMap* map, int mapSz, bool required = false);
// write attribute- double // write attribute- any type
static void WriteAttr(tinyxml2::XMLElement* elem, std::string name, int n, double* data, template<typename T>
const double* def = 0); static void WriteAttr(tinyxml2::XMLElement* elem, std::string name, int n, T* data,
const T* def = 0);
// write attribute- float
static void WriteAttr(tinyxml2::XMLElement* elem, std::string name, int n, float* data,
const float* def = 0);
// write attribute- byte
static void WriteAttr(tinyxml2::XMLElement* elem, std::string name, int n, mjtByte* data,
const mjtByte* def = 0);
// write attribute- int
static void WriteAttr(tinyxml2::XMLElement* elem, std::string name, int n, int* data,
const int* def = 0);
// write vector<double> attribute, with and without default // write vector<double> attribute, with and without default
static void WriteVector(tinyxml2::XMLElement* elem, std::string name, std::vector<double>& vec); static void WriteVector(tinyxml2::XMLElement* elem, std::string name, std::vector<double>& vec);