Coverage Report

Created: 2026-09-04 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/cacheddateformat.cpp
Line
Count
Source
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
146k
    formatter(dateFormat),
33
146k
    millisecondStart(0),
34
146k
    slotBegin(std::numeric_limits<log4cxx_time_t>::min()),
35
146k
    cache(50, 0x20),
36
146k
    expiration(expiration1),
37
146k
    previousTime(std::numeric_limits<log4cxx_time_t>::min())
38
146k
  {}
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
146k
  m_priv(std::make_unique<CachedDateFormatPriv>(dateFormat, expiration1))
128
146k
{
129
146k
  if (dateFormat == NULL)
130
0
  {
131
0
    throw NullPointerException(LOG4CXX_STR("dateFormat"));
132
0
  }
133
134
146k
  if (expiration1 < 0)
135
0
  {
136
0
    throw IllegalArgumentException(LOG4CXX_STR("expiration must be non-negative"));
137
0
  }
138
146k
}
139
140
146k
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
13.4k
{
156
157
13.4k
  log4cxx_time_t slotBegin = (time / 1000000) * 1000000;
158
159
13.4k
  if (slotBegin > time)
160
0
  {
161
0
    slotBegin -= 1000000;
162
0
  }
163
164
13.4k
  int millis = (int) (time - slotBegin) / 1000;
165
166
  // the magic numbers are in microseconds
167
13.4k
  int magic = magic1;
168
13.4k
  LogString magicString(magicString1);
169
170
13.4k
  if (millis == magic1 / 1000)
171
28
  {
172
28
    magic = magic2;
173
28
    magicString = magicString2;
174
28
  }
175
176
13.4k
  LogString plusMagic;
177
13.4k
  formatter->format(plusMagic, slotBegin + magic);
178
179
  /**
180
   *   If the string lengths differ then
181
   *      we can't use the cache except for duplicate requests.
182
   */
183
13.4k
  if (plusMagic.length() != formatted.length())
184
0
  {
185
0
    return UNRECOGNIZED_MILLISECONDS;
186
0
  }
187
13.4k
  else
188
13.4k
  {
189
    // find first difference between values
190
485k
    for (LogString::size_type i = 0; i < formatted.length(); i++)
191
478k
    {
192
478k
      if (formatted[i] != plusMagic[i])
193
6.70k
      {
194
        //
195
        //   determine the expected digits for the base time
196
6.70k
        const logchar abc[] = { 0x41, 0x42, 0x43, 0 };
197
6.70k
        LogString formattedMillis(abc);
198
6.70k
        millisecondFormat(millis, formattedMillis, 0);
199
200
6.70k
        LogString plusZero;
201
6.70k
        formatter->format(plusZero, slotBegin);
202
203
        // Test if the next 1..3 characters match the magic string, main problem is that magic
204
        // available millis in formatted can overlap. Therefore the current i is not always the
205
        // index of the first millis char, but may be already within the millis. Besides that
206
        // the millis can occur everywhere in formatted. See LOGCXX-420 and following.
207
6.70k
        size_t  magicLength     = magicString.length();
208
6.70k
        size_t  overlapping     = magicString.find(plusMagic[i]);
209
6.70k
        int     possibleRetVal  = int(i - overlapping);
210
211
6.70k
        if (plusZero.length() == formatted.length()
212
5.80k
          && regionMatches(magicString,       0, plusMagic,   possibleRetVal, magicLength)
213
5.80k
          && regionMatches(formattedMillis,   0, formatted,   possibleRetVal, magicLength)
214
5.80k
          && regionMatches(zeroString,        0, plusZero,    possibleRetVal, magicLength)
215
          // The following will and should fail for patterns with more than one SSS because
216
          // we only seem to be able to change one SSS in e.g. format and need to reformat the
217
          // whole string in other cases.
218
5.80k
          && (formatted.length() == possibleRetVal + magicLength
219
171
            || plusZero.compare(possibleRetVal + magicLength,
220
171
              LogString::npos, plusMagic, possibleRetVal + magicLength, LogString::npos) == 0))
221
5.75k
        {
222
5.75k
          return possibleRetVal;
223
5.75k
        }
224
950
        else
225
950
        {
226
950
          return UNRECOGNIZED_MILLISECONDS;
227
950
        }
228
6.70k
      }
229
478k
    }
230
13.4k
  }
231
232
6.73k
  return NO_MILLISECONDS;
233
13.4k
}
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&)
Line
Count
Source
155
5.95k
{
156
157
5.95k
  log4cxx_time_t slotBegin = (time / 1000000) * 1000000;
158
159
5.95k
  if (slotBegin > time)
160
0
  {
161
0
    slotBegin -= 1000000;
162
0
  }
163
164
5.95k
  int millis = (int) (time - slotBegin) / 1000;
165
166
  // the magic numbers are in microseconds
167
5.95k
  int magic = magic1;
168
5.95k
  LogString magicString(magicString1);
169
170
5.95k
  if (millis == magic1 / 1000)
171
12
  {
172
12
    magic = magic2;
173
12
    magicString = magicString2;
174
12
  }
175
176
5.95k
  LogString plusMagic;
177
5.95k
  formatter->format(plusMagic, slotBegin + magic);
178
179
  /**
180
   *   If the string lengths differ then
181
   *      we can't use the cache except for duplicate requests.
182
   */
183
5.95k
  if (plusMagic.length() != formatted.length())
184
0
  {
185
0
    return UNRECOGNIZED_MILLISECONDS;
186
0
  }
187
5.95k
  else
188
5.95k
  {
189
    // find first difference between values
190
223k
    for (LogString::size_type i = 0; i < formatted.length(); i++)
191
221k
    {
192
221k
      if (formatted[i] != plusMagic[i])
193
3.23k
      {
194
        //
195
        //   determine the expected digits for the base time
196
3.23k
        const logchar abc[] = { 0x41, 0x42, 0x43, 0 };
197
3.23k
        LogString formattedMillis(abc);
198
3.23k
        millisecondFormat(millis, formattedMillis, 0);
199
200
3.23k
        LogString plusZero;
201
3.23k
        formatter->format(plusZero, slotBegin);
202
203
        // Test if the next 1..3 characters match the magic string, main problem is that magic
204
        // available millis in formatted can overlap. Therefore the current i is not always the
205
        // index of the first millis char, but may be already within the millis. Besides that
206
        // the millis can occur everywhere in formatted. See LOGCXX-420 and following.
207
3.23k
        size_t  magicLength     = magicString.length();
208
3.23k
        size_t  overlapping     = magicString.find(plusMagic[i]);
209
3.23k
        int     possibleRetVal  = int(i - overlapping);
210
211
3.23k
        if (plusZero.length() == formatted.length()
212
2.79k
          && regionMatches(magicString,       0, plusMagic,   possibleRetVal, magicLength)
213
2.79k
          && regionMatches(formattedMillis,   0, formatted,   possibleRetVal, magicLength)
214
2.79k
          && regionMatches(zeroString,        0, plusZero,    possibleRetVal, magicLength)
215
          // The following will and should fail for patterns with more than one SSS because
216
          // we only seem to be able to change one SSS in e.g. format and need to reformat the
217
          // whole string in other cases.
218
2.79k
          && (formatted.length() == possibleRetVal + magicLength
219
94
            || plusZero.compare(possibleRetVal + magicLength,
220
94
              LogString::npos, plusMagic, possibleRetVal + magicLength, LogString::npos) == 0))
221
2.76k
        {
222
2.76k
          return possibleRetVal;
223
2.76k
        }
224
475
        else
225
475
        {
226
475
          return UNRECOGNIZED_MILLISECONDS;
227
475
        }
228
3.23k
      }
229
221k
    }
230
5.95k
  }
231
232
2.71k
  return NO_MILLISECONDS;
233
5.95k
}
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&)
Line
Count
Source
155
7.49k
{
156
157
7.49k
  log4cxx_time_t slotBegin = (time / 1000000) * 1000000;
158
159
7.49k
  if (slotBegin > time)
160
0
  {
161
0
    slotBegin -= 1000000;
162
0
  }
163
164
7.49k
  int millis = (int) (time - slotBegin) / 1000;
165
166
  // the magic numbers are in microseconds
167
7.49k
  int magic = magic1;
168
7.49k
  LogString magicString(magicString1);
169
170
7.49k
  if (millis == magic1 / 1000)
171
16
  {
172
16
    magic = magic2;
173
16
    magicString = magicString2;
174
16
  }
175
176
7.49k
  LogString plusMagic;
177
7.49k
  formatter->format(plusMagic, slotBegin + magic);
178
179
  /**
180
   *   If the string lengths differ then
181
   *      we can't use the cache except for duplicate requests.
182
   */
183
7.49k
  if (plusMagic.length() != formatted.length())
184
0
  {
185
0
    return UNRECOGNIZED_MILLISECONDS;
186
0
  }
187
7.49k
  else
188
7.49k
  {
189
    // find first difference between values
190
261k
    for (LogString::size_type i = 0; i < formatted.length(); i++)
191
257k
    {
192
257k
      if (formatted[i] != plusMagic[i])
193
3.47k
      {
194
        //
195
        //   determine the expected digits for the base time
196
3.47k
        const logchar abc[] = { 0x41, 0x42, 0x43, 0 };
197
3.47k
        LogString formattedMillis(abc);
198
3.47k
        millisecondFormat(millis, formattedMillis, 0);
199
200
3.47k
        LogString plusZero;
201
3.47k
        formatter->format(plusZero, slotBegin);
202
203
        // Test if the next 1..3 characters match the magic string, main problem is that magic
204
        // available millis in formatted can overlap. Therefore the current i is not always the
205
        // index of the first millis char, but may be already within the millis. Besides that
206
        // the millis can occur everywhere in formatted. See LOGCXX-420 and following.
207
3.47k
        size_t  magicLength     = magicString.length();
208
3.47k
        size_t  overlapping     = magicString.find(plusMagic[i]);
209
3.47k
        int     possibleRetVal  = int(i - overlapping);
210
211
3.47k
        if (plusZero.length() == formatted.length()
212
3.01k
          && regionMatches(magicString,       0, plusMagic,   possibleRetVal, magicLength)
213
3.01k
          && regionMatches(formattedMillis,   0, formatted,   possibleRetVal, magicLength)
214
3.01k
          && regionMatches(zeroString,        0, plusZero,    possibleRetVal, magicLength)
215
          // The following will and should fail for patterns with more than one SSS because
216
          // we only seem to be able to change one SSS in e.g. format and need to reformat the
217
          // whole string in other cases.
218
3.01k
          && (formatted.length() == possibleRetVal + magicLength
219
77
            || plusZero.compare(possibleRetVal + magicLength,
220
77
              LogString::npos, plusMagic, possibleRetVal + magicLength, LogString::npos) == 0))
221
2.99k
        {
222
2.99k
          return possibleRetVal;
223
2.99k
        }
224
475
        else
225
475
        {
226
475
          return UNRECOGNIZED_MILLISECONDS;
227
475
        }
228
3.47k
      }
229
257k
    }
230
7.49k
  }
231
232
4.01k
  return NO_MILLISECONDS;
233
7.49k
}
234
#if LOG4CXX_ABI_VERSION <= 15
235
int CachedDateFormat::findMillisecondStart(
236
  log4cxx_time_t time, const LogString& formatted,
237
  const DateFormatPtr& formatter,
238
  Pool& pool)
239
0
{
240
0
  return findMillisecondStart(time, formatted, formatter);
241
0
}
Unexecuted instantiation: 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&)
Unexecuted instantiation: 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&)
242
#endif
243
244
/**
245
 * Formats a millisecond count into a date/time string.
246
 *
247
 *  @param now Number of milliseconds after midnight 1 Jan 1970 GMT.
248
 *  @param sbuf the string buffer to write to
249
 */
250
void CachedDateFormat::format( LOG4CXX_FORMAT_TIME_FORMAL_PARAMETERS ) const
251
17.9k
{
252
253
  //
254
  // If the current requested time is identical to the previously
255
  //     requested time, then append the cache contents.
256
  //
257
17.9k
  if (tm == m_priv->previousTime)
258
0
  {
259
0
    toAppendTo.append(m_priv->cache);
260
0
    return;
261
0
  }
262
263
  //
264
  //   If millisecond pattern was not unrecognized
265
  //     (that is if it was found or milliseconds did not appear)
266
  //
267
17.9k
  if (m_priv->millisecondStart != UNRECOGNIZED_MILLISECONDS)
268
17.9k
  {
269
    //    Check if the cache is still valid.
270
    //    If the requested time is within the same integral second
271
    //       as the last request and a shorter expiration was not requested.
272
17.9k
    if (tm < m_priv->slotBegin + m_priv->expiration
273
4.50k
      && tm >= m_priv->slotBegin
274
4.49k
      && tm < m_priv->slotBegin + 1000000L)
275
4.49k
    {
276
      //
277
      //    if there was a millisecond field then update it
278
      //
279
4.49k
      if (m_priv->millisecondStart >= 0)
280
0
      {
281
0
        millisecondFormat((int) ((tm - m_priv->slotBegin) / 1000), m_priv->cache, m_priv->millisecondStart);
282
0
      }
283
284
      //
285
      //   update the previously requested time
286
      //      (the slot begin should be unchanged)
287
4.49k
      m_priv->previousTime = tm;
288
4.49k
      toAppendTo.append(m_priv->cache);
289
290
4.49k
      return;
291
4.49k
    }
292
17.9k
  }
293
294
  //
295
  //  could not use previous value.
296
  //    Call underlying formatter to format date.
297
13.4k
  m_priv->cache.erase(m_priv->cache.begin(), m_priv->cache.end());
298
13.4k
  m_priv->formatter->format(m_priv->cache, tm);
299
13.4k
  toAppendTo.append(m_priv->cache);
300
13.4k
  m_priv->previousTime = tm;
301
13.4k
  m_priv->slotBegin = (m_priv->previousTime / 1000000) * 1000000;
302
303
13.4k
  if (m_priv->slotBegin > m_priv->previousTime)
304
0
  {
305
0
    m_priv->slotBegin -= 1000000;
306
0
  }
307
308
  //
309
  //    if the milliseconds field was previous found
310
  //       then reevaluate in case it moved.
311
  //
312
13.4k
  if (m_priv->millisecondStart >= 0)
313
13.4k
  {
314
13.4k
    m_priv->millisecondStart = findMillisecondStart(tm, m_priv->cache, m_priv->formatter);
315
13.4k
  }
316
13.4k
}
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
251
7.79k
{
252
253
  //
254
  // If the current requested time is identical to the previously
255
  //     requested time, then append the cache contents.
256
  //
257
7.79k
  if (tm == m_priv->previousTime)
258
0
  {
259
0
    toAppendTo.append(m_priv->cache);
260
0
    return;
261
0
  }
262
263
  //
264
  //   If millisecond pattern was not unrecognized
265
  //     (that is if it was found or milliseconds did not appear)
266
  //
267
7.79k
  if (m_priv->millisecondStart != UNRECOGNIZED_MILLISECONDS)
268
7.79k
  {
269
    //    Check if the cache is still valid.
270
    //    If the requested time is within the same integral second
271
    //       as the last request and a shorter expiration was not requested.
272
7.79k
    if (tm < m_priv->slotBegin + m_priv->expiration
273
1.84k
      && tm >= m_priv->slotBegin
274
1.83k
      && tm < m_priv->slotBegin + 1000000L)
275
1.83k
    {
276
      //
277
      //    if there was a millisecond field then update it
278
      //
279
1.83k
      if (m_priv->millisecondStart >= 0)
280
0
      {
281
0
        millisecondFormat((int) ((tm - m_priv->slotBegin) / 1000), m_priv->cache, m_priv->millisecondStart);
282
0
      }
283
284
      //
285
      //   update the previously requested time
286
      //      (the slot begin should be unchanged)
287
1.83k
      m_priv->previousTime = tm;
288
1.83k
      toAppendTo.append(m_priv->cache);
289
290
1.83k
      return;
291
1.83k
    }
292
7.79k
  }
293
294
  //
295
  //  could not use previous value.
296
  //    Call underlying formatter to format date.
297
5.96k
  m_priv->cache.erase(m_priv->cache.begin(), m_priv->cache.end());
298
5.96k
  m_priv->formatter->format(m_priv->cache, tm);
299
5.96k
  toAppendTo.append(m_priv->cache);
300
5.96k
  m_priv->previousTime = tm;
301
5.96k
  m_priv->slotBegin = (m_priv->previousTime / 1000000) * 1000000;
302
303
5.96k
  if (m_priv->slotBegin > m_priv->previousTime)
304
0
  {
305
0
    m_priv->slotBegin -= 1000000;
306
0
  }
307
308
  //
309
  //    if the milliseconds field was previous found
310
  //       then reevaluate in case it moved.
311
  //
312
5.96k
  if (m_priv->millisecondStart >= 0)
313
5.95k
  {
314
5.95k
    m_priv->millisecondStart = findMillisecondStart(tm, m_priv->cache, m_priv->formatter);
315
5.95k
  }
316
5.96k
}
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
251
10.1k
{
252
253
  //
254
  // If the current requested time is identical to the previously
255
  //     requested time, then append the cache contents.
256
  //
257
10.1k
  if (tm == m_priv->previousTime)
258
0
  {
259
0
    toAppendTo.append(m_priv->cache);
260
0
    return;
261
0
  }
262
263
  //
264
  //   If millisecond pattern was not unrecognized
265
  //     (that is if it was found or milliseconds did not appear)
266
  //
267
10.1k
  if (m_priv->millisecondStart != UNRECOGNIZED_MILLISECONDS)
268
10.1k
  {
269
    //    Check if the cache is still valid.
270
    //    If the requested time is within the same integral second
271
    //       as the last request and a shorter expiration was not requested.
272
10.1k
    if (tm < m_priv->slotBegin + m_priv->expiration
273
2.66k
      && tm >= m_priv->slotBegin
274
2.65k
      && tm < m_priv->slotBegin + 1000000L)
275
2.65k
    {
276
      //
277
      //    if there was a millisecond field then update it
278
      //
279
2.65k
      if (m_priv->millisecondStart >= 0)
280
0
      {
281
0
        millisecondFormat((int) ((tm - m_priv->slotBegin) / 1000), m_priv->cache, m_priv->millisecondStart);
282
0
      }
283
284
      //
285
      //   update the previously requested time
286
      //      (the slot begin should be unchanged)
287
2.65k
      m_priv->previousTime = tm;
288
2.65k
      toAppendTo.append(m_priv->cache);
289
290
2.65k
      return;
291
2.65k
    }
292
10.1k
  }
293
294
  //
295
  //  could not use previous value.
296
  //    Call underlying formatter to format date.
297
7.50k
  m_priv->cache.erase(m_priv->cache.begin(), m_priv->cache.end());
298
7.50k
  m_priv->formatter->format(m_priv->cache, tm);
299
7.50k
  toAppendTo.append(m_priv->cache);
300
7.50k
  m_priv->previousTime = tm;
301
7.50k
  m_priv->slotBegin = (m_priv->previousTime / 1000000) * 1000000;
302
303
7.50k
  if (m_priv->slotBegin > m_priv->previousTime)
304
0
  {
305
0
    m_priv->slotBegin -= 1000000;
306
0
  }
307
308
  //
309
  //    if the milliseconds field was previous found
310
  //       then reevaluate in case it moved.
311
  //
312
7.50k
  if (m_priv->millisecondStart >= 0)
313
7.49k
  {
314
7.49k
    m_priv->millisecondStart = findMillisecondStart(tm, m_priv->cache, m_priv->formatter);
315
7.49k
  }
316
7.50k
}
317
318
/**
319
 *   Formats a count of milliseconds (0-999) into a numeric representation.
320
 *   @param millis Millisecond count between 0 and 999.
321
 *   @buf String buffer, may not be null.
322
 *   @offset Starting position in buffer, the length of the
323
 *       buffer must be at least offset + 3.
324
 */
325
void CachedDateFormat::millisecondFormat(int millis,
326
  LogString& buf,
327
  int offset)
328
6.70k
{
329
6.70k
  buf[offset] = digits[millis / 100];
330
6.70k
  buf[offset + 1] = digits[(millis / 10) % 10];
331
6.70k
  buf[offset + 2] = digits[millis  % 10];
332
6.70k
}
log4cxx::pattern::CachedDateFormat::millisecondFormat(int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, int)
Line
Count
Source
328
3.23k
{
329
3.23k
  buf[offset] = digits[millis / 100];
330
3.23k
  buf[offset + 1] = digits[(millis / 10) % 10];
331
3.23k
  buf[offset + 2] = digits[millis  % 10];
332
3.23k
}
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
328
3.47k
{
329
3.47k
  buf[offset] = digits[millis / 100];
330
3.47k
  buf[offset + 1] = digits[(millis / 10) % 10];
331
3.47k
  buf[offset + 2] = digits[millis  % 10];
332
3.47k
}
333
334
/**
335
 * Set timezone.
336
 *
337
 * @remarks Setting the timezone using getCalendar().setTimeZone()
338
 * will likely cause caching to misbehave.
339
 * @param timeZone TimeZone new timezone
340
 */
341
void CachedDateFormat::setTimeZone(const TimeZonePtr& timeZone)
342
0
{
343
0
  m_priv->formatter->setTimeZone(timeZone);
344
0
  m_priv->previousTime = std::numeric_limits<log4cxx_time_t>::min();
345
0
  m_priv->slotBegin = std::numeric_limits<log4cxx_time_t>::min();
346
0
}
347
348
349
350
void CachedDateFormat::numberFormat( LOG4CXX_FORMAT_NUMBER_FORMAL_PARAMETERS ) const
351
0
{
352
0
  m_priv->formatter->numberFormat(toAppendTo, n);
353
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
354
355
356
/**
357
 * Gets maximum cache validity for the specified SimpleDateTime
358
 *    conversion pattern.
359
 *  @param pattern conversion pattern, may not be null.
360
 *  @returns Duration in microseconds from an integral second
361
 *      that the cache will return consistent results.
362
 */
363
int CachedDateFormat::getMaximumCacheValidity(const LogString& pattern)
364
22.8k
{
365
  //
366
  //   If there are more "S" in the pattern than just one "SSS" then
367
  //      (for example, "HH:mm:ss,SSS SSS"), then set the expiration to
368
  //      one millisecond which should only perform duplicate request caching.
369
  //
370
22.8k
  const logchar S = 0x53;
371
22.8k
  const logchar SSS[] = { 0x53, 0x53, 0x53, 0 };
372
22.8k
  size_t firstS = pattern.find(S);
373
22.8k
  size_t len = pattern.length();
374
375
  //
376
  //   if there are no S's or
377
  //      three that start with the first S and no fourth S in the string
378
  //
379
22.8k
  if (firstS == LogString::npos ||
380
10.7k
    (len >= firstS + 3 && pattern.compare(firstS, 3, SSS) == 0
381
8.36k
      && (len == firstS + 3 ||
382
2.98k
        pattern.find(S, firstS + 3) == LogString::npos)))
383
18.5k
  {
384
18.5k
    return 1000000;
385
18.5k
  }
386
387
4.24k
  return 1000;
388
22.8k
}
log4cxx::pattern::CachedDateFormat::getMaximumCacheValidity(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
364
10.5k
{
365
  //
366
  //   If there are more "S" in the pattern than just one "SSS" then
367
  //      (for example, "HH:mm:ss,SSS SSS"), then set the expiration to
368
  //      one millisecond which should only perform duplicate request caching.
369
  //
370
10.5k
  const logchar S = 0x53;
371
10.5k
  const logchar SSS[] = { 0x53, 0x53, 0x53, 0 };
372
10.5k
  size_t firstS = pattern.find(S);
373
10.5k
  size_t len = pattern.length();
374
375
  //
376
  //   if there are no S's or
377
  //      three that start with the first S and no fourth S in the string
378
  //
379
10.5k
  if (firstS == LogString::npos ||
380
5.34k
    (len >= firstS + 3 && pattern.compare(firstS, 3, SSS) == 0
381
4.00k
      && (len == firstS + 3 ||
382
1.39k
        pattern.find(S, firstS + 3) == LogString::npos)))
383
8.21k
  {
384
8.21k
    return 1000000;
385
8.21k
  }
386
387
2.35k
  return 1000;
388
10.5k
}
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
364
12.2k
{
365
  //
366
  //   If there are more "S" in the pattern than just one "SSS" then
367
  //      (for example, "HH:mm:ss,SSS SSS"), then set the expiration to
368
  //      one millisecond which should only perform duplicate request caching.
369
  //
370
12.2k
  const logchar S = 0x53;
371
12.2k
  const logchar SSS[] = { 0x53, 0x53, 0x53, 0 };
372
12.2k
  size_t firstS = pattern.find(S);
373
12.2k
  size_t len = pattern.length();
374
375
  //
376
  //   if there are no S's or
377
  //      three that start with the first S and no fourth S in the string
378
  //
379
12.2k
  if (firstS == LogString::npos ||
380
5.44k
    (len >= firstS + 3 && pattern.compare(firstS, 3, SSS) == 0
381
4.36k
      && (len == firstS + 3 ||
382
1.59k
        pattern.find(S, firstS + 3) == LogString::npos)))
383
10.3k
  {
384
10.3k
    return 1000000;
385
10.3k
  }
386
387
1.88k
  return 1000;
388
12.2k
}
389
390
391
/**
392
* Tests if two string regions are equal.
393
* @param target target string.
394
* @param toffset character position in target to start comparison.
395
* @param other other string.
396
* @param ooffset character position in other to start comparison.
397
* @param len length of region.
398
* @return true if regions are equal.
399
*/
400
bool CachedDateFormat::regionMatches(
401
  const LogString& target,
402
  size_t toffset,
403
  const LogString& other,
404
  size_t ooffset,
405
  size_t len)
406
17.4k
{
407
17.4k
  return target.compare(toffset, len, other, ooffset, len) == 0;
408
17.4k
}
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
406
8.38k
{
407
8.38k
  return target.compare(toffset, len, other, ooffset, len) == 0;
408
8.38k
}
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
406
9.03k
{
407
9.03k
  return target.compare(toffset, len, other, ooffset, len) == 0;
408
9.03k
}
409