Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/include/unotools/digitgroupingiterator.hxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#ifndef INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
21
#define INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
22
23
#include <com/sun/star/uno/Sequence.hxx>
24
#include <sal/log.hxx>
25
26
namespace utl {
27
28
/** Iterator to be used with a digit grouping as obtained through
29
    LocaleDataWrapper::getDigitGrouping().
30
31
    The iterator advances over the digit groupings, returning the number of
32
    digits per group. If the last group was encountered the iterator will
33
    always return the last grouping.
34
35
    Grouping values are sanitized to be >= 0, even if originally signed
36
    sal_Int32.
37
38
    Usage example with a string buffer containing a decimal representation of
39
    an integer number. Note that of course this loop could be optimized to not
40
    count single characters but hunks of groups instead using the get() method,
41
    this is just for illustrating usage. Anyway, for double values it is highly
42
    more efficient to use ::rtl::math::doubleToString() and pass the grouping
43
    sequence, instead of using this iterator and inserting characters into
44
    strings.
45
46
    DigitGroupingIterator aGrouping(...)
47
    sal_Int32 nCount = 0;
48
    sal_Int32 n = aBuffer.getLength();
49
    // >1 because we don't want to insert a separator if there is no leading digit.
50
    while (n-- > 1)
51
    {
52
        if (++nCount >= aGrouping.getPos())
53
        {
54
            aBuffer.insert( n, cSeparator);
55
            nGroupDigits = aGrouping.advance();
56
        }
57
    }
58
59
 */
60
61
class DigitGroupingIterator
62
{
63
    const css::uno::Sequence< sal_Int32 > maGroupings;
64
65
    sal_Int32   mnGroup;        // current active grouping
66
    sal_Int32   mnDigits;       // current active digits per group
67
    sal_Int32   mnNextPos;      // position (in digits) of next grouping
68
69
    void setInfinite()
70
9.20M
    {
71
9.20M
        mnGroup = maGroupings.getLength();
72
9.20M
    }
73
74
    bool isInfinite() const
75
9.98M
    {
76
9.98M
        return mnGroup >= maGroupings.getLength();
77
9.98M
    }
78
79
    sal_Int32 getGrouping() const
80
18.6M
    {
81
18.6M
        if (mnGroup < maGroupings.getLength())
82
18.6M
        {
83
18.6M
            sal_Int32 n = maGroupings[mnGroup];
84
18.6M
            SAL_WARN_IF( n < 0, "unotools.i18n", "DigitGroupingIterator::getGrouping: negative grouping");
85
18.6M
            if (n < 0)
86
0
                n = 0;      // sanitize ...
87
18.6M
            return n;
88
18.6M
        }
89
0
        return 0;
90
18.6M
    }
91
92
    void setPos()
93
19.4M
    {
94
        // someone might be playing jokes on us, so check for overflow
95
19.4M
        if (mnNextPos <= SAL_MAX_INT32 - mnDigits)
96
19.4M
            mnNextPos += mnDigits;
97
19.4M
    }
98
99
    void setDigits()
100
18.6M
    {
101
18.6M
        sal_Int32 nPrev = mnDigits;
102
18.6M
        mnDigits = getGrouping();
103
18.6M
        if (!mnDigits)
104
9.20M
        {
105
9.20M
            mnDigits = nPrev;
106
9.20M
            setInfinite();
107
9.20M
        }
108
18.6M
        setPos();
109
18.6M
    }
110
111
    void initGrouping()
112
9.45M
    {
113
9.45M
        mnDigits = 3;       // just in case of constructed with empty grouping
114
9.45M
        mnGroup = 0;
115
9.45M
        mnNextPos = 0;
116
9.45M
        setDigits();
117
9.45M
    }
118
119
    DigitGroupingIterator( const DigitGroupingIterator & ) = delete;
120
    DigitGroupingIterator & operator=( const DigitGroupingIterator & ) = delete;
121
122
public:
123
124
    explicit DigitGroupingIterator( const css::uno::Sequence< sal_Int32 > & rGroupings )
125
9.41M
        : maGroupings( rGroupings)
126
9.41M
    {
127
9.41M
        initGrouping();
128
9.41M
    }
129
130
    /** Advance iterator to next grouping. */
131
    DigitGroupingIterator & advance()
132
9.98M
    {
133
9.98M
        if (isInfinite())
134
749k
            setPos();
135
9.23M
        else
136
9.23M
        {
137
9.23M
            ++mnGroup;
138
9.23M
            setDigits();
139
9.23M
        }
140
9.98M
        return *this;
141
9.98M
    }
142
143
    /** Obtain current grouping. Always > 0. */
144
    sal_Int32 get() const
145
165k
    {
146
165k
        return mnDigits;
147
165k
    }
148
149
    /** The next position (in integer digits) from the right where to insert a
150
        group separator. */
151
    sal_Int32 getPos() const
152
37.3M
    {
153
37.3M
        return mnNextPos;
154
37.3M
    }
155
156
    /** Reset iterator to start again from the right beginning. */
157
    void reset()
158
38.0k
    {
159
38.0k
        initGrouping();
160
38.0k
    }
161
162
    /** Create a sequence of bool values containing positions where to add a
163
        separator when iterating forward over a string and copying digit per
164
        digit. For example, for grouping in thousands and nIntegerDigits==7 the
165
        sequence returned would be {1,0,0,1,0,0,0} so the caller would add a
166
        separator after the 1st and the 4th digit. */
167
    static css::uno::Sequence< sal_Bool > createForwardSequence(
168
            sal_Int32 nIntegerDigits,
169
            const css::uno::Sequence< sal_Int32 > & rGroupings )
170
0
    {
171
0
        if (nIntegerDigits <= 0)
172
0
            return css::uno::Sequence< sal_Bool >();
173
0
        DigitGroupingIterator aIterator( rGroupings);
174
0
        css::uno::Sequence< sal_Bool > aSeq( nIntegerDigits);
175
0
        sal_Bool* pArr = aSeq.getArray();
176
0
        for (sal_Int32 j = 0; --nIntegerDigits >= 0; ++j)
177
0
        {
178
0
            if (j == aIterator.getPos())
179
0
            {
180
0
                pArr[nIntegerDigits] = true;
181
0
                aIterator.advance();
182
0
            }
183
0
            else
184
0
                pArr[nIntegerDigits] = false;
185
0
        }
186
0
        return aSeq;
187
0
    }
188
};
189
190
} // namespace utl
191
192
#endif // INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
193
194
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */