Skip to content

Commit 19dc715

Browse files
committed
Optimize IdString operations to avoid calling c_str()
1 parent e661e2f commit 19dc715

File tree

2 files changed

+151
-18
lines changed

2 files changed

+151
-18
lines changed

kernel/rtlil.h

Lines changed: 133 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,85 @@ struct RTLIL::IdString
273273
*out += std::to_string(-index_);
274274
}
275275

276+
class const_iterator {
277+
private:
278+
const std::string *prefix;
279+
std::string suffix;
280+
const char *c_str;
281+
int c_str_len;
282+
// When this is INT_MAX it's the generic "end" value.
283+
int index;
284+
285+
public:
286+
using iterator_category = std::forward_iterator_tag;
287+
using value_type = char;
288+
using difference_type = std::ptrdiff_t;
289+
using pointer = const char*;
290+
using reference = const char&;
291+
292+
const_iterator(const char *c_str) : prefix(nullptr), c_str(c_str), c_str_len(strlen(c_str)), index(0) {}
293+
const_iterator(const std::string *prefix, int number) :
294+
prefix(prefix), suffix(std::to_string(number)), c_str(nullptr), c_str_len(0), index(0) {}
295+
// Construct end-marker
296+
const_iterator() : prefix(nullptr), c_str(nullptr), c_str_len(0), index(INT_MAX) {}
297+
298+
int size() const {
299+
if (c_str != nullptr)
300+
return c_str_len;
301+
return GetSize(*prefix) + GetSize(suffix);
302+
}
303+
304+
char operator*() const {
305+
if (c_str != nullptr)
306+
return c_str[index];
307+
int prefix_size = GetSize(*prefix);
308+
if (index < prefix_size)
309+
return prefix->at(index);
310+
return suffix[index - prefix_size];
311+
}
312+
313+
const_iterator& operator++() { ++index; return *this; }
314+
const_iterator operator++(int) { const_iterator result(*this); ++index; return result; }
315+
const_iterator& operator+=(int i) { index += i; return *this; }
316+
317+
const_iterator operator+(int add) {
318+
const_iterator result = *this;
319+
result += add;
320+
return result;
321+
}
322+
323+
bool operator==(const const_iterator& other) const {
324+
return index == other.index || (other.index == INT_MAX && index == size())
325+
|| (index == INT_MAX && other.index == other.size());
326+
}
327+
bool operator!=(const const_iterator& other) const {
328+
return !(*this == other);
329+
}
330+
};
331+
const_iterator begin() const {
332+
if (index_ >= 0) {
333+
return const_iterator(global_id_storage_.at(index_));
334+
}
335+
return const_iterator(global_negative_id_prefix_storage_.at(index_), -index_);
336+
}
337+
const_iterator end() const {
338+
return const_iterator();
339+
}
340+
341+
inline bool lt_by_name(const IdString &rhs) const {
342+
const_iterator rhs_it = rhs.begin();
343+
for (char ch : *this) {
344+
if (rhs_it == rhs.end())
345+
return false;
346+
if (ch < *rhs_it)
347+
return true;
348+
if (ch > *rhs_it)
349+
return false;
350+
++rhs_it;
351+
}
352+
return rhs_it != rhs.end();
353+
}
354+
276355
inline bool operator<(const IdString &rhs) const {
277356
return index_ < rhs.index_;
278357
}
@@ -291,45 +370,81 @@ struct RTLIL::IdString
291370
bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; }
292371

293372
char operator[](size_t i) const {
294-
const char *p = c_str();
373+
if (index_ >= 0) {
374+
const char *p = global_id_storage_.at(index_);
295375
#ifndef NDEBUG
296-
for (; i != 0; i--, p++)
297-
log_assert(*p != 0);
298-
return *p;
376+
for (; i != 0; i--, p++)
377+
log_assert(*p != 0);
378+
return *p;
299379
#else
300-
return *(p + i);
380+
return *(p + i);
301381
#endif
382+
}
383+
const std::string &id_start = *global_negative_id_prefix_storage_.at(index_);
384+
if (i < id_start.size())
385+
return id_start[i];
386+
return std::to_string(-index_).c_str()[i - id_start.size()];
302387
}
303388

