@@ -167,19 +167,25 @@ std::shared_ptr<arrow::Table> ArrowHelpers::concatTables(std::vector<std::shared
167167 return arrow::Table::Make (std::make_shared<arrow::Schema>(resultFields), columns);
168168}
169169
170+ // ASCII-only lowercase. Column labels are plain identifiers, so we deliberately
171+ // avoid the locale-aware std::tolower: it goes through the C locale facet on
172+ // every character and dominated getIndexFromLabel in profiles.
173+ static constexpr char asciiToLower (char c)
174+ {
175+ return (c >= ' A' && c <= ' Z' ) ? static_cast <char >(c + 32 ) : c;
176+ }
177+
170178arrow::ChunkedArray* getIndexFromLabel (arrow::Table* table, std::string_view label)
171179{
172- auto field = std::ranges::find_if (table->schema ()->fields (), [&](std::shared_ptr<arrow::Field> const & f) {
173- auto caseInsensitiveCompare = [](const std::string_view& str1, const std::string& str2) {
174- return std::ranges::equal (
175- str1, str2,
176- [](char c1, char c2) {
177- return std::tolower (static_cast <unsigned char >(c1)) ==
178- std::tolower (static_cast <unsigned char >(c2));
179- });
180- };
181-
182- return caseInsensitiveCompare (label, f->name ());
180+ // Take the exact-match common case first (string_view comparison checks length
181+ // then memcmp), and fall back to a case-insensitive scan only when the labels
182+ // differ in case.
183+ auto field = std::ranges::find_if (table->schema ()->fields (), [label](std::shared_ptr<arrow::Field> const & f) {
184+ std::string_view name = f->name ();
185+ return label == name ||
186+ std::ranges::equal (label, name, [](char c1, char c2) {
187+ return asciiToLower (c1) == asciiToLower (c2);
188+ });
183189 });
184190 if (field == table->schema ()->fields ().end ()) {
185191 o2::framework::throw_error (o2::framework::runtime_error_f (" Unable to find column with label %s." , label));
0 commit comments