Speed up String2Vector.

PiperOrigin-RevId: 612767185
Change-Id: I4a4de5e03bbd6653be7ccb3e730ad64a335e17b0
This commit is contained in:
Kyle Bayes
2024-03-05 02:49:22 -08:00
committed by Copybara-Service
parent 9efa4ebe0b
commit 31384bdfeb
6 changed files with 132 additions and 111 deletions
+1 -1
View File
@@ -490,7 +490,7 @@ mjtByte mjm_setInStringVec(mjStringVec dest, int i, const char* text) {
// split text and copy into string array
void mjm_setStringVec(mjStringVec dest, const char* text) {
std::vector<std::string>* v = reinterpret_cast<std::vector<std::string>*>(dest);
mjXUtil::String2Vector(text, *v);
*v = mjXUtil::String2Vector<std::string>(text);
}
+4 -4
View File
@@ -420,9 +420,9 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjmBody* body, char* error, int
}
}
mjXUtil::Vector2String(userface, face);
} else {
} else {
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++]--) {};
mjXUtil::Vector2String(userface, face);
}
@@ -439,7 +439,7 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjmBody* body, char* error, int
}
}
if (!userface.empty()) {
mjXUtil::String2Vector(userface, face);
face = mjXUtil::String2Vector<int>(userface);
for (int j=0; j<face.size()/3; j++) {
mjtNum area[3];
mjtNum edge1[3];
@@ -1306,7 +1306,7 @@ void mjCComposite::MakeSkin2(mjCModel* model, mjtNum inflate) {
// copy skin from existing mesh
if (type==mjCOMPTYPE_PARTICLE && username.empty()) {
std::vector<int> skinface;
mjXUtil::String2Vector(userface, skinface);
skinface = mjXUtil::String2Vector<int>(userface);
int nvert = uservert.size()/3;
for (int j=0; j<2; j++) {
+27 -35
View File
@@ -1304,18 +1304,15 @@ void mjXReader::OneFlex(XMLElement* elem, mjmFlex* pflex) {
mjm_setStringVec(pflex->vertbody, text.c_str());
}
if (ReadAttrTxt(elem, "vertex", text)) {
std::vector<double> vert;
String2Vector(text, vert);
std::vector<double> vert = String2Vector<double>(text);
mjm_setDouble(pflex->vert, vert.data(), vert.size());
}
if (ReadAttrTxt(elem, "element", text, true)) {
std::vector<int> elem;
String2Vector(text, elem);
std::vector<int> elem = String2Vector<int>(text);
mjm_setInt(pflex->elem, elem.data(), elem.size());
}
if (ReadAttrTxt(elem, "texcoord", text)) {
std::vector<float> texcoord;
String2Vector(text, texcoord);
std::vector<float> texcoord = String2Vector<float>(text);
mjm_setFloat(pflex->texcoord, texcoord.data(), texcoord.size());
}
@@ -1447,22 +1444,19 @@ void mjXReader::OneSkin(XMLElement* elem, mjmSkin* pskin) {
// read vertex data
if (ReadAttrTxt(elem, "vertex", text)) {
std::vector<float> vert;
String2Vector(text, vert);
std::vector<float> vert = String2Vector<float>(text);
mjm_setFloat(pskin->vert, vert.data(), vert.size());
}
// read texcoord data
if (ReadAttrTxt(elem, "texcoord", text)) {
std::vector<float> texcoord;
String2Vector(text, texcoord);
std::vector<float> texcoord = String2Vector<float>(text);
mjm_setFloat(pskin->texcoord, texcoord.data(), texcoord.size());
}
// read user face data
if (ReadAttrTxt(elem, "face", text)) {
std::vector<int> face;
String2Vector(text, face);
std::vector<int> face = String2Vector<int>(text);
mjm_setInt(pskin->face, face.data(), face.size());
}
@@ -1490,15 +1484,13 @@ void mjXReader::OneSkin(XMLElement* elem, mjmSkin* pskin) {
bindquat.push_back(data[3]);
// read vertid
vector<int> tempid;
ReadAttrTxt(bone, "vertid", text, true);
String2Vector(text, tempid);
vector<int> tempid = String2Vector<int>(text);
mjm_appendIntVec(pskin->vertid, tempid.data(), tempid.size());
// read vertweight
vector<float> tempweight;
ReadAttrTxt(bone, "vertweight", text, true);
String2Vector(text, tempweight);
vector<float> tempweight = String2Vector<float>(text);
mjm_appendFloatVec(pskin->vertweight, tempweight.data(), tempweight.size());
// advance to next bone
@@ -2277,8 +2269,8 @@ void mjXReader::OneComposite(XMLElement* elem, mjmBody* pbody, mjmDefault* def)
ReadAttrTxt(elem, "curve", curves);
ReadAttrTxt(elem, "initial", comp.initial);
ReadAttr(elem, "size", 3, comp.size, text, false, false);
if (ReadAttrTxt(elem, "vertex", text)){
String2Vector(text, comp.uservert);
if (ReadAttrTxt(elem, "vertex", text)) {
comp.uservert = String2Vector<float>(text);
}
// shell
@@ -2521,13 +2513,13 @@ void mjXReader::OneFlexcomp(XMLElement* elem, mjmBody* pbody) {
fcomp.rigid = (n==1);
}
if (ReadAttrTxt(elem, "point", text)){
String2Vector(text, fcomp.point);
fcomp.point = String2Vector<mjtNum>(text);
}
if (ReadAttrTxt(elem, "element", text)){
String2Vector(text, fcomp.element);
fcomp.element = String2Vector<int>(text);
}
if (ReadAttrTxt(elem, "texcoord", text)) {
String2Vector(text, fcomp.texcoord);
fcomp.texcoord = String2Vector<float>(text);
}
// edge
@@ -2566,22 +2558,22 @@ void mjXReader::OneFlexcomp(XMLElement* elem, mjmBody* pbody) {
XMLElement* epin = FirstChildElement(elem, "pin");
while (epin) {
// accumulate id, coord, range
vector<int> temp;
if (ReadAttrTxt(epin, "id", text)){
String2Vector(text, temp);
fcomp.pinid.insert(fcomp.pinid.end(), temp.begin(), temp.end());
if (ReadAttrTxt(epin, "id", text)) {
vector<int> v = String2Vector<int>(text);
fcomp.pinid.insert(fcomp.pinid.end(), v.begin(), v.end());
}
if (ReadAttrTxt(epin, "range", text)){
String2Vector(text, temp);
fcomp.pinrange.insert(fcomp.pinrange.end(), temp.begin(), temp.end());
if (ReadAttrTxt(epin, "range", text)) {
vector<int> v = String2Vector<int>(text);
fcomp.pinrange.insert(fcomp.pinrange.end(), v.begin(), v.end());
}
if (ReadAttrTxt(epin, "grid", text)){
String2Vector(text, temp);
fcomp.pingrid.insert(fcomp.pingrid.end(), temp.begin(), temp.end());
if (ReadAttrTxt(epin, "grid", text)) {
vector<int> v = String2Vector<int>(text);
fcomp.pingrid.insert(fcomp.pingrid.end(), v.begin(), v.end());
}
if (ReadAttrTxt(epin, "gridrange", text)){
String2Vector(text, temp);
fcomp.pingridrange.insert(fcomp.pingridrange.end(), temp.begin(), temp.end());
if (ReadAttrTxt(epin, "gridrange", text)) {
vector<int> v = String2Vector<int>(text);
fcomp.pingridrange.insert(fcomp.pingridrange.end(), v.begin(), v.end());
}
// advance
@@ -2884,7 +2876,7 @@ void mjXReader::Custom(XMLElement* section) {
// read name and assign
ReadAttrTxt(obj, "objname", text, true);
objname += text + " ";
objname += " " + text;
// read parameter and assign
double oprm = 0;
+38 -60
View File
@@ -13,6 +13,7 @@
// limitations under the License.
#include <algorithm>
#include <cerrno>
#include <climits>
#include <cmath>
#include <cstddef>
@@ -42,7 +43,6 @@
namespace {
using std::istringstream;
using std::size_t;
using std::string;
using std::stringstream;
@@ -735,74 +735,52 @@ bool mjXUtil::ReadAttrInt(XMLElement* elem, const char* attr, int* data, bool re
// read vector<string> from string
void mjXUtil::String2Vector(const string& txt, vector<string>& vec) {
stringstream strm(txt);
vec.clear();
while (!strm.eof()) {
string word;
strm >> word;
if (strm.fail()) {
break;
} else {
vec.push_back(word);
}
}
template<> int mjXUtil::StrToNum(char* str, char** c) {
return std::strtol(str, c, 10);
}
// 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<> float mjXUtil::StrToNum(char* str, char** c) {
return std::strtof(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<> double mjXUtil::StrToNum(char* str, char** c) {
return std::strtod(str, c);
}
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
void mjXUtil::String2Vector(const string& txt, vector<int>& vec) {
stringstream strm(txt);
vec.clear();
while (!strm.eof()) {
int num;
strm >> num;
if (strm.fail()) {
break;
} else {
vec.push_back(num);
}
for (;;) {
cs = ch;
T num = StrToNum<T>(cs, &ch);
if (cs == ch) break;
if (errno) break;
v.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
View File
@@ -163,17 +163,9 @@ class mjXUtil {
static bool ReadAttrInt(tinyxml2::XMLElement* elem, const char* attr, int* data,
bool required = false);
// read vector<string> from string
static void String2Vector(const std::string& txt, std::vector<std::string>& vec);
// 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);
// convert string to vector
template<typename T>
static std::vector<T> String2Vector(const std::string& s);
// write vector<string> to string
static void Vector2String(std::string& txt, const std::vector<std::string>& vec);
@@ -220,6 +212,8 @@ class mjXUtil {
template<typename T>
static bool ReadAttrValues(tinyxml2::XMLElement* elem, const char* attr,
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_
+57
View File
@@ -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