mirror of
https://github.com/YosysHQ/yosys
synced 2025-11-03 13:07:58 +00:00
Optimize IdString operations to avoid calling c_str()
This commit is contained in:
parent
2075b3416f
commit
a534fda855
2 changed files with 200 additions and 21 deletions
203
kernel/rtlil.h
203
kernel/rtlil.h
|
|
@ -130,6 +130,8 @@ struct RTLIL::IdString
|
|||
struct Storage {
|
||||
char *buf;
|
||||
int size;
|
||||
|
||||
std::string_view str_view() const { return {buf, static_cast<size_t>(size)}; }
|
||||
};
|
||||
|
||||
#undef YOSYS_XTRACE_GET_PUT
|
||||
|
|
@ -260,14 +262,135 @@ struct RTLIL::IdString
|
|||
|
||||
inline void append_to(std::string *out) const {
|
||||
if (index_ >= 0) {
|
||||
const Storage &storage = global_id_storage_.at(index_);
|
||||
*out += std::string_view(storage.buf, storage.size);
|
||||
*out += global_id_storage_.at(index_).str_view();
|
||||
return;
|
||||
}
|
||||
*out += *global_autoidx_id_prefix_storage_.at(index_);
|
||||
*out += std::to_string(-index_);
|
||||
}
|
||||
|
||||
class Substrings {
|
||||
std::string_view first_;
|
||||
int suffix_number;
|
||||
char buf[10];
|
||||
public:
|
||||
Substrings(const Storage &storage) : first_(storage.str_view()), suffix_number(-1) {}
|
||||
// suffix_number must be non-negative
|
||||
Substrings(const std::string *prefix, int suffix_number)
|
||||
: first_(*prefix), suffix_number(suffix_number) {}
|
||||
std::string_view first() { return first_; }
|
||||
std::optional<std::string_view> next() {
|
||||
if (suffix_number < 0)
|
||||
return std::nullopt;
|
||||
int i = sizeof(buf);
|
||||
do {
|
||||
--i;
|
||||
buf[i] = (suffix_number % 10) + '0';
|
||||
suffix_number /= 10;
|
||||
} while (suffix_number > 0);
|
||||
suffix_number = -1;
|
||||
return std::string_view(buf + i, sizeof(buf) - i);
|
||||
}
|
||||
};
|
||||
|
||||
class const_iterator {
|
||||
const std::string *prefix;
|
||||
std::string suffix;
|
||||
const char *c_str;
|
||||
int c_str_len;
|
||||
// When this is INT_MAX it's the generic "end" value.
|
||||
int index;
|
||||
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = char;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = const char*;
|
||||
using reference = const char&;
|
||||
|
||||
const_iterator(const Storage &storage) : prefix(nullptr), c_str(storage.buf), c_str_len(storage.size), index(0) {}
|
||||
const_iterator(const std::string *prefix, int number) :
|
||||
prefix(prefix), suffix(std::to_string(number)), c_str(nullptr), c_str_len(0), index(0) {}
|
||||
// Construct end-marker
|
||||
const_iterator() : prefix(nullptr), c_str(nullptr), c_str_len(0), index(INT_MAX) {}
|
||||
|
||||
int size() const {
|
||||
if (c_str != nullptr)
|
||||
return c_str_len;
|
||||
return GetSize(*prefix) + GetSize(suffix);
|
||||
}
|
||||
|
||||
char operator*() const {
|
||||
if (c_str != nullptr)
|
||||
return c_str[index];
|
||||
int prefix_size = GetSize(*prefix);
|
||||
if (index < prefix_size)
|
||||
return prefix->at(index);
|
||||
return suffix[index - prefix_size];
|
||||
}
|
||||
|
||||
const_iterator& operator++() { ++index; return *this; }
|
||||
const_iterator operator++(int) { const_iterator result(*this); ++index; return result; }
|
||||
const_iterator& operator+=(int i) { index += i; return *this; }
|
||||
|
||||
const_iterator operator+(int add) {
|
||||
const_iterator result = *this;
|
||||
result += add;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const const_iterator& other) const {
|
||||
return index == other.index || (other.index == INT_MAX && index == size())
|
||||
|| (index == INT_MAX && other.index == other.size());
|
||||
}
|
||||
bool operator!=(const const_iterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
const_iterator begin() const {
|
||||
if (index_ >= 0) {
|
||||
return const_iterator(global_id_storage_.at(index_));
|
||||
}
|
||||
return const_iterator(global_autoidx_id_prefix_storage_.at(index_), -index_);
|
||||
}
|
||||
const_iterator end() const {
|
||||
return const_iterator();
|
||||
}
|
||||
|
||||
Substrings substrings() const {
|
||||
if (index_ >= 0) {
|
||||
return Substrings(global_id_storage_.at(index_));
|
||||
}
|
||||
return Substrings(global_autoidx_id_prefix_storage_.at(index_), -index_);
|
||||
}
|
||||
|
||||
inline bool lt_by_name(const IdString &rhs) const {
|
||||
Substrings lhs_it = substrings();
|
||||
Substrings rhs_it = rhs.substrings();
|
||||
std::string_view lhs_substr = lhs_it.first();
|
||||
std::string_view rhs_substr = rhs_it.first();
|
||||
while (true) {
|
||||
int min = std::min(GetSize(lhs_substr), GetSize(rhs_substr));
|
||||
int diff = memcmp(lhs_substr.data(), rhs_substr.data(), min);
|
||||
if (diff != 0)
|
||||
return diff < 0;
|
||||
lhs_substr = lhs_substr.substr(min);
|
||||
rhs_substr = rhs_substr.substr(min);
|
||||
if (rhs_substr.empty()) {
|
||||
if (std::optional<std::string_view> s = rhs_it.next())
|
||||
rhs_substr = *s;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
if (lhs_substr.empty()) {
|
||||
if (std::optional<std::string_view> s = lhs_it.next())
|
||||
lhs_substr = *s;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool operator<(const IdString &rhs) const {
|
||||
return index_ < rhs.index_;
|
||||
}
|
||||
|
|
@ -284,30 +407,68 @@ struct RTLIL::IdString
|
|||
bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; }
|
||||
|
||||
char operator[](size_t i) const {
|
||||
const char *p = c_str();
|
||||
if (index_ >= 0) {
|
||||
const Storage &storage = global_id_storage_.at(index_);
|
||||
#ifndef NDEBUG
|
||||
for (; i != 0; i--, p++)
|
||||
log_assert(*p != 0);
|
||||
return *p;
|
||||
#else
|
||||
return *(p + i);
|
||||
log_assert(static_cast<int>(i) < storage.size);
|
||||
#endif
|
||||
return *(storage.buf + i);
|
||||
}
|
||||
const std::string &id_start = *global_autoidx_id_prefix_storage_.at(index_);
|
||||
if (i < id_start.size())
|
||||
return id_start[i];
|
||||
i -= id_start.size();
|
||||
std::string suffix = std::to_string(-index_);
|
||||
#ifndef NDEBUG
|
||||
// Allow indexing to access the trailing null.
|
||||
log_assert(i <= suffix.size());
|
||||
#endif
|
||||
return suffix[i];
|
||||
}
|
||||
|
||||
std::string substr(size_t pos = 0, size_t len = std::string::npos) const {
|
||||
if (len == std::string::npos || len + pos >= size())
|
||||
return std::string(c_str() + pos);
|
||||
else
|
||||
return std::string(c_str() + pos, len);
|
||||
std::string result;
|
||||
const_iterator it = begin() + pos;
|
||||
const_iterator end_it = end();
|
||||
if (len != std::string::npos && len < it.size() - pos) {
|
||||
end_it = it + len;
|
||||
}
|
||||
std::copy(it, end_it, std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
int compare(size_t pos, size_t len, const char* s) const {
|
||||
return strncmp(c_str()+pos, s, len);
|
||||
const_iterator it = begin() + pos;
|
||||
const_iterator end_it = end();
|
||||
while (len > 0 && *s != 0 && it != end_it) {
|
||||
int diff = *it - *s;
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
++it;
|
||||
++s;
|
||||
--len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool begins_with(std::string_view prefix) const {
|
||||
if (size() < prefix.size()) return false;
|
||||
return compare(0, prefix.size(), prefix.data()) == 0;
|
||||
Substrings it = substrings();
|
||||
std::string_view substr = it.first();
|
||||
while (true) {
|
||||
int min = std::min(GetSize(substr), GetSize(prefix));
|
||||
if (memcmp(substr.data(), prefix.data(), min) != 0)
|
||||
return false;
|
||||
prefix = prefix.substr(min);
|
||||
if (prefix.empty())
|
||||
return true;
|
||||
substr = substr.substr(min);
|
||||
if (substr.empty()) {
|
||||
if (std::optional<std::string_view> s = it.next())
|
||||
substr = *s;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ends_with(std::string_view suffix) const {
|
||||
|
|
@ -317,13 +478,13 @@ struct RTLIL::IdString
|
|||
}
|
||||
|
||||
bool contains(std::string_view s) const {
|
||||
return std::string_view(c_str()).find(s) != std::string::npos;
|
||||
if (index_ >= 0)
|
||||
return global_id_storage_.at(index_).str_view().find(s) != std::string::npos;
|
||||
return str().find(s) != std::string::npos;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
if (index_ >= 0)
|
||||
return global_id_storage_.at(index_).size;
|
||||
return strlen(c_str());
|
||||
return begin().size();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
|
|
@ -601,13 +762,13 @@ namespace RTLIL {
|
|||
|
||||
template <typename T> struct sort_by_name_str {
|
||||
bool operator()(T *a, T *b) const {
|
||||
return strcmp(a->name.c_str(), b->name.c_str()) < 0;
|
||||
return a->name.lt_by_name(b->name);
|
||||
}
|
||||
};
|
||||
|
||||
struct sort_by_id_str {
|
||||
bool operator()(const RTLIL::IdString &a, const RTLIL::IdString &b) const {
|
||||
return strcmp(a.c_str(), b.c_str()) < 0;
|
||||
return a.lt_by_name(b);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -373,6 +373,24 @@ namespace RTLIL {
|
|||
EXPECT_EQ(id, id2);
|
||||
}
|
||||
|
||||
TEST_F(KernelRtlilTest, NewIdBeginsWith) {
|
||||
IdString id = NEW_ID;
|
||||
EXPECT_TRUE(id.begins_with("$auto"));
|
||||
EXPECT_FALSE(id.begins_with("xyz"));
|
||||
EXPECT_TRUE(id.begins_with("$auto$"));
|
||||
EXPECT_FALSE(id.begins_with("abcdefghijklmn"));
|
||||
EXPECT_TRUE(id.begins_with("$auto$rtlilTest"));
|
||||
EXPECT_FALSE(id.begins_with("$auto$rtlilX"));
|
||||
}
|
||||
|
||||
TEST_F(KernelRtlilTest, NewIdIndexing) {
|
||||
IdString id = NEW_ID;
|
||||
std::string str = id.str();
|
||||
for (int i = 0; i < GetSize(str) + 1; ++i) {
|
||||
EXPECT_EQ(id[i], str.c_str()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
class WireRtlVsHdlIndexConversionTest :
|
||||
public KernelRtlilTest,
|
||||
public testing::WithParamInterface<std::tuple<bool, int, int>>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue