diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c index 09b3fd70b26..3b4cc393486 100644 --- a/gdb/dwarf2/cooked-index.c +++ b/gdb/dwarf2/cooked-index.c @@ -30,56 +30,43 @@ /* See cooked-index.h. */ -bool +int cooked_index_entry::compare (const char *stra, const char *strb, - bool completing) + comparison_mode mode) { - /* If we've ever matched "<" in both strings, then we disable the - special template parameter handling. */ - bool seen_lt = false; + auto munge = [] (char c) -> unsigned char + { + /* We want to sort '<' before any other printable character. + So, rewrite '<' to something just before ' '. */ + if (c == '<') + return '\x1f'; + return TOLOWER ((unsigned char) c); + }; while (*stra != '\0' && *strb != '\0' - && (TOLOWER ((unsigned char) *stra) - == TOLOWER ((unsigned char ) *strb))) + && (munge (*stra) == munge (*strb))) { - if (*stra == '<') - seen_lt = true; ++stra; ++strb; } - unsigned c1 = TOLOWER ((unsigned char) *stra); - unsigned c2 = TOLOWER ((unsigned char) *strb); + unsigned char c1 = munge (*stra); + unsigned char c2 = munge (*strb); - if (completing) + if (c1 == c2) + return 0; + + /* When completing, if STRB ends earlier than STRA, consider them as + equal. When comparing, if STRB ends earlier and STRA ends with + '<', consider them as equal. */ + if (mode == COMPLETE || (mode == MATCH && c1 == munge ('<'))) { - /* When completing, if one string ends earlier than the other, - consider them as equal. Also, completion mode ignores the - special '<' handling. */ - if (c1 == '\0' || c2 == '\0') - return false; - /* Fall through to the generic case. */ - } - else if (seen_lt) - { - /* Fall through to the generic case. */ - } - else if (c1 == '\0' || c1 == '<') - { - /* Maybe they both end at the same spot. */ - if (c2 == '\0' || c2 == '<') - return false; - /* First string ended earlier. */ - return true; - } - else if (c2 == '\0' || c2 == '<') - { - /* Second string ended earlier. */ - return false; + if (c2 == '\0') + return 0; } - return c1 < c2; + return c1 < c2 ? -1 : 1; } #if GDB_SELF_TEST @@ -89,45 +76,65 @@ namespace { void test_compare () { - SELF_CHECK (!cooked_index_entry::compare ("abcd", "abcd", false)); - SELF_CHECK (!cooked_index_entry::compare ("abcd", "abcd", false)); - SELF_CHECK (!cooked_index_entry::compare ("abcd", "abcd", true)); - SELF_CHECK (!cooked_index_entry::compare ("abcd", "abcd", true)); + /* Convenience aliases. */ + const auto mode_compare = cooked_index_entry::MATCH; + const auto mode_sort = cooked_index_entry::SORT; + const auto mode_complete = cooked_index_entry::COMPLETE; - SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE", false)); - SELF_CHECK (!cooked_index_entry::compare ("ABCDE", "abcd", false)); - SELF_CHECK (!cooked_index_entry::compare ("abcd", "ABCDE", true)); - SELF_CHECK (!cooked_index_entry::compare ("ABCDE", "abcd", true)); + SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd", + mode_compare) == 0); + SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd", + mode_complete) == 0); - SELF_CHECK (!cooked_index_entry::compare ("name", "name<>", false)); - SELF_CHECK (!cooked_index_entry::compare ("name<>", "name", false)); - SELF_CHECK (!cooked_index_entry::compare ("name", "name<>", true)); - SELF_CHECK (!cooked_index_entry::compare ("name<>", "name", true)); + SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE", + mode_compare) < 0); + SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd", + mode_compare) > 0); + SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE", + mode_complete) < 0); + SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd", + mode_complete) == 0); - SELF_CHECK (!cooked_index_entry::compare ("name", "name", false)); - SELF_CHECK (!cooked_index_entry::compare ("name", "name", false)); - SELF_CHECK (!cooked_index_entry::compare ("name", "name", true)); - SELF_CHECK (!cooked_index_entry::compare ("name", "name", true)); + SELF_CHECK (cooked_index_entry::compare ("name", "name<>", + mode_compare) < 0); + SELF_CHECK (cooked_index_entry::compare ("name<>", "name", + mode_compare) == 0); + SELF_CHECK (cooked_index_entry::compare ("name", "name<>", + mode_complete) < 0); + SELF_CHECK (cooked_index_entry::compare ("name<>", "name", + mode_complete) == 0); - SELF_CHECK (!cooked_index_entry::compare ("name>", - "name>", false)); + SELF_CHECK (cooked_index_entry::compare ("name", "name", + mode_compare) == 0); + SELF_CHECK (cooked_index_entry::compare ("name", "name", + mode_compare) > 0); + SELF_CHECK (cooked_index_entry::compare ("name", "name", + mode_complete) == 0); + SELF_CHECK (cooked_index_entry::compare ("name", "name", + mode_complete) > 0); - SELF_CHECK (!cooked_index_entry::compare ("name", "name>", false)); - SELF_CHECK (!cooked_index_entry::compare ("name>", "name", false)); - SELF_CHECK (cooked_index_entry::compare ("name>", - false)); - SELF_CHECK (!cooked_index_entry::compare ("name>", - true)); - SELF_CHECK (!cooked_index_entry::compare ("name>", "name>", "name>", + "name>", + mode_compare) == 0); - SELF_CHECK (cooked_index_entry::compare ("", "abcd", false)); - SELF_CHECK (!cooked_index_entry::compare ("", "abcd", true)); - SELF_CHECK (!cooked_index_entry::compare ("abcd", "", false)); - SELF_CHECK (!cooked_index_entry::compare ("abcd", "", true)); + SELF_CHECK (cooked_index_entry::compare ("name", "name>", + mode_compare) < 0); + SELF_CHECK (cooked_index_entry::compare ("name>", "name", + mode_compare) == 0); + SELF_CHECK (cooked_index_entry::compare ("name>", "name 0); + SELF_CHECK (cooked_index_entry::compare ("name>", "name 0); + SELF_CHECK (cooked_index_entry::compare ("abcd", "", mode_complete) == 0); + + SELF_CHECK (cooked_index_entry::compare ("func", "func", + mode_sort) < 0); + SELF_CHECK (cooked_index_entry::compare ("func", "func1", + mode_sort) < 0); } } /* anonymous namespace */ @@ -359,20 +366,22 @@ cooked_index::find (const std::string &name, bool completing) { wait (); + cooked_index_entry::comparison_mode mode = (completing + ? cooked_index_entry::COMPLETE + : cooked_index_entry::MATCH); + auto lower = std::lower_bound (m_entries.begin (), m_entries.end (), name, [=] (const cooked_index_entry *entry, const std::string &n) { - return cooked_index_entry::compare (entry->canonical, n.c_str (), - completing); + return cooked_index_entry::compare (entry->canonical, n.c_str (), mode) < 0; }); auto upper = std::upper_bound (m_entries.begin (), m_entries.end (), name, [=] (const std::string &n, const cooked_index_entry *entry) { - return cooked_index_entry::compare (n.c_str (), entry->canonical, - completing); + return cooked_index_entry::compare (entry->canonical, n.c_str (), mode) > 0; }); return range (lower, upper); diff --git a/gdb/dwarf2/cooked-index.h b/gdb/dwarf2/cooked-index.h index 2b34a6534e8..91adaa6ff04 100644 --- a/gdb/dwarf2/cooked-index.h +++ b/gdb/dwarf2/cooked-index.h @@ -143,16 +143,54 @@ struct cooked_index_entry : public allocate_on_obstack STORAGE. */ const char *full_name (struct obstack *storage) const; - /* Compare two strings, case-insensitively. Return true if STRA is - less than STRB. If one string has template parameters, but the - other does not, then they are considered to be equal; so for - example "t" == "t", "t" < "t", but "t" == "t". */ - static bool compare (const char *stra, const char *strb, bool completing); + /* Comparison modes for the 'compare' function. See the function + for a description. */ + enum comparison_mode + { + MATCH, + SORT, + COMPLETE, + }; + + /* Compare two strings, case-insensitively. Return -1 if STRA is + less than STRB, 0 if they are equal, and 1 if STRA is greater. + + When comparing, '<' is considered to be less than all other + printable characters. This ensures that "t" sorts before + "t1", which is necessary when looking up "t". This '<' handling + is to ensure that certain C++ lookups work correctly. It is + inexact, and applied regardless of the search language, but this + is ok because callers of this code do more precise filtering + according to their needs. This is also why using a + case-insensitive comparison works even for languages that are + case sensitive. + + MODE controls how the comparison proceeds. + + MODE==SORT is used when sorting and the only special '<' handling + that it does is to ensure that '<' sorts before all other + printable characters. This ensures that the resulting ordering + will be binary-searchable. + + MODE==MATCH is used when searching for a symbol. In this case, + STRB must always be the search name, and STRA must be the name in + the index that is under consideration. In compare mode, early + termination of STRB may match STRA -- for example, "t" and + "t" will be considered to be equal. (However, if A=="t" and + B=="t", then this will not consider them as equal.) + + MODE==COMPLETE is used when searching for a symbol for + completion. In this case, STRB must always be the search name, + and STRA must be the name in the index that is under + consideration. In completion mode, early termination of STRB + always results in a match. */ + static int compare (const char *stra, const char *strb, + comparison_mode mode); /* Compare two entries by canonical name. */ bool operator< (const cooked_index_entry &other) const { - return compare (canonical, other.canonical, false); + return compare (canonical, other.canonical, SORT) < 0; } /* The name as it appears in DWARF. This always points into one of