Speed up String2Vector.
PiperOrigin-RevId: 612767185 Change-Id: I4a4de5e03bbd6653be7ccb3e730ad64a335e17b0
This commit is contained in:
committed by
Copybara-Service
parent
9efa4ebe0b
commit
31384bdfeb
@@ -490,7 +490,7 @@ mjtByte mjm_setInStringVec(mjStringVec dest, int i, const char* text) {
|
|||||||
// split text and copy into string array
|
// split text and copy into string array
|
||||||
void mjm_setStringVec(mjStringVec dest, const char* text) {
|
void mjm_setStringVec(mjStringVec dest, const char* text) {
|
||||||
std::vector<std::string>* v = reinterpret_cast<std::vector<std::string>*>(dest);
|
std::vector<std::string>* v = reinterpret_cast<std::vector<std::string>*>(dest);
|
||||||
mjXUtil::String2Vector(text, *v);
|
*v = mjXUtil::String2Vector<std::string>(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -420,9 +420,9 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjmBody* body, char* error, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mjXUtil::Vector2String(userface, face);
|
mjXUtil::Vector2String(userface, face);
|
||||||
} else {
|
} else {
|
||||||
dim = 2; // can only load a surface for now
|
dim = 2; // can only load a surface for now
|
||||||
mjXUtil::String2Vector(userface, face);
|
face = mjXUtil::String2Vector<int>(userface);
|
||||||
for (int i=0; i<face.size(); face[i++]--) {};
|
for (int i=0; i<face.size(); face[i++]--) {};
|
||||||
mjXUtil::Vector2String(userface, face);
|
mjXUtil::Vector2String(userface, face);
|
||||||
}
|
}
|
||||||
@@ -439,7 +439,7 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjmBody* body, char* error, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!userface.empty()) {
|
if (!userface.empty()) {
|
||||||
mjXUtil::String2Vector(userface, face);
|
face = mjXUtil::String2Vector<int>(userface);
|
||||||
for (int j=0; j<face.size()/3; j++) {
|
for (int j=0; j<face.size()/3; j++) {
|
||||||
mjtNum area[3];
|
mjtNum area[3];
|
||||||
mjtNum edge1[3];
|
mjtNum edge1[3];
|
||||||
@@ -1306,7 +1306,7 @@ void mjCComposite::MakeSkin2(mjCModel* model, mjtNum inflate) {
|
|||||||
// copy skin from existing mesh
|
// copy skin from existing mesh
|
||||||
if (type==mjCOMPTYPE_PARTICLE && username.empty()) {
|
if (type==mjCOMPTYPE_PARTICLE && username.empty()) {
|
||||||
std::vector<int> skinface;
|
std::vector<int> skinface;
|
||||||
mjXUtil::String2Vector(userface, skinface);
|
skinface = mjXUtil::String2Vector<int>(userface);
|
||||||
int nvert = uservert.size()/3;
|
int nvert = uservert.size()/3;
|
||||||
|
|
||||||
for (int j=0; j<2; j++) {
|
for (int j=0; j<2; j++) {
|
||||||
|
|||||||
@@ -1304,18 +1304,15 @@ void mjXReader::OneFlex(XMLElement* elem, mjmFlex* pflex) {
|
|||||||
mjm_setStringVec(pflex->vertbody, text.c_str());
|
mjm_setStringVec(pflex->vertbody, text.c_str());
|
||||||
}
|
}
|
||||||
if (ReadAttrTxt(elem, "vertex", text)) {
|
if (ReadAttrTxt(elem, "vertex", text)) {
|
||||||
std::vector<double> vert;
|
std::vector<double> vert = String2Vector<double>(text);
|
||||||
String2Vector(text, vert);
|
|
||||||
mjm_setDouble(pflex->vert, vert.data(), vert.size());
|
mjm_setDouble(pflex->vert, vert.data(), vert.size());
|
||||||
}
|
}
|
||||||
if (ReadAttrTxt(elem, "element", text, true)) {
|
if (ReadAttrTxt(elem, "element", text, true)) {
|
||||||
std::vector<int> elem;
|
std::vector<int> elem = String2Vector<int>(text);
|
||||||
String2Vector(text, elem);
|
|
||||||
mjm_setInt(pflex->elem, elem.data(), elem.size());
|
mjm_setInt(pflex->elem, elem.data(), elem.size());
|
||||||
}
|
}
|
||||||
if (ReadAttrTxt(elem, "texcoord", text)) {
|
if (ReadAttrTxt(elem, "texcoord", text)) {
|
||||||
std::vector<float> texcoord;
|
std::vector<float> texcoord = String2Vector<float>(text);
|
||||||
String2Vector(text, texcoord);
|
|
||||||
mjm_setFloat(pflex->texcoord, texcoord.data(), texcoord.size());
|
mjm_setFloat(pflex->texcoord, texcoord.data(), texcoord.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1447,22 +1444,19 @@ void mjXReader::OneSkin(XMLElement* elem, mjmSkin* pskin) {
|
|||||||
|
|
||||||
// read vertex data
|
// read vertex data
|
||||||
if (ReadAttrTxt(elem, "vertex", text)) {
|
if (ReadAttrTxt(elem, "vertex", text)) {
|
||||||
std::vector<float> vert;
|
std::vector<float> vert = String2Vector<float>(text);
|
||||||
String2Vector(text, vert);
|
|
||||||
mjm_setFloat(pskin->vert, vert.data(), vert.size());
|
mjm_setFloat(pskin->vert, vert.data(), vert.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// read texcoord data
|
// read texcoord data
|
||||||
if (ReadAttrTxt(elem, "texcoord", text)) {
|
if (ReadAttrTxt(elem, "texcoord", text)) {
|
||||||
std::vector<float> texcoord;
|
std::vector<float> texcoord = String2Vector<float>(text);
|
||||||
String2Vector(text, texcoord);
|
|
||||||
mjm_setFloat(pskin->texcoord, texcoord.data(), texcoord.size());
|
mjm_setFloat(pskin->texcoord, texcoord.data(), texcoord.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// read user face data
|
// read user face data
|
||||||
if (ReadAttrTxt(elem, "face", text)) {
|
if (ReadAttrTxt(elem, "face", text)) {
|
||||||
std::vector<int> face;
|
std::vector<int> face = String2Vector<int>(text);
|
||||||
String2Vector(text, face);
|
|
||||||
mjm_setInt(pskin->face, face.data(), face.size());
|
mjm_setInt(pskin->face, face.data(), face.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1490,15 +1484,13 @@ void mjXReader::OneSkin(XMLElement* elem, mjmSkin* pskin) {
|
|||||||
bindquat.push_back(data[3]);
|
bindquat.push_back(data[3]);
|
||||||
|
|
||||||
// read vertid
|
// read vertid
|
||||||
vector<int> tempid;
|
|
||||||
ReadAttrTxt(bone, "vertid", text, true);
|
ReadAttrTxt(bone, "vertid", text, true);
|
||||||
String2Vector(text, tempid);
|
vector<int> tempid = String2Vector<int>(text);
|
||||||
mjm_appendIntVec(pskin->vertid, tempid.data(), tempid.size());
|
mjm_appendIntVec(pskin->vertid, tempid.data(), tempid.size());
|
||||||
|
|
||||||
// read vertweight
|
// read vertweight
|
||||||
vector<float> tempweight;
|
|
||||||
ReadAttrTxt(bone, "vertweight", text, true);
|
ReadAttrTxt(bone, "vertweight", text, true);
|
||||||
String2Vector(text, tempweight);
|
vector<float> tempweight = String2Vector<float>(text);
|
||||||
mjm_appendFloatVec(pskin->vertweight, tempweight.data(), tempweight.size());
|
mjm_appendFloatVec(pskin->vertweight, tempweight.data(), tempweight.size());
|
||||||
|
|
||||||
// advance to next bone
|
// advance to next bone
|
||||||
@@ -2277,8 +2269,8 @@ void mjXReader::OneComposite(XMLElement* elem, mjmBody* pbody, mjmDefault* def)
|
|||||||
ReadAttrTxt(elem, "curve", curves);
|
ReadAttrTxt(elem, "curve", curves);
|
||||||
ReadAttrTxt(elem, "initial", comp.initial);
|
ReadAttrTxt(elem, "initial", comp.initial);
|
||||||
ReadAttr(elem, "size", 3, comp.size, text, false, false);
|
ReadAttr(elem, "size", 3, comp.size, text, false, false);
|
||||||
if (ReadAttrTxt(elem, "vertex", text)){
|
if (ReadAttrTxt(elem, "vertex", text)) {
|
||||||
String2Vector(text, comp.uservert);
|
comp.uservert = String2Vector<float>(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
// shell
|
// shell
|
||||||
@@ -2521,13 +2513,13 @@ void mjXReader::OneFlexcomp(XMLElement* elem, mjmBody* pbody) {
|
|||||||
fcomp.rigid = (n==1);
|
fcomp.rigid = (n==1);
|
||||||
}
|
}
|
||||||
if (ReadAttrTxt(elem, "point", text)){
|
if (ReadAttrTxt(elem, "point", text)){
|
||||||
String2Vector(text, fcomp.point);
|
fcomp.point = String2Vector<mjtNum>(text);
|
||||||
}
|
}
|
||||||
if (ReadAttrTxt(elem, "element", text)){
|
if (ReadAttrTxt(elem, "element", text)){
|
||||||
String2Vector(text, fcomp.element);
|
fcomp.element = String2Vector<int>(text);
|
||||||
}
|
}
|
||||||
if (ReadAttrTxt(elem, "texcoord", text)) {
|
if (ReadAttrTxt(elem, "texcoord", text)) {
|
||||||
String2Vector(text, fcomp.texcoord);
|
fcomp.texcoord = String2Vector<float>(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
// edge
|
// edge
|
||||||
@@ -2566,22 +2558,22 @@ void mjXReader::OneFlexcomp(XMLElement* elem, mjmBody* pbody) {
|
|||||||
XMLElement* epin = FirstChildElement(elem, "pin");
|
XMLElement* epin = FirstChildElement(elem, "pin");
|
||||||
while (epin) {
|
while (epin) {
|
||||||
// accumulate id, coord, range
|
// accumulate id, coord, range
|
||||||
vector<int> temp;
|
if (ReadAttrTxt(epin, "id", text)) {
|
||||||
if (ReadAttrTxt(epin, "id", text)){
|
vector<int> v = String2Vector<int>(text);
|
||||||
String2Vector(text, temp);
|
fcomp.pinid.insert(fcomp.pinid.end(), v.begin(), v.end());
|
||||||
fcomp.pinid.insert(fcomp.pinid.end(), temp.begin(), temp.end());
|
|
||||||
}
|
}
|
||||||
if (ReadAttrTxt(epin, "range", text)){
|
if (ReadAttrTxt(epin, "range", text)) {
|
||||||
String2Vector(text, temp);
|
vector<int> v = String2Vector<int>(text);
|
||||||
fcomp.pinrange.insert(fcomp.pinrange.end(), temp.begin(), temp.end());
|
fcomp.pinrange.insert(fcomp.pinrange.end(), v.begin(), v.end());
|
||||||
}
|
}
|
||||||
if (ReadAttrTxt(epin, "grid", text)){
|
if (ReadAttrTxt(epin, "grid", text)) {
|
||||||
String2Vector(text, temp);
|
|
||||||
fcomp.pingrid.insert(fcomp.pingrid.end(), temp.begin(), temp.end());
|
vector<int> v = String2Vector<int>(text);
|
||||||
|
fcomp.pingrid.insert(fcomp.pingrid.end(), v.begin(), v.end());
|
||||||
}
|
}
|
||||||
if (ReadAttrTxt(epin, "gridrange", text)){
|
if (ReadAttrTxt(epin, "gridrange", text)) {
|
||||||
String2Vector(text, temp);
|
vector<int> v = String2Vector<int>(text);
|
||||||
fcomp.pingridrange.insert(fcomp.pingridrange.end(), temp.begin(), temp.end());
|
fcomp.pingridrange.insert(fcomp.pingridrange.end(), v.begin(), v.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
// advance
|
// advance
|
||||||
@@ -2884,7 +2876,7 @@ void mjXReader::Custom(XMLElement* section) {
|
|||||||
|
|
||||||
// read name and assign
|
// read name and assign
|
||||||
ReadAttrTxt(obj, "objname", text, true);
|
ReadAttrTxt(obj, "objname", text, true);
|
||||||
objname += text + " ";
|
objname += " " + text;
|
||||||
|
|
||||||
// read parameter and assign
|
// read parameter and assign
|
||||||
double oprm = 0;
|
double oprm = 0;
|
||||||
|
|||||||
+38
-60
@@ -13,6 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cerrno>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
@@ -42,7 +43,6 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using std::istringstream;
|
|
||||||
using std::size_t;
|
using std::size_t;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::stringstream;
|
using std::stringstream;
|
||||||
@@ -735,74 +735,52 @@ bool mjXUtil::ReadAttrInt(XMLElement* elem, const char* attr, int* data, bool re
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// read vector<string> from string
|
template<> int mjXUtil::StrToNum(char* str, char** c) {
|
||||||
void mjXUtil::String2Vector(const string& txt, vector<string>& vec) {
|
return std::strtol(str, c, 10);
|
||||||
stringstream strm(txt);
|
|
||||||
vec.clear();
|
|
||||||
|
|
||||||
while (!strm.eof()) {
|
|
||||||
string word;
|
|
||||||
strm >> word;
|
|
||||||
if (strm.fail()) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
vec.push_back(word);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<> float mjXUtil::StrToNum(char* str, char** c) {
|
||||||
|
return std::strtof(str, c);
|
||||||
// read vector<mjtNum> from string
|
|
||||||
void mjXUtil::String2Vector(const string& txt, vector<double>& vec) {
|
|
||||||
stringstream strm(txt);
|
|
||||||
vec.clear();
|
|
||||||
|
|
||||||
while (!strm.eof()) {
|
|
||||||
double num;
|
|
||||||
strm >> num;
|
|
||||||
if (strm.fail()) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
vec.push_back(num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<> double mjXUtil::StrToNum(char* str, char** c) {
|
||||||
|
return std::strtod(str, c);
|
||||||
// read vector<float> from string
|
|
||||||
void mjXUtil::String2Vector(const string& txt, vector<float>& vec) {
|
|
||||||
stringstream strm(txt);
|
|
||||||
vec.clear();
|
|
||||||
|
|
||||||
while (!strm.eof()) {
|
|
||||||
float num;
|
|
||||||
strm >> num;
|
|
||||||
if (strm.fail()) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
vec.push_back(num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::vector<T> mjXUtil::String2Vector(const std::string& s) {
|
||||||
|
errno = 0;
|
||||||
|
std::vector<T> v;
|
||||||
|
char* cs = (char*) s.c_str();
|
||||||
|
char* ch = cs;
|
||||||
|
|
||||||
|
// reserve worst case
|
||||||
|
v.reserve((s.size() >> 1) + 1);
|
||||||
|
|
||||||
// read vector<int> from string
|
for (;;) {
|
||||||
void mjXUtil::String2Vector(const string& txt, vector<int>& vec) {
|
cs = ch;
|
||||||
stringstream strm(txt);
|
T num = StrToNum<T>(cs, &ch);
|
||||||
vec.clear();
|
if (cs == ch) break;
|
||||||
|
if (errno) break;
|
||||||
while (!strm.eof()) {
|
v.push_back(num);
|
||||||
int num;
|
|
||||||
strm >> num;
|
|
||||||
if (strm.fail()) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
vec.push_back(num);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v.shrink_to_fit();
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
template std::vector<int> mjXUtil::String2Vector(const std::string& s);
|
||||||
|
template std::vector<float> mjXUtil::String2Vector(const std::string& s);
|
||||||
|
template std::vector<double> mjXUtil::String2Vector(const std::string& s);
|
||||||
|
template<>
|
||||||
|
std::vector<std::string> mjXUtil::String2Vector(const std::string& s) {
|
||||||
|
std::vector<std::string> v;
|
||||||
|
std::stringstream ss(s);
|
||||||
|
std::string word;
|
||||||
|
while (ss >> word) {
|
||||||
|
v.push_back(word);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+5
-11
@@ -163,17 +163,9 @@ class mjXUtil {
|
|||||||
static bool ReadAttrInt(tinyxml2::XMLElement* elem, const char* attr, int* data,
|
static bool ReadAttrInt(tinyxml2::XMLElement* elem, const char* attr, int* data,
|
||||||
bool required = false);
|
bool required = false);
|
||||||
|
|
||||||
// read vector<string> from string
|
// convert string to vector
|
||||||
static void String2Vector(const std::string& txt, std::vector<std::string>& vec);
|
template<typename T>
|
||||||
|
static std::vector<T> String2Vector(const std::string& s);
|
||||||
// read vector<double> from string
|
|
||||||
static void String2Vector(const std::string& txt, std::vector<double>& vec);
|
|
||||||
|
|
||||||
// read vector<float> from string
|
|
||||||
static void String2Vector(const std::string& txt, std::vector<float>& vec);
|
|
||||||
|
|
||||||
// read vector<int> from string
|
|
||||||
static void String2Vector(const std::string& txt, std::vector<int>& vec);
|
|
||||||
|
|
||||||
// write vector<string> to string
|
// write vector<string> to string
|
||||||
static void Vector2String(std::string& txt, const std::vector<std::string>& vec);
|
static void Vector2String(std::string& txt, const std::vector<std::string>& vec);
|
||||||
@@ -220,6 +212,8 @@ class mjXUtil {
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
static bool ReadAttrValues(tinyxml2::XMLElement* elem, const char* attr,
|
static bool ReadAttrValues(tinyxml2::XMLElement* elem, const char* attr,
|
||||||
std::function<void (int, T)> push, int max = -1);
|
std::function<void (int, T)> push, int max = -1);
|
||||||
|
template<typename T> static T StrToNum(char* str, char** c);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MUJOCO_SRC_XML_XML_UTIL_H_
|
#endif // MUJOCO_SRC_XML_XML_UTIL_H_
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2024 DeepMind Technologies Limited
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include "src/xml/xml_util.h"
|
||||||
|
#include "test/fixture.h"
|
||||||
|
|
||||||
|
namespace mujoco {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using XMLUtilTest = MujocoTest;
|
||||||
|
|
||||||
|
using ::testing::ElementsAre;
|
||||||
|
|
||||||
|
TEST_F(XMLUtilTest, String2VectorFloat) {
|
||||||
|
std::vector<float> v = mjXUtil::String2Vector<float>(" 1.2 3.2 5.3 6 ");
|
||||||
|
EXPECT_THAT(v, ElementsAre(1.2, 3.2, 5.3, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(XMLUtilTest, String2VectorEmpty) {
|
||||||
|
std::vector<float> v = mjXUtil::String2Vector<float>("");
|
||||||
|
EXPECT_THAT(v, ElementsAre());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(XMLUtilTest, String2VectorError) {
|
||||||
|
std::vector<float> v = mjXUtil::String2Vector<float>("ABCD. /123/122/113");
|
||||||
|
EXPECT_THAT(v, ElementsAre());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(XMLUtilTest, String2VectorInt) {
|
||||||
|
std::vector<int> v = mjXUtil::String2Vector<int>(" -1 3 5 6");
|
||||||
|
EXPECT_THAT(v, ElementsAre(-1, 3, 5, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(XMLUtilTest, String2VectorString) {
|
||||||
|
auto v = mjXUtil::String2Vector<std::string>(" abc def ");
|
||||||
|
EXPECT_THAT(v, ElementsAre("abc", "def"));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace mujoco
|
||||||
Reference in New Issue
Block a user