mirror of
https://github.com/YosysHQ/yosys
synced 2025-11-05 13:56:04 +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 {
|
struct Storage {
|
||||||
char *buf;
|
char *buf;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
|
std::string_view str_view() const { return {buf, static_cast<size_t>(size)}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef YOSYS_XTRACE_GET_PUT
|
#undef YOSYS_XTRACE_GET_PUT
|
||||||
|
|
@ -260,14 +262,135 @@ struct RTLIL::IdString
|
||||||
|
|
||||||
inline void append_to(std::string *out) const {
|
inline void append_to(std::string *out) const {
|
||||||
if (index_ >= 0) {
|
if (index_ >= 0) {
|
||||||
const Storage &storage = global_id_storage_.at(index_);
|
*out += global_id_storage_.at(index_).str_view();
|
||||||
*out += std::string_view(storage.buf, storage.size);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*out += *global_autoidx_id_prefix_storage_.at(index_);
|
*out += *global_autoidx_id_prefix_storage_.at(index_);
|
||||||
*out += std::to_string(-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 {
|
inline bool operator<(const IdString &rhs) const {
|
||||||
return index_ < rhs.index_;
|
return index_ < rhs.index_;
|
||||||
}
|
}
|
||||||
|
|
@ -284,30 +407,68 @@ struct RTLIL::IdString
|
||||||
bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; }
|
bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; }
|
||||||
|
|
||||||
char operator[](size_t i) const {
|
char operator[](size_t i) const {
|
||||||
const char *p = c_str();
|
if (index_ >= 0) {
|
||||||
|
const Storage &storage = global_id_storage_.at(index_);
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
for (; i != 0; i--, p++)
|
log_assert(static_cast<int>(i) < storage.size);
|
||||||
log_assert(*p != 0);
|
|
||||||
return *p;
|
|
||||||
#else
|
|
||||||
return *(p + i);
|
|
||||||
#endif
|
#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 {
|
std::string substr(size_t pos = 0, size_t len = std::string::npos) const {
|
||||||
if (len == std::string::npos || len + pos >= size())
|
std::string result;
|
||||||
return std::string(c_str() + pos);
|
const_iterator it = begin() + pos;
|
||||||
else
|
const_iterator end_it = end();
|
||||||
return std::string(c_str() + pos, len);
|
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 {
|
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 {
|
bool begins_with(std::string_view prefix) const {
|
||||||
if (size() < prefix.size()) return false;
|
Substrings it = substrings();
|
||||||
return compare(0, prefix.size(), prefix.data()) == 0;
|
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 {
|
bool ends_with(std::string_view suffix) const {
|
||||||
|
|
@ -317,13 +478,13 @@ struct RTLIL::IdString
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contains(std::string_view s) const {
|
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 {
|
size_t size() const {
|
||||||
if (index_ >= 0)
|
return begin().size();
|
||||||
return global_id_storage_.at(index_).size;
|
|
||||||
return strlen(c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const {
|
bool empty() const {
|
||||||
|
|
@ -601,13 +762,13 @@ namespace RTLIL {
|
||||||
|
|
||||||
template <typename T> struct sort_by_name_str {
|
template <typename T> struct sort_by_name_str {
|
||||||
bool operator()(T *a, T *b) const {
|
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 {
|
struct sort_by_id_str {
|
||||||
bool operator()(const RTLIL::IdString &a, const RTLIL::IdString &b) const {
|
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);
|
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 :
|
class WireRtlVsHdlIndexConversionTest :
|
||||||
public KernelRtlilTest,
|
public KernelRtlilTest,
|
||||||
public testing::WithParamInterface<std::tuple<bool, int, int>>
|
public testing::WithParamInterface<std::tuple<bool, int, int>>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue