/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include namespace { constexpr bool isSeparator(char c) { return c == '.' || c == '/' || c == '\\'; } } // namespace namespace folly { std::string LogName::canonicalize(StringPiece input) { std::string cname; cname.reserve(input.size()); // Ignore trailing category separator characters size_t end = input.size(); while (end > 0 && isSeparator(input[end - 1])) { --end; } bool ignoreSeparator = true; for (size_t idx = 0; idx < end; ++idx) { if (isSeparator(input[idx])) { if (ignoreSeparator) { continue; } cname.push_back('.'); ignoreSeparator = true; } else { cname.push_back(input[idx]); ignoreSeparator = false; } } return cname; } size_t LogName::hash(StringPiece name) { // Code based on StringPiece::hash(), but which ignores leading and trailing // category separator characters, as well as multiple consecutive separator // characters, so equivalent names result in the same hash. uint32_t hash = 5381; size_t end = name.size(); while (end > 0 && isSeparator(name[end - 1])) { --end; } bool ignoreSeparator = true; for (size_t idx = 0; idx < end; ++idx) { uint8_t value; if (isSeparator(name[idx])) { if (ignoreSeparator) { continue; } value = '.'; ignoreSeparator = true; } else { value = static_cast(name[idx]); ignoreSeparator = false; } hash = ((hash << 5) + hash) + value; } return hash; } int LogName::cmp(StringPiece a, StringPiece b) { // Ignore trailing separators auto stripTrailingSeparators = [](StringPiece& s) { while (!s.empty() && isSeparator(s.back())) { s.uncheckedSubtract(1); } }; stripTrailingSeparators(a); stripTrailingSeparators(b); // Advance ptr until it no longer points to a category separator. // This is used to skip over consecutive sequences of separator characters. auto skipOverSeparators = [](StringPiece& s) { while (!s.empty() && isSeparator(s.front())) { s.uncheckedAdvance(1); } }; bool ignoreSeparator = true; while (true) { if (ignoreSeparator) { skipOverSeparators(a); skipOverSeparators(b); } if (a.empty()) { return b.empty() ? 0 : -1; } else if (b.empty()) { return 1; } if (isSeparator(a.front())) { if (!isSeparator(b.front())) { return '.' - b.front(); } ignoreSeparator = true; } else { if (a.front() != b.front()) { return a.front() - b.front(); } ignoreSeparator = false; } a.uncheckedAdvance(1); b.uncheckedAdvance(1); } } StringPiece LogName::getParent(StringPiece name) { if (name.empty()) { return name; } ssize_t idx = name.size(); // Skip over any trailing separator characters while (idx > 0 && isSeparator(name[idx - 1])) { --idx; } // Now walk backwards to the next separator character while (idx > 0 && !isSeparator(name[idx - 1])) { --idx; } // And again skip over any separator characters, in case there are multiple // repeated characters. while (idx > 0 && isSeparator(name[idx - 1])) { --idx; } return StringPiece(name.begin(), idx); } } // namespace folly