304389
std::string substr(size_t pos = 0, size_t len = std::string::npos) const {
305-
if (len == std::string::npos || len >= strlen(c_str() + pos))
306-
return std::string(c_str() + pos);
307-
else
308-
return std::string(c_str() + pos, len);
390+
std::string result;
391+
const_iterator it = begin() + pos;
392+
const_iterator end_it = end();
393+
if (len != std::string::npos && len < it.size() - pos) {
394+
end_it = it + len;
395+
}
396+
std::copy(it, end_it, std::back_inserter(result));
397+
return result;
309398
}
310399

311400
int compare(size_t pos, size_t len, const char* s) const {
312-
return strncmp(c_str()+pos, s, len);
401+
const_iterator it = begin() + pos;
402+
const_iterator end_it = end();
403+
while (len > 0 && *s != 0 && it != end_it) {
404+
int diff = *it - *s;
405+
if (diff != 0)
406+
return diff;
407+
++it;
408+
++s;
409+
--len;
410+
}
411+
return 0;
313412
}
314413

315414
bool begins_with(const char* prefix) const {
316-
size_t len = strlen(prefix);
317-
if (size() < len) return false;
318-
return compare(0, len, prefix) == 0;
415+
const_iterator it = begin();
416+
const_iterator end_it = end();
417+
while (*prefix != 0) {
418+
if (it == end_it || *prefix != *it)
419+
return false;
420+
++prefix;
421+
++it;
422+
}
423+
return true;
319424
}
320425

321426
bool ends_with(const char* suffix) const {
322-
size_t len = strlen(suffix);
323-
if (size() < len) return false;
324-
return compare(size()-len, len, suffix) == 0;
427+
int suffix_len = strlen(suffix);
428+
const_iterator it = begin();
429+
int sz = it.size();
430+
if (suffix_len > sz)
431+
return false;
432+
it += sz - suffix_len;
433+
while (*suffix != 0) {
434+
if (*it != *suffix)
435+
return false;
436+
++suffix;
437+
++it;
438+
}
439+
return true;
325440
}
326441

327442
bool contains(const char* str) const {
328443
return strstr(c_str(), str);
329444
}
330445

331446
size_t size() const {
332-
return strlen(c_str());
447+
return begin().size();
333448
}
334449

335450
bool empty() const {
@@ -627,7 +742,7 @@ namespace RTLIL {
627742

628743
struct sort_by_id_str {
629744
bool operator()(const RTLIL::IdString &a, const RTLIL::IdString &b) const {
630-
return strcmp(a.c_str(), b.c_str()) < 0;
745+
return a.lt_by_name(b);
631746
}
632747
};
633748

tests/unit/kernel/rtlilTest.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,24 @@ namespace RTLIL {
373373
EXPECT_EQ(id, id2);
374374
}
375375

376+
TEST_F(KernelRtlilTest, NewIdBeginsWith) {
377+
IdString id = NEW_ID;
378+
EXPECT_TRUE(id.begins_with("$auto"));
379+
EXPECT_FALSE(id.begins_with("xyz"));
380+
EXPECT_TRUE(id.begins_with("$auto$"));
381+
EXPECT_FALSE(id.begins_with("abcdefghijklmn"));
382+
EXPECT_TRUE(id.begins_with("$auto$rtlilTest"));
383+
EXPECT_FALSE(id.begins_with("$auto$rtlilX"));
384+
}
385+
386+
TEST_F(KernelRtlilTest, NewIdIndexing) {
387+
IdString id = NEW_ID;
388+
std::string str = id.str();
389+
for (int i = 0; i < GetSize(str) + 1; ++i) {
390+
EXPECT_EQ(id[i], str.c_str()[i]);
391+
}
392+
}
393+
376394
class WireRtlVsHdlIndexConversionTest :
377395
public KernelRtlilTest,
378396
public testing::WithParamInterface<std::tuple<bool, int, int>>

0 commit comments

Comments
 (0)