logging: improve the AsyncFileWriter flush test()
[folly.git] / folly / experimental / logging / LogName.cpp
1 /*
2  * Copyright 2004-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <folly/experimental/logging/LogName.h>
17
18 namespace folly {
19
20 std::string LogName::canonicalize(StringPiece input) {
21   std::string cname;
22   cname.reserve(input.size());
23
24   // Ignore trailing '.'s
25   size_t end = input.size();
26   while (end > 0 && input[end - 1] == '.') {
27     --end;
28   }
29
30   bool ignoreDot = true;
31   for (size_t idx = 0; idx < end; ++idx) {
32     if (ignoreDot && input[idx] == '.') {
33       continue;
34     }
35     cname.push_back(input[idx]);
36     ignoreDot = (input[idx] == '.');
37   }
38   return cname;
39 }
40
41 size_t LogName::hash(StringPiece name) {
42   // Code based on StringPiece::hash(), but which ignores leading and
43   // trailing '.' characters, as well as multiple consecutive '.' characters,
44   // so equivalent names result in the same hash.
45   uint32_t hash = 5381;
46
47   size_t end = name.size();
48   while (end > 0 && name[end - 1] == '.') {
49     --end;
50   }
51
52   bool ignoreDot = true;
53   for (size_t idx = 0; idx < end; ++idx) {
54     if (ignoreDot && name[idx] == '.') {
55       continue;
56     }
57     hash = ((hash << 5) + hash) + name[idx];
58     // If this character was a '.', ignore subsequent consecutive '.'s
59     ignoreDot = (name[idx] == '.');
60   }
61   return hash;
62 }
63
64 int LogName::cmp(StringPiece a, StringPiece b) {
65   // Ignore trailing '.'s
66   auto stripTrailingDots = [](StringPiece& s) {
67     while (!s.empty() && s.back() == '.') {
68       s.uncheckedSubtract(1);
69     }
70   };
71   stripTrailingDots(a);
72   stripTrailingDots(b);
73
74   // Advance ptr until it no longer points to a '.'
75   // This is used to skip over consecutive sequences of '.' characters.
76   auto skipOverDots = [](StringPiece& s) {
77     while (!s.empty() && s.front() == '.') {
78       s.uncheckedAdvance(1);
79     }
80   };
81
82   bool ignoreDot = true;
83   while (true) {
84     if (ignoreDot) {
85       skipOverDots(a);
86       skipOverDots(b);
87     }
88     if (a.empty()) {
89       return b.empty() ? 0 : -1;
90     } else if (b.empty()) {
91       return 1;
92     }
93     if (a.front() != b.front()) {
94       return a.front() - b.front();
95     }
96     ignoreDot = (a.front() == '.');
97     a.uncheckedAdvance(1);
98     b.uncheckedAdvance(1);
99   }
100 }
101
102 StringPiece LogName::getParent(StringPiece name) {
103   if (name.empty()) {
104     return name;
105   }
106
107   ssize_t idx = name.size();
108
109   // Skip over any trailing '.' characters
110   while (idx > 0 && name[idx - 1] == '.') {
111     --idx;
112   }
113
114   // Now walk backwards to the next '.' character
115   while (idx > 0 && name[idx - 1] != '.') {
116     --idx;
117   }
118
119   // And again skip over any '.' characters, in case there are multiple
120   // repeated characters.
121   while (idx > 0 && name[idx - 1] == '.') {
122     --idx;
123   }
124
125   return StringPiece(name.begin(), idx);
126 }
127 }