Coverage Report

Created: 2025-07-11 07:00

/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