Coverage Report

Created: 2026-07-30 07:12

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
153k
    formatter(dateFormat),
33
153k
    millisecondStart(0),
34
153k
    slotBegin(std::numeric_limits<log4cxx_time_t>::min()),
35
153k
    cache(50, 0x20),
36
153k
    expiration(expiration1),
37
153k
    previousTime(std::numeric_limits<log4cxx_time_t>::min())
38
153k
  {}
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
153k
  m_priv(std::make_unique<CachedDateFormatPriv>(dateFormat, expiration1))
128
153k
{
129
153k
  if (dateFormat == NULL)
130
0
  {
131
0
    throw NullPointerException(LOG4CXX_STR("dateFormat"));
132
0
  }
133
134
153k
  if (expiration1 < 0)
135
0
  {
136
0
    throw IllegalArgumentException(LOG4CXX_STR("expiration must be non-negative"));
137
0
  }
138
153k
}
139
140
153k
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
14.4k
{
156
157
14.4k
  log4cxx_time_t slotBegin = (time / 1000000) * 1000000;
158
159
14.4k
  if (slotBegin > time)
160
0
  {
161
0
    slotBegin -= 1000000;
162
0
  }
163
164
14.4k
  int millis = (int) (time - slotBegin) / 1000;
165
166
  // the magic numbers are in microseconds
167
14.4k
  int magic = magic1;
168
14.4k
  LogString magicString(magicString1);
169
170
14.4k
  if (millis == magic1 / 1000)
171
58
  {
172
58
    magic = magic2;
173
58
    magicString = magicString2;
174
58
  }
175
176
14.4k
  LogString plusMagic;
177
14.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
14.4k
  if (plusMagic.length() != formatted.length())
184
4
  {
185
4
    return UNRECOGNIZED_MILLISECONDS;
186
4
  }
187
14.4k
  else
188
14.4k
  {
189
    // find first difference between values
190
478k
    for (LogString::size_type i = 0; i < formatted.length(); i++)
191
470k
    {
192
470k
      if (formatted[i] != plusMagic[i])
193
6.64k
      {
194
        //
195
        //   determine the expected digits for the base time
196
6.64k
        const logchar abc[] = { 0x41, 0x42, 0x43, 0 };
197
6.64k
        LogString formattedMillis(abc);
198
6.64k
        millisecondFormat(millis, formattedMillis, 0);
199
200
6.64k
        LogString plusZero;
201
6.64k
        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.64k
        size_t  magicLength     = magicString.length();
208
6.64k
        size_t  overlapping     = magicString.find(plusMagic[i]);
209
6.64k
        int     possibleRetVal  = int(i - overlapping);
210
211
6.64k
        if (plusZero.length() == formatted.length()
212
5.77k
          && regionMatches(magicString,       0, plusMagic,   possibleRetVal, magicLength)
213
5.77k
          && regionMatches(formattedMillis,   0, formatted,   possibleRetVal, magicLength)
214
5.77k
          && 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.77k
          && (formatted.length() == possibleRetVal + magicLength
219
172
            || plusZero.compare(possibleRetVal + magicLength,
220
172
              LogString::npos, plusMagic, possibleRetVal + magicLength, LogString::npos) == 0))
221
5.72k
        {
222
5.72k
          return possibleRetVal;
223
5.72k
        }
224
921
        else
225
921
        {
226
921
          return UNRECOGNIZED_MILLISECONDS;
227
921
        }
228
6.64k
      }
229
470k
    }
230
14.4k
  }
231
232
7.82k
  return NO_MILLISECONDS;
233
14.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.84k
{
156
157
5.84k
  log4cxx_time_t slotBegin = (time / 1000000) * 1000000;
158
159
5.84k
  if (slotBegin > time)
160
0
  {
161
0
    slotBegin -= 1000000;
162
0
  }
163
164
5.84k
  int millis = (int) (time - slotBegin) / 1000;
165
166
  // the magic numbers are in microseconds
167
5.84k
  int magic = magic1;
168
5.84k
  LogString magicString(magicString1);
169
170
5.84k
  if (millis == magic1 / 1000)
171
28
  {
172
28
    magic = magic2;
173
28
    magicString = magicString2;
174
28
  }
175
176
5.84k
  LogString plusMagic;
177
5.84k
  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.84k
  if (plusMagic.length() != formatted.length())
184
0
  {
185
0
    return UNRECOGNIZED_MILLISECONDS;
186
0
  }
187
5.84k
  else
188
5.84k
  {
189
    // find first difference between values
190
216k
    for (LogString::size_type i = 0; i < formatted.length(); i++)
191
213k
    {
192
213k
      if (formatted[i] != plusMagic[i])
193
3.15k
      {
194
        //
195
        //   determine the expected digits for the base time
196
3.15k
        const logchar abc[] = { 0x41, 0x42, 0x43, 0 };
197
3.15k
        LogString formattedMillis(abc);
198
3.15k
        millisecondFormat(millis, formattedMillis, 0);
199
200
3.15k
        LogString plusZero;
201
3.15k
        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.15k
        size_t  magicLength     = magicString.length();
208
3.15k
        size_t  overlapping     = magicString.find(plusMagic[i]);
209
3.15k
        int     possibleRetVal  = int(i - overlapping);
210
211
3.15k
        if (plusZero.length() == formatted.length()
212
2.73k
          && regionMatches(magicString,       0, plusMagic,   possibleRetVal, magicLength)
213
2.73k
          && regionMatches(formattedMillis,   0, formatted,   possibleRetVal, magicLength)
214
2.73k
          && 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.73k
          && (formatted.length() == possibleRetVal + magicLength
219
97
            || plusZero.compare(possibleRetVal + magicLength,
220
97
              LogString::npos, plusMagic, possibleRetVal + magicLength, LogString::npos) == 0))
221
2.69k
        {
222
2.69k
          return possibleRetVal;
223
2.69k
        }
224
452
        else
225
452
        {
226
452
          return UNRECOGNIZED_MILLISECONDS;
227
452
        }
228
3.15k
      }
229
213k
    }
230
5.84k
  }
231
232
2.69k
  return NO_MILLISECONDS;
233
5.84k
}
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
8.63k
{
156
157
8.63k
  log4cxx_time_t slotBegin = (time / 1000000) * 1000000;
158
159
8.63k
  if (slotBegin > time)
160
0
  {
161
0
    slotBegin -= 1000000;
162
0
  }
163
164
8.63k
  int millis = (int) (time - slotBegin) / 1000;
165
166
  // the magic numbers are in microseconds
167
8.63k
  int magic = magic1;
168
8.63k
  LogString magicString(magicString1);
169
170
8.63k
  if (millis == magic1 / 1000)
171
30
  {
172
30
    magic = magic2;
173
30
    magicString = magicString2;
174
30
  }
175
176
8.63k
  LogString plusMagic;
177
8.63k
  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
8.63k
  if (plusMagic.length() != formatted.length())
184
4
  {
185
4
    return UNRECOGNIZED_MILLISECONDS;
186
4
  }
187
8.62k
  else
188
8.62k
  {
189
    // find first difference between values
190
261k
    for (LogString::size_type i = 0; i < formatted.length(); i++)
191
256k
    {
192
256k
      if (formatted[i] != plusMagic[i])
193
3.49k
      {
194
        //
195
        //   determine the expected digits for the base time
196
3.49k
        const logchar abc[] = { 0x41, 0x42, 0x43, 0 };
197
3.49k
        LogString formattedMillis(abc);
198
3.49k
        millisecondFormat(millis, formattedMillis, 0);
199
200
3.49k
        LogString plusZero;
201
3.49k
        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.49k
        size_t  magicLength     = magicString.length();
208
3.49k
        size_t  overlapping     = magicString.find(plusMagic[i]);
209
3.49k
        int     possibleRetVal  = int(i - overlapping);
210
211
3.49k
        if (plusZero.length() == formatted.length()
212
3.04k
          && regionMatches(magicString,       0, plusMagic,   possibleRetVal, magicLength)
213
3.04k
          && regionMatches(formattedMillis,   0, formatted,   possibleRetVal, magicLength)
214
3.04k
          && 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.04k
          && (formatted.length() == possibleRetVal + magicLength
219
75
            || plusZero.compare(possibleRetVal + magicLength,
220
75
              LogString::npos, plusMagic, possibleRetVal + magicLength, LogString::npos) == 0))
221
3.02k
        {
222
3.02k
          return possibleRetVal;
223
3.02k
        }
224
469
        else
225
469
        {
226
469
          return UNRECOGNIZED_MILLISECONDS;
227
469
        }
228
3.49k
      }
229
256k
    }
230
8.62k
  }
231
232
5.13k
  return NO_MILLISECONDS;
233
8.63k
}
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
19.9k
{
252
253
  //
254
  // If the current requested time is identical to the previously
255
  //     requested time, then append the cache contents.
256
  //
257
19.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
19.9k
  if (m_priv->millisecondStart != UNRECOGNIZED_MILLISECONDS)
268
19.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
19.9k
    if (tm < m_priv->slotBegin + m_priv->expiration
273
5.43k
      && tm >= m_priv->slotBegin
274
5.42k
      && tm < m_priv->slotBegin + 1000000L)
275
5.42k
    {
276
      //
277
      //    if there was a millisecond field then update it
278
      //
279
5.42k
      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
5.42k
      m_priv->previousTime = tm;
288
5.42k
      toAppendTo.append(m_priv->cache);
289
290
5.42k
      return;
291
5.42k
    }
292
19.9k
  }
293
294
  //
295
  //  could not use previous value.
296
  //    Call underlying formatter to format date.
297
14.4k
  m_priv->cache.erase(m_priv->cache.begin(), m_priv->cache.end());
298
14.4k
  m_priv->formatter->format(m_priv->cache, tm);
299
14.4k
  toAppendTo.append(m_priv->cache);
300
14.4k
  m_priv->previousTime = tm;
301
14.4k
  m_priv->slotBegin = (m_priv->previousTime / 1000000) * 1000000;
302
303
14.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
14.4k
  if (m_priv->millisecondStart >= 0)
313
14.4k
  {
314
14.4k
    m_priv->millisecondStart = findMillisecondStart(tm, m_priv->cache, m_priv->formatter);
315
14.4k
  }
316
14.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.68k
{
252
253
  //
254
  // If the current requested time is identical to the previously
255
  //     requested time, then append the cache contents.
256
  //
257
7.68k
  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.68k
  if (m_priv->millisecondStart != UNRECOGNIZED_MILLISECONDS)
268
7.68k
  {
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.68k
    if (tm < m_priv->slotBegin + m_priv->expiration
273
1.84k
      && tm >= m_priv->slotBegin
274
1.84k
      && tm < m_priv->slotBegin + 1000000L)
275
1.84k
    {
276
      //
277
      //    if there was a millisecond field then update it
278
      //
279
1.84k
      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.84k
      m_priv->previousTime = tm;
288
1.84k
      toAppendTo.append(m_priv->cache);
289
290
1.84k
      return;
291
1.84k
    }
292
7.68k
  }
293
294
  //
295
  //  could not use previous value.
296
  //    Call underlying formatter to format date.
297
5.84k
  m_priv->cache.erase(m_priv->cache.begin(), m_priv->cache.end());
298
5.84k
  m_priv->formatter->format(m_priv->cache, tm);
299
5.84k
  toAppendTo.append(m_priv->cache);
300
5.84k
  m_priv->previousTime = tm;
301
5.84k
  m_priv->slotBegin = (m_priv->previousTime / 1000000) * 1000000;
302
303
5.84k
  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.84k
  if (m_priv->millisecondStart >= 0)
313
5.84k
  {
314
5.84k
    m_priv->millisecondStart = findMillisecondStart(tm, m_priv->cache, m_priv->formatter);
315
5.84k
  }
316
5.84k
}
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
12.2k
{
252
253
  //
254
  // If the current requested time is identical to the previously
255
  //     requested time, then append the cache contents.
256
  //
257
12.2k
  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
12.2k
  if (m_priv->millisecondStart != UNRECOGNIZED_MILLISECONDS)
268
12.2k
  {
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
12.2k
    if (tm < m_priv->slotBegin + m_priv->expiration
273
3.58k
      && tm >= m_priv->slotBegin
274
3.58k
      && tm < m_priv->slotBegin + 1000000L)
275
3.58k
    {
276
      //
277
      //    if there was a millisecond field then update it
278
      //
279
3.58k
      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
3.58k
      m_priv->previousTime = tm;
288
3.58k
      toAppendTo.append(m_priv->cache);
289
290
3.58k
      return;
291
3.58k
    }
292
12.2k
  }
293
294
  //
295
  //  could not use previous value.
296
  //    Call underlying formatter to format date.
297
8.64k
  m_priv->cache.erase(m_priv->cache.begin(), m_priv->cache.end());
298
8.64k
  m_priv->formatter->format(m_priv->cache, tm);
299
8.64k
  toAppendTo.append(m_priv->cache);
300
8.64k
  m_priv->previousTime = tm;
301
8.64k
  m_priv->slotBegin = (m_priv->previousTime / 1000000) * 1000000;
302
303
8.64k
  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
8.64k
  if (m_priv->millisecondStart >= 0)
313
8.63k
  {
314
8.63k
    m_priv->millisecondStart = findMillisecondStart(tm, m_priv->cache, m_priv->formatter);
315
8.63k
  }
316
8.64k
}
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.64k
{
329
6.64k
  buf[offset] = digits[millis / 100];
330
6.64k
  buf[offset + 1] = digits[(millis / 10) % 10];
331
6.64k
  buf[offset + 2] = digits[millis  % 10];
332
6.64k
}
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.15k
{
329
3.15k
  buf[offset] = digits[millis / 100];
330
3.15k
  buf[offset + 1] = digits[(millis / 10) % 10];
331
3.15k
  buf[offset + 2] = digits[millis  % 10];
332
3.15k
}
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.49k
{
329
3.49k
  buf[offset] = digits[millis / 100];
330
3.49k
  buf[offset + 1] = digits[(millis / 10) % 10];
331
3.49k
  buf[offset + 2] = digits[millis  % 10];
332
3.49k
}
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
25.3k
{
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
25.3k
  const logchar S = 0x53;
371
25.3k
  const logchar SSS[] = { 0x53, 0x53, 0x53, 0 };
372
25.3k
  size_t firstS = pattern.find(S);
373
25.3k
  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
25.3k
  if (firstS == LogString::npos ||
380
11.3k
    (len >= firstS + 3 && pattern.compare(firstS, 3, SSS) == 0
381
8.86k
      && (len == firstS + 3 ||
382
3.61k
        pattern.find(S, firstS + 3) == LogString::npos)))
383
20.8k
  {
384
20.8k
    return 1000000;
385
20.8k
  }
386
387
4.47k
  return 1000;
388
25.3k
}
log4cxx::pattern::CachedDateFormat::getMaximumCacheValidity(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
364
10.6k
{
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.6k
  const logchar S = 0x53;
371
10.6k
  const logchar SSS[] = { 0x53, 0x53, 0x53, 0 };
372
10.6k
  size_t firstS = pattern.find(S);
373
10.6k
  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.6k
  if (firstS == LogString::npos ||
380
5.26k
    (len >= firstS + 3 && pattern.compare(firstS, 3, SSS) == 0
381
3.96k
      && (len == firstS + 3 ||
382
1.53k
        pattern.find(S, firstS + 3) == LogString::npos)))
383
8.22k
  {
384
8.22k
    return 1000000;
385
8.22k
  }
386
387
2.39k
  return 1000;
388
10.6k
}
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
14.7k
{
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
14.7k
  const logchar S = 0x53;
371
14.7k
  const logchar SSS[] = { 0x53, 0x53, 0x53, 0 };
372
14.7k
  size_t firstS = pattern.find(S);
373
14.7k
  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
14.7k
  if (firstS == LogString::npos ||
380
6.06k
    (len >= firstS + 3 && pattern.compare(firstS, 3, SSS) == 0
381
4.89k
      && (len == firstS + 3 ||
382
2.07k
        pattern.find(S, firstS + 3) == LogString::npos)))
383
12.6k
  {
384
12.6k
    return 1000000;
385
12.6k
  }
386
387
2.08k
  return 1000;
388
14.7k
}
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.3k
{
407
17.3k
  return target.compare(toffset, len, other, ooffset, len) == 0;
408
17.3k
}
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.20k
{
407
8.20k
  return target.compare(toffset, len, other, ooffset, len) == 0;
408
8.20k
}
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.12k
{
407
9.12k
  return target.compare(toffset, len, other, ooffset, len) == 0;
408
9.12k
}
409