/src/logging-log4cxx/src/main/cpp/cacheddateformat.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
3 | | * contributor license agreements. See the NOTICE file distributed with |
4 | | * this work for additional information regarding copyright ownership. |
5 | | * The ASF licenses this file to You under the Apache License, Version 2.0 |
6 | | * (the "License"); you may not use this file except in compliance with |
7 | | * the License. You may obtain a copy of the License at |
8 | | * |
9 | | * http://www.apache.org/licenses/LICENSE-2.0 |
10 | | * |
11 | | * Unless required by applicable law or agreed to in writing, software |
12 | | * distributed under the License is distributed on an "AS IS" BASIS, |
13 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | | * See the License for the specific language governing permissions and |
15 | | * limitations under the License. |
16 | | */ |
17 | | #define __STDC_CONSTANT_MACROS |
18 | | #define NOMINMAX /* tell wnidows not to define min/max macros */ |
19 | | #include <log4cxx/logstring.h> |
20 | | #include <log4cxx/helpers/cacheddateformat.h> |
21 | | #include <log4cxx/helpers/pool.h> |
22 | | #include <limits> |
23 | | #include <log4cxx/helpers/exception.h> |
24 | | |
25 | | using namespace LOG4CXX_NS; |
26 | | using namespace LOG4CXX_NS::helpers; |
27 | | using namespace LOG4CXX_NS::pattern; |
28 | | |
29 | | struct CachedDateFormat::CachedDateFormatPriv |
30 | | { |
31 | | CachedDateFormatPriv(DateFormatPtr dateFormat, int expiration1) : |
32 | 114k | formatter(dateFormat), |
33 | 114k | millisecondStart(0), |
34 | 114k | slotBegin(std::numeric_limits<log4cxx_time_t>::min()), |
35 | 114k | cache(50, 0x20), |
36 | 114k | expiration(expiration1), |
37 | 114k | previousTime(std::numeric_limits<log4cxx_time_t>::min()) |
38 | 114k | {} |
39 | | |
40 | | /** |
41 | | * Wrapped formatter. |
42 | | */ |
43 | | LOG4CXX_NS::helpers::DateFormatPtr formatter; |
44 | | |
45 | | /** |
46 | | * Index of initial digit of millisecond pattern or |
47 | | * UNRECOGNIZED_MILLISECONDS or NO_MILLISECONDS. |
48 | | */ |
49 | | mutable int millisecondStart; |
50 | | |
51 | | /** |
52 | | * Integral second preceding the previous convered Date. |
53 | | */ |
54 | | mutable log4cxx_time_t slotBegin; |
55 | | |
56 | | |
57 | | /** |
58 | | * Cache of previous conversion. |
59 | | */ |
60 | | mutable LogString cache; |
61 | | |
62 | | |
63 | | /** |
64 | | * Maximum validity period for the cache. |
65 | | * Typically 1, use cache for duplicate requests only, or |
66 | | * 1000000, use cache for requests within the same integral second. |
67 | | */ |
68 | | const int expiration; |
69 | | |
70 | | /** |
71 | | * Date requested in previous conversion. |
72 | | */ |
73 | | mutable log4cxx_time_t previousTime; |
74 | | }; |
75 | | |
76 | | |
77 | | /** |
78 | | * Supported digit set. If the wrapped DateFormat uses |
79 | | * a different unit set, the millisecond pattern |
80 | | * will not be recognized and duplicate requests |
81 | | * will use the cache. |
82 | | */ |
83 | | const logchar CachedDateFormat::digits[] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0 }; |
84 | | |
85 | | |
86 | | /** |
87 | | * First magic number (in microseconds) used to detect |
88 | | * the millisecond position. |
89 | | */ |
90 | | const int CachedDateFormat::magic1 = 654000; |
91 | | |
92 | | |
93 | | /** |
94 | | * Expected representation of first magic number in milliseconds. |
95 | | */ |
96 | | const logchar CachedDateFormat::magicString1[] = { 0x36, 0x35, 0x34, 0 }; |
97 | | |
98 | | |
99 | | /** |
100 | | * Second magic number (in microseconds) used to detect |
101 | | * the millisecond position. |
102 | | */ |
103 | | const int CachedDateFormat::magic2 = 987000; |
104 | | |
105 | | |
106 | | /** |
107 | | * Expected representation of second magic number in milliseconds. |
108 | | */ |
109 | | const logchar CachedDateFormat::magicString2[] = { 0x39, 0x38, 0x37, 0}; |
110 | | |
111 | | |
112 | | /** |
113 | | * Expected representation of 0 milliseconds. |
114 | | */ |
115 | | const logchar CachedDateFormat::zeroString[] = { 0x30, 0x30, 0x30, 0 }; |
116 | | |
117 | | /** |
118 | | * Creates a new CachedDateFormat object. |
119 | | * @param dateFormat Date format, may not be null. |
120 | | * @param expiration maximum cached range in milliseconds. |
121 | | * If the dateFormat is known to be incompatible with the |
122 | | * caching algorithm, use a value of 0 to totally disable |
123 | | * caching or 1 to only use cache for duplicate requests. |
124 | | */ |
125 | | CachedDateFormat::CachedDateFormat(const DateFormatPtr& dateFormat, |
126 | | int expiration1) : |
127 | 114k | m_priv(std::make_unique<CachedDateFormatPriv>(dateFormat, expiration1)) |
128 | 114k | { |
129 | 114k | if (dateFormat == NULL) |
130 | 0 | { |
131 | 0 | throw IllegalArgumentException(LOG4CXX_STR("dateFormat cannot be null")); |
132 | 0 | } |
133 | | |
134 | 114k | if (expiration1 < 0) |
135 | 0 | { |
136 | 0 | throw IllegalArgumentException(LOG4CXX_STR("expiration must be non-negative")); |
137 | 0 | } |
138 | 114k | } |
139 | | |
140 | 114k | CachedDateFormat::~CachedDateFormat() {} |
141 | | |
142 | | |
143 | | /** |
144 | | * Finds start of millisecond field in formatted time. |
145 | | * @param time long time, must be integral number of seconds |
146 | | * @param formatted String corresponding formatted string |
147 | | * @param formatter DateFormat date format |
148 | | * @return int position in string of first digit of milliseconds, |
149 | | * -1 indicates no millisecond field, -2 indicates unrecognized |
150 | | * field (likely RelativeTimeDateFormat) |
151 | | */ |
152 | | int CachedDateFormat::findMillisecondStart( |
153 | | log4cxx_time_t time, const LogString& formatted, |
154 | | const DateFormatPtr& formatter, |
155 | | Pool& pool) |
156 | 4.99k | { |
157 | | |
158 | 4.99k | log4cxx_time_t slotBegin = (time / 1000000) * 1000000; |
159 | | |
160 | 4.99k | if (slotBegin > time) |
161 | 0 | { |
162 | 0 | slotBegin -= 1000000; |
163 | 0 | } |
164 | | |
165 | 4.99k | int millis = (int) (time - slotBegin) / 1000; |
166 | | |
167 | | // the magic numbers are in microseconds |
168 | 4.99k | int magic = magic1; |
169 | 4.99k | LogString magicString(magicString1); |
170 | | |
171 | 4.99k | if (millis == magic1 / 1000) |
172 | 0 | { |
173 | 0 | magic = magic2; |
174 | 0 | magicString = magicString2; |
175 | 0 | } |
176 | | |
177 | 4.99k | LogString plusMagic; |
178 | 4.99k | formatter->format(plusMagic, slotBegin + magic, pool); |
179 | | |
180 | | /** |
181 | | * If the string lengths differ then |
182 | | * we can't use the cache except for duplicate requests. |
183 | | */ |
184 | 4.99k | if (plusMagic.length() != formatted.length()) |
185 | 345 | { |
186 | 345 | return UNRECOGNIZED_MILLISECONDS; |
187 | 345 | } |
188 | 4.64k | else |
189 | 4.64k | { |
190 | | // find first difference between values |
191 | 230k | for (LogString::size_type i = 0; i < formatted.length(); i++) |
192 | 226k | { |
193 | 226k | if (formatted[i] != plusMagic[i]) |
194 | 1.29k | { |
195 | | // |
196 | | // determine the expected digits for the base time |
197 | 1.29k | const logchar abc[] = { 0x41, 0x42, 0x43, 0 }; |
198 | 1.29k | LogString formattedMillis(abc); |
199 | 1.29k | millisecondFormat(millis, formattedMillis, 0); |
200 | | |
201 | 1.29k | LogString plusZero; |
202 | 1.29k | formatter->format(plusZero, slotBegin, pool); |
203 | | |
204 | | // Test if the next 1..3 characters match the magic string, main problem is that magic |
205 | | // available millis in formatted can overlap. Therefore the current i is not always the |
206 | | // index of the first millis char, but may be already within the millis. Besides that |
207 | | // the millis can occur everywhere in formatted. See LOGCXX-420 and following. |
208 | 1.29k | size_t magicLength = magicString.length(); |
209 | 1.29k | size_t overlapping = magicString.find(plusMagic[i]); |
210 | 1.29k | int possibleRetVal = int(i - overlapping); |
211 | | |
212 | 1.29k | if (plusZero.length() == formatted.length() |
213 | 1.29k | && regionMatches(magicString, 0, plusMagic, possibleRetVal, magicLength) |
214 | 1.29k | && regionMatches(formattedMillis, 0, formatted, possibleRetVal, magicLength) |
215 | 1.29k | && regionMatches(zeroString, 0, plusZero, possibleRetVal, magicLength) |
216 | | // The following will and should fail for patterns with more than one SSS because |
217 | | // we only seem to be able to change one SSS in e.g. format and need to reformat the |
218 | | // whole string in other cases. |
219 | 1.29k | && (formatted.length() == possibleRetVal + magicLength |
220 | 808 | || plusZero.compare(possibleRetVal + magicLength, |
221 | 148 | LogString::npos, plusMagic, possibleRetVal + magicLength, LogString::npos) == 0)) |
222 | 753 | { |
223 | 753 | return possibleRetVal; |
224 | 753 | } |
225 | 542 | else |
226 | 542 | { |
227 | 542 | return UNRECOGNIZED_MILLISECONDS; |
228 | 542 | } |
229 | 1.29k | } |
230 | 226k | } |
231 | 4.64k | } |
232 | | |
233 | 3.35k | return NO_MILLISECONDS; |
234 | 4.99k | } log4cxx::pattern::CachedDateFormat::findMillisecondStart(long, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::shared_ptr<log4cxx::helpers::DateFormat> const&, log4cxx::helpers::Pool&) Line | Count | Source | 156 | 3.61k | { | 157 | | | 158 | 3.61k | log4cxx_time_t slotBegin = (time / 1000000) * 1000000; | 159 | | | 160 | 3.61k | if (slotBegin > time) | 161 | 0 | { | 162 | 0 | slotBegin -= 1000000; | 163 | 0 | } | 164 | | | 165 | 3.61k | int millis = (int) (time - slotBegin) / 1000; | 166 | | | 167 | | // the magic numbers are in microseconds | 168 | 3.61k | int magic = magic1; | 169 | 3.61k | LogString magicString(magicString1); | 170 | | | 171 | 3.61k | if (millis == magic1 / 1000) | 172 | 0 | { | 173 | 0 | magic = magic2; | 174 | 0 | magicString = magicString2; | 175 | 0 | } | 176 | | | 177 | 3.61k | LogString plusMagic; | 178 | 3.61k | formatter->format(plusMagic, slotBegin + magic, pool); | 179 | | | 180 | | /** | 181 | | * If the string lengths differ then | 182 | | * we can't use the cache except for duplicate requests. | 183 | | */ | 184 | 3.61k | if (plusMagic.length() != formatted.length()) | 185 | 171 | { | 186 | 171 | return UNRECOGNIZED_MILLISECONDS; | 187 | 171 | } | 188 | 3.43k | else | 189 | 3.43k | { | 190 | | // find first difference between values | 191 | 132k | for (LogString::size_type i = 0; i < formatted.length(); i++) | 192 | 129k | { | 193 | 129k | if (formatted[i] != plusMagic[i]) | 194 | 702 | { | 195 | | // | 196 | | // determine the expected digits for the base time | 197 | 702 | const logchar abc[] = { 0x41, 0x42, 0x43, 0 }; | 198 | 702 | LogString formattedMillis(abc); | 199 | 702 | millisecondFormat(millis, formattedMillis, 0); | 200 | | | 201 | 702 | LogString plusZero; | 202 | 702 | formatter->format(plusZero, slotBegin, pool); | 203 | | | 204 | | // Test if the next 1..3 characters match the magic string, main problem is that magic | 205 | | // available millis in formatted can overlap. Therefore the current i is not always the | 206 | | // index of the first millis char, but may be already within the millis. Besides that | 207 | | // the millis can occur everywhere in formatted. See LOGCXX-420 and following. | 208 | 702 | size_t magicLength = magicString.length(); | 209 | 702 | size_t overlapping = magicString.find(plusMagic[i]); | 210 | 702 | int possibleRetVal = int(i - overlapping); | 211 | | | 212 | 702 | if (plusZero.length() == formatted.length() | 213 | 702 | && regionMatches(magicString, 0, plusMagic, possibleRetVal, magicLength) | 214 | 702 | && regionMatches(formattedMillis, 0, formatted, possibleRetVal, magicLength) | 215 | 702 | && regionMatches(zeroString, 0, plusZero, possibleRetVal, magicLength) | 216 | | // The following will and should fail for patterns with more than one SSS because | 217 | | // we only seem to be able to change one SSS in e.g. format and need to reformat the | 218 | | // whole string in other cases. | 219 | 702 | && (formatted.length() == possibleRetVal + magicLength | 220 | 481 | || plusZero.compare(possibleRetVal + magicLength, | 221 | 85 | LogString::npos, plusMagic, possibleRetVal + magicLength, LogString::npos) == 0)) | 222 | 446 | { | 223 | 446 | return possibleRetVal; | 224 | 446 | } | 225 | 256 | else | 226 | 256 | { | 227 | 256 | return UNRECOGNIZED_MILLISECONDS; | 228 | 256 | } | 229 | 702 | } | 230 | 129k | } | 231 | 3.43k | } | 232 | | | 233 | 2.73k | return NO_MILLISECONDS; | 234 | 3.61k | } |
log4cxx::pattern::CachedDateFormat::findMillisecondStart(long, std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&, std::__1::shared_ptr<log4cxx::helpers::DateFormat> const&, log4cxx::helpers::Pool&) Line | Count | Source | 156 | 1.38k | { | 157 | | | 158 | 1.38k | log4cxx_time_t slotBegin = (time / 1000000) * 1000000; | 159 | | | 160 | 1.38k | if (slotBegin > time) | 161 | 0 | { | 162 | 0 | slotBegin -= 1000000; | 163 | 0 | } | 164 | | | 165 | 1.38k | int millis = (int) (time - slotBegin) / 1000; | 166 | | | 167 | | // the magic numbers are in microseconds | 168 | 1.38k | int magic = magic1; | 169 | 1.38k | LogString magicString(magicString1); | 170 | | | 171 | 1.38k | if (millis == magic1 / 1000) | 172 | 0 | { | 173 | 0 | magic = magic2; | 174 | 0 | magicString = magicString2; | 175 | 0 | } | 176 | | | 177 | 1.38k | LogString plusMagic; | 178 | 1.38k | formatter->format(plusMagic, slotBegin + magic, pool); | 179 | | | 180 | | /** | 181 | | * If the string lengths differ then | 182 | | * we can't use the cache except for duplicate requests. | 183 | | */ | 184 | 1.38k | if (plusMagic.length() != formatted.length()) | 185 | 174 | { | 186 | 174 | return UNRECOGNIZED_MILLISECONDS; | 187 | 174 | } | 188 | 1.20k | else | 189 | 1.20k | { | 190 | | // find first difference between values | 191 | 97.5k | for (LogString::size_type i = 0; i < formatted.length(); i++) | 192 | 96.9k | { | 193 | 96.9k | if (formatted[i] != plusMagic[i]) | 194 | 593 | { | 195 | | // | 196 | | // determine the expected digits for the base time | 197 | 593 | const logchar abc[] = { 0x41, 0x42, 0x43, 0 }; | 198 | 593 | LogString formattedMillis(abc); | 199 | 593 | millisecondFormat(millis, formattedMillis, 0); | 200 | | | 201 | 593 | LogString plusZero; | 202 | 593 | formatter->format(plusZero, slotBegin, pool); | 203 | | | 204 | | // Test if the next 1..3 characters match the magic string, main problem is that magic | 205 | | // available millis in formatted can overlap. Therefore the current i is not always the | 206 | | // index of the first millis char, but may be already within the millis. Besides that | 207 | | // the millis can occur everywhere in formatted. See LOGCXX-420 and following. | 208 | 593 | size_t magicLength = magicString.length(); | 209 | 593 | size_t overlapping = magicString.find(plusMagic[i]); | 210 | 593 | int possibleRetVal = int(i - overlapping); | 211 | | | 212 | 593 | if (plusZero.length() == formatted.length() | 213 | 593 | && regionMatches(magicString, 0, plusMagic, possibleRetVal, magicLength) | 214 | 593 | && regionMatches(formattedMillis, 0, formatted, possibleRetVal, magicLength) | 215 | 593 | && regionMatches(zeroString, 0, plusZero, possibleRetVal, magicLength) | 216 | | // The following will and should fail for patterns with more than one SSS because | 217 | | // we only seem to be able to change one SSS in e.g. format and need to reformat the | 218 | | // whole string in other cases. | 219 | 593 | && (formatted.length() == possibleRetVal + magicLength | 220 | 327 | || plusZero.compare(possibleRetVal + magicLength, | 221 | 63 | LogString::npos, plusMagic, possibleRetVal + magicLength, LogString::npos) == 0)) | 222 | 307 | { | 223 | 307 | return possibleRetVal; | 224 | 307 | } | 225 | 286 | else | 226 | 286 | { | 227 | 286 | return UNRECOGNIZED_MILLISECONDS; | 228 | 286 | } | 229 | 593 | } | 230 | 96.9k | } | 231 | 1.20k | } | 232 | | | 233 | 616 | return NO_MILLISECONDS; | 234 | 1.38k | } |
|
235 | | |
236 | | |
237 | | /** |
238 | | * Formats a millisecond count into a date/time string. |
239 | | * |
240 | | * @param now Number of milliseconds after midnight 1 Jan 1970 GMT. |
241 | | * @param sbuf the string buffer to write to |
242 | | */ |
243 | | void CachedDateFormat::format(LogString& buf, log4cxx_time_t now, Pool& p) const |
244 | 6.90k | { |
245 | | |
246 | | // |
247 | | // If the current requested time is identical to the previously |
248 | | // requested time, then append the cache contents. |
249 | | // |
250 | 6.90k | if (now == m_priv->previousTime) |
251 | 0 | { |
252 | 0 | buf.append(m_priv->cache); |
253 | 0 | return; |
254 | 0 | } |
255 | | |
256 | | // |
257 | | // If millisecond pattern was not unrecognized |
258 | | // (that is if it was found or milliseconds did not appear) |
259 | | // |
260 | 6.90k | if (m_priv->millisecondStart != UNRECOGNIZED_MILLISECONDS) |
261 | 6.90k | { |
262 | | // Check if the cache is still valid. |
263 | | // If the requested time is within the same integral second |
264 | | // as the last request and a shorter expiration was not requested. |
265 | 6.90k | if (now < m_priv->slotBegin + m_priv->expiration |
266 | 6.90k | && now >= m_priv->slotBegin |
267 | 6.90k | && now < m_priv->slotBegin + 1000000L) |
268 | 1.90k | { |
269 | | // |
270 | | // if there was a millisecond field then update it |
271 | | // |
272 | 1.90k | if (m_priv->millisecondStart >= 0) |
273 | 0 | { |
274 | 0 | millisecondFormat((int) ((now - m_priv->slotBegin) / 1000), m_priv->cache, m_priv->millisecondStart); |
275 | 0 | } |
276 | | |
277 | | // |
278 | | // update the previously requested time |
279 | | // (the slot begin should be unchanged) |
280 | 1.90k | m_priv->previousTime = now; |
281 | 1.90k | buf.append(m_priv->cache); |
282 | | |
283 | 1.90k | return; |
284 | 1.90k | } |
285 | 6.90k | } |
286 | | |
287 | | // |
288 | | // could not use previous value. |
289 | | // Call underlying formatter to format date. |
290 | 4.99k | m_priv->cache.erase(m_priv->cache.begin(), m_priv->cache.end()); |
291 | 4.99k | m_priv->formatter->format(m_priv->cache, now, p); |
292 | 4.99k | buf.append(m_priv->cache); |
293 | 4.99k | m_priv->previousTime = now; |
294 | 4.99k | m_priv->slotBegin = (m_priv->previousTime / 1000000) * 1000000; |
295 | | |
296 | 4.99k | if (m_priv->slotBegin > m_priv->previousTime) |
297 | 0 | { |
298 | 0 | m_priv->slotBegin -= 1000000; |
299 | 0 | } |
300 | | |
301 | | // |
302 | | // if the milliseconds field was previous found |
303 | | // then reevaluate in case it moved. |
304 | | // |
305 | 4.99k | if (m_priv->millisecondStart >= 0) |
306 | 4.99k | { |
307 | 4.99k | m_priv->millisecondStart = findMillisecondStart(now, m_priv->cache, m_priv->formatter, p); |
308 | 4.99k | } |
309 | 4.99k | } log4cxx::pattern::CachedDateFormat::format(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, long, log4cxx::helpers::Pool&) const Line | Count | Source | 244 | 5.51k | { | 245 | | | 246 | | // | 247 | | // If the current requested time is identical to the previously | 248 | | // requested time, then append the cache contents. | 249 | | // | 250 | 5.51k | if (now == m_priv->previousTime) | 251 | 0 | { | 252 | 0 | buf.append(m_priv->cache); | 253 | 0 | return; | 254 | 0 | } | 255 | | | 256 | | // | 257 | | // If millisecond pattern was not unrecognized | 258 | | // (that is if it was found or milliseconds did not appear) | 259 | | // | 260 | 5.51k | if (m_priv->millisecondStart != UNRECOGNIZED_MILLISECONDS) | 261 | 5.51k | { | 262 | | // Check if the cache is still valid. | 263 | | // If the requested time is within the same integral second | 264 | | // as the last request and a shorter expiration was not requested. | 265 | 5.51k | if (now < m_priv->slotBegin + m_priv->expiration | 266 | 5.51k | && now >= m_priv->slotBegin | 267 | 5.51k | && now < m_priv->slotBegin + 1000000L) | 268 | 1.90k | { | 269 | | // | 270 | | // if there was a millisecond field then update it | 271 | | // | 272 | 1.90k | if (m_priv->millisecondStart >= 0) | 273 | 0 | { | 274 | 0 | millisecondFormat((int) ((now - m_priv->slotBegin) / 1000), m_priv->cache, m_priv->millisecondStart); | 275 | 0 | } | 276 | | | 277 | | // | 278 | | // update the previously requested time | 279 | | // (the slot begin should be unchanged) | 280 | 1.90k | m_priv->previousTime = now; | 281 | 1.90k | buf.append(m_priv->cache); | 282 | | | 283 | 1.90k | return; | 284 | 1.90k | } | 285 | 5.51k | } | 286 | | | 287 | | // | 288 | | // could not use previous value. | 289 | | // Call underlying formatter to format date. | 290 | 3.61k | m_priv->cache.erase(m_priv->cache.begin(), m_priv->cache.end()); | 291 | 3.61k | m_priv->formatter->format(m_priv->cache, now, p); | 292 | 3.61k | buf.append(m_priv->cache); | 293 | 3.61k | m_priv->previousTime = now; | 294 | 3.61k | m_priv->slotBegin = (m_priv->previousTime / 1000000) * 1000000; | 295 | | | 296 | 3.61k | if (m_priv->slotBegin > m_priv->previousTime) | 297 | 0 | { | 298 | 0 | m_priv->slotBegin -= 1000000; | 299 | 0 | } | 300 | | | 301 | | // | 302 | | // if the milliseconds field was previous found | 303 | | // then reevaluate in case it moved. | 304 | | // | 305 | 3.61k | if (m_priv->millisecondStart >= 0) | 306 | 3.61k | { | 307 | 3.61k | m_priv->millisecondStart = findMillisecondStart(now, m_priv->cache, m_priv->formatter, p); | 308 | 3.61k | } | 309 | 3.61k | } |
log4cxx::pattern::CachedDateFormat::format(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >&, long, log4cxx::helpers::Pool&) const Line | Count | Source | 244 | 1.38k | { | 245 | | | 246 | | // | 247 | | // If the current requested time is identical to the previously | 248 | | // requested time, then append the cache contents. | 249 | | // | 250 | 1.38k | if (now == m_priv->previousTime) | 251 | 0 | { | 252 | 0 | buf.append(m_priv->cache); | 253 | 0 | return; | 254 | 0 | } | 255 | | | 256 | | // | 257 | | // If millisecond pattern was not unrecognized | 258 | | // (that is if it was found or milliseconds did not appear) | 259 | | // | 260 | 1.38k | if (m_priv->millisecondStart != UNRECOGNIZED_MILLISECONDS) | 261 | 1.38k | { | 262 | | // Check if the cache is still valid. | 263 | | // If the requested time is within the same integral second | 264 | | // as the last request and a shorter expiration was not requested. | 265 | 1.38k | if (now < m_priv->slotBegin + m_priv->expiration | 266 | 1.38k | && now >= m_priv->slotBegin | 267 | 1.38k | && now < m_priv->slotBegin + 1000000L) | 268 | 0 | { | 269 | | // | 270 | | // if there was a millisecond field then update it | 271 | | // | 272 | 0 | if (m_priv->millisecondStart >= 0) | 273 | 0 | { | 274 | 0 | millisecondFormat((int) ((now - m_priv->slotBegin) / 1000), m_priv->cache, m_priv->millisecondStart); | 275 | 0 | } | 276 | | | 277 | | // | 278 | | // update the previously requested time | 279 | | // (the slot begin should be unchanged) | 280 | 0 | m_priv->previousTime = now; | 281 | 0 | buf.append(m_priv->cache); | 282 | |
| 283 | 0 | return; | 284 | 0 | } | 285 | 1.38k | } | 286 | | | 287 | | // | 288 | | // could not use previous value. | 289 | | // Call underlying formatter to format date. | 290 | 1.38k | m_priv->cache.erase(m_priv->cache.begin(), m_priv->cache.end()); | 291 | 1.38k | m_priv->formatter->format(m_priv->cache, now, p); | 292 | 1.38k | buf.append(m_priv->cache); | 293 | 1.38k | m_priv->previousTime = now; | 294 | 1.38k | m_priv->slotBegin = (m_priv->previousTime / 1000000) * 1000000; | 295 | | | 296 | 1.38k | if (m_priv->slotBegin > m_priv->previousTime) | 297 | 0 | { | 298 | 0 | m_priv->slotBegin -= 1000000; | 299 | 0 | } | 300 | | | 301 | | // | 302 | | // if the milliseconds field was previous found | 303 | | // then reevaluate in case it moved. | 304 | | // | 305 | 1.38k | if (m_priv->millisecondStart >= 0) | 306 | 1.38k | { | 307 | 1.38k | m_priv->millisecondStart = findMillisecondStart(now, m_priv->cache, m_priv->formatter, p); | 308 | 1.38k | } | 309 | 1.38k | } |
|
310 | | |
311 | | /** |
312 | | * Formats a count of milliseconds (0-999) into a numeric representation. |
313 | | * @param millis Millisecond count between 0 and 999. |
314 | | * @buf String buffer, may not be null. |
315 | | * @offset Starting position in buffer, the length of the |
316 | | * buffer must be at least offset + 3. |
317 | | */ |
318 | | void CachedDateFormat::millisecondFormat(int millis, |
319 | | LogString& buf, |
320 | | int offset) |
321 | 1.29k | { |
322 | 1.29k | buf[offset] = digits[millis / 100]; |
323 | 1.29k | buf[offset + 1] = digits[(millis / 10) % 10]; |
324 | 1.29k | buf[offset + 2] = digits[millis % 10]; |
325 | 1.29k | } log4cxx::pattern::CachedDateFormat::millisecondFormat(int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, int) Line | Count | Source | 321 | 702 | { | 322 | 702 | buf[offset] = digits[millis / 100]; | 323 | 702 | buf[offset + 1] = digits[(millis / 10) % 10]; | 324 | 702 | buf[offset + 2] = digits[millis % 10]; | 325 | 702 | } |
log4cxx::pattern::CachedDateFormat::millisecondFormat(int, std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >&, int) Line | Count | Source | 321 | 593 | { | 322 | 593 | buf[offset] = digits[millis / 100]; | 323 | 593 | buf[offset + 1] = digits[(millis / 10) % 10]; | 324 | 593 | buf[offset + 2] = digits[millis % 10]; | 325 | 593 | } |
|
326 | | |
327 | | /** |
328 | | * Set timezone. |
329 | | * |
330 | | * @remarks Setting the timezone using getCalendar().setTimeZone() |
331 | | * will likely cause caching to misbehave. |
332 | | * @param timeZone TimeZone new timezone |
333 | | */ |
334 | | void CachedDateFormat::setTimeZone(const TimeZonePtr& timeZone) |
335 | 0 | { |
336 | 0 | m_priv->formatter->setTimeZone(timeZone); |
337 | 0 | m_priv->previousTime = std::numeric_limits<log4cxx_time_t>::min(); |
338 | 0 | m_priv->slotBegin = std::numeric_limits<log4cxx_time_t>::min(); |
339 | 0 | } |
340 | | |
341 | | |
342 | | |
343 | | void CachedDateFormat::numberFormat(LogString& s, int n, Pool& p) const |
344 | 0 | { |
345 | 0 | m_priv->formatter->numberFormat(s, n, p); |
346 | 0 | } Unexecuted instantiation: log4cxx::pattern::CachedDateFormat::numberFormat(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, int, log4cxx::helpers::Pool&) const Unexecuted instantiation: log4cxx::pattern::CachedDateFormat::numberFormat(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >&, int, log4cxx::helpers::Pool&) const |
347 | | |
348 | | |
349 | | /** |
350 | | * Gets maximum cache validity for the specified SimpleDateTime |
351 | | * conversion pattern. |
352 | | * @param pattern conversion pattern, may not be null. |
353 | | * @returns Duration in microseconds from an integral second |
354 | | * that the cache will return consistent results. |
355 | | */ |
356 | | int CachedDateFormat::getMaximumCacheValidity(const LogString& pattern) |
357 | 12.2k | { |
358 | | // |
359 | | // If there are more "S" in the pattern than just one "SSS" then |
360 | | // (for example, "HH:mm:ss,SSS SSS"), then set the expiration to |
361 | | // one millisecond which should only perform duplicate request caching. |
362 | | // |
363 | 12.2k | const logchar S = 0x53; |
364 | 12.2k | const logchar SSS[] = { 0x53, 0x53, 0x53, 0 }; |
365 | 12.2k | size_t firstS = pattern.find(S); |
366 | 12.2k | size_t len = pattern.length(); |
367 | | |
368 | | // |
369 | | // if there are no S's or |
370 | | // three that start with the first S and no fourth S in the string |
371 | | // |
372 | 12.2k | if (firstS == LogString::npos || |
373 | 12.2k | (len >= firstS + 3 && pattern.compare(firstS, 3, SSS) == 0 |
374 | 5.97k | && (len == firstS + 3 || |
375 | 3.71k | pattern.find(S, firstS + 3) == LogString::npos))) |
376 | 8.13k | { |
377 | 8.13k | return 1000000; |
378 | 8.13k | } |
379 | | |
380 | 4.09k | return 1000; |
381 | 12.2k | } log4cxx::pattern::CachedDateFormat::getMaximumCacheValidity(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) Line | Count | Source | 357 | 7.23k | { | 358 | | // | 359 | | // If there are more "S" in the pattern than just one "SSS" then | 360 | | // (for example, "HH:mm:ss,SSS SSS"), then set the expiration to | 361 | | // one millisecond which should only perform duplicate request caching. | 362 | | // | 363 | 7.23k | const logchar S = 0x53; | 364 | 7.23k | const logchar SSS[] = { 0x53, 0x53, 0x53, 0 }; | 365 | 7.23k | size_t firstS = pattern.find(S); | 366 | 7.23k | size_t len = pattern.length(); | 367 | | | 368 | | // | 369 | | // if there are no S's or | 370 | | // three that start with the first S and no fourth S in the string | 371 | | // | 372 | 7.23k | if (firstS == LogString::npos || | 373 | 7.23k | (len >= firstS + 3 && pattern.compare(firstS, 3, SSS) == 0 | 374 | 3.08k | && (len == firstS + 3 || | 375 | 1.94k | pattern.find(S, firstS + 3) == LogString::npos))) | 376 | 4.85k | { | 377 | 4.85k | return 1000000; | 378 | 4.85k | } | 379 | | | 380 | 2.37k | return 1000; | 381 | 7.23k | } |
log4cxx::pattern::CachedDateFormat::getMaximumCacheValidity(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&) Line | Count | Source | 357 | 5.00k | { | 358 | | // | 359 | | // If there are more "S" in the pattern than just one "SSS" then | 360 | | // (for example, "HH:mm:ss,SSS SSS"), then set the expiration to | 361 | | // one millisecond which should only perform duplicate request caching. | 362 | | // | 363 | 5.00k | const logchar S = 0x53; | 364 | 5.00k | const logchar SSS[] = { 0x53, 0x53, 0x53, 0 }; | 365 | 5.00k | size_t firstS = pattern.find(S); | 366 | 5.00k | size_t len = pattern.length(); | 367 | | | 368 | | // | 369 | | // if there are no S's or | 370 | | // three that start with the first S and no fourth S in the string | 371 | | // | 372 | 5.00k | if (firstS == LogString::npos || | 373 | 5.00k | (len >= firstS + 3 && pattern.compare(firstS, 3, SSS) == 0 | 374 | 2.89k | && (len == firstS + 3 || | 375 | 1.76k | pattern.find(S, firstS + 3) == LogString::npos))) | 376 | 3.28k | { | 377 | 3.28k | return 1000000; | 378 | 3.28k | } | 379 | | | 380 | 1.71k | return 1000; | 381 | 5.00k | } |
|
382 | | |
383 | | |
384 | | /** |
385 | | * Tests if two string regions are equal. |
386 | | * @param target target string. |
387 | | * @param toffset character position in target to start comparison. |
388 | | * @param other other string. |
389 | | * @param ooffset character position in other to start comparison. |
390 | | * @param len length of region. |
391 | | * @return true if regions are equal. |
392 | | */ |
393 | | bool CachedDateFormat::regionMatches( |
394 | | const LogString& target, |
395 | | size_t toffset, |
396 | | const LogString& other, |
397 | | size_t ooffset, |
398 | | size_t len) |
399 | 2.42k | { |
400 | 2.42k | return target.compare(toffset, len, other, ooffset, len) == 0; |
401 | 2.42k | } log4cxx::pattern::CachedDateFormat::regionMatches(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long, unsigned long) Line | Count | Source | 399 | 1.44k | { | 400 | 1.44k | return target.compare(toffset, len, other, ooffset, len) == 0; | 401 | 1.44k | } |
log4cxx::pattern::CachedDateFormat::regionMatches(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&, unsigned long, std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&, unsigned long, unsigned long) Line | Count | Source | 399 | 981 | { | 400 | 981 | return target.compare(toffset, len, other, ooffset, len) == 0; | 401 | 981 | } |
|
402 | | |