Line data Source code
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 223216 : class DigitGroupingIterator
62 : {
63 : const ::com::sun::star::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 165344 : void setInfinite()
70 : {
71 165344 : mnGroup = maGroupings.getLength();
72 165344 : }
73 :
74 165536 : bool isInfinite() const
75 : {
76 165536 : return mnGroup >= maGroupings.getLength();
77 : }
78 :
79 391933 : sal_Int32 getGrouping() const
80 : {
81 391933 : if (mnGroup < maGroupings.getLength())
82 : {
83 391933 : sal_Int32 n = maGroupings[mnGroup];
84 : SAL_WARN_IF( n < 0, "unotools.i18n", "DigitGroupingIterator::getGrouping: negative grouping");
85 391933 : if (n < 0)
86 0 : n = 0; // sanitize ...
87 391933 : return n;
88 : }
89 0 : return 0;
90 : }
91 :
92 391997 : void setPos()
93 : {
94 : // someone might be playing jokes on us, so check for overflow
95 391997 : if (mnNextPos <= SAL_MAX_INT32 - mnDigits)
96 391997 : mnNextPos += mnDigits;
97 391997 : }
98 :
99 391933 : void setDigits()
100 : {
101 391933 : sal_Int32 nPrev = mnDigits;
102 391933 : mnDigits = getGrouping();
103 391933 : if (!mnDigits)
104 : {
105 165344 : mnDigits = nPrev;
106 165344 : setInfinite();
107 : }
108 391933 : setPos();
109 391933 : }
110 :
111 226461 : void initGrouping()
112 : {
113 226461 : mnDigits = 3; // just in case of constructed with empty grouping
114 226461 : mnGroup = 0;
115 226461 : mnNextPos = 0;
116 226461 : setDigits();
117 226461 : }
118 :
119 : DigitGroupingIterator( const DigitGroupingIterator & ) SAL_DELETED_FUNCTION;
120 : DigitGroupingIterator & operator=( const DigitGroupingIterator & ) SAL_DELETED_FUNCTION;
121 :
122 : public:
123 :
124 223216 : explicit DigitGroupingIterator( const ::com::sun::star::uno::Sequence< sal_Int32 > & rGroupings )
125 223216 : : maGroupings( rGroupings)
126 : {
127 223216 : initGrouping();
128 223216 : }
129 :
130 : /** Advance iterator to next grouping. */
131 165536 : DigitGroupingIterator & advance()
132 : {
133 165536 : if (isInfinite())
134 64 : setPos();
135 : else
136 : {
137 165472 : ++mnGroup;
138 165472 : setDigits();
139 : }
140 165536 : return *this;
141 : }
142 :
143 : /** Obtain current grouping. Always > 0. */
144 1378 : sal_Int32 get() const
145 : {
146 1378 : return mnDigits;
147 : }
148 :
149 : /** The next position (in integer digits) from the right where to insert a
150 : group separator. */
151 708580 : sal_Int32 getPos()
152 : {
153 708580 : return mnNextPos;
154 : }
155 :
156 : /** Reset iterator to start again from the right beginning. */
157 3245 : void reset()
158 : {
159 3245 : initGrouping();
160 3245 : }
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 54673 : static ::com::sun::star::uno::Sequence< sal_Bool > createForwardSequence(
168 : sal_Int32 nIntegerDigits,
169 : const ::com::sun::star::uno::Sequence< sal_Int32 > & rGroupings )
170 : {
171 54673 : if (nIntegerDigits <= 0)
172 0 : return ::com::sun::star::uno::Sequence< sal_Bool >();
173 54673 : DigitGroupingIterator aIterator( rGroupings);
174 109346 : ::com::sun::star::uno::Sequence< sal_Bool > aSeq( nIntegerDigits);
175 54673 : sal_Bool* pArr = aSeq.getArray();
176 144504 : for (sal_Int32 j = 0; --nIntegerDigits >= 0; ++j)
177 : {
178 89831 : if (j == aIterator.getPos())
179 : {
180 298 : pArr[nIntegerDigits] = sal_True;
181 298 : aIterator.advance();
182 : }
183 : else
184 89533 : pArr[nIntegerDigits] = sal_False;
185 : }
186 109346 : return aSeq;
187 : }
188 : };
189 :
190 : } // namespace utl
191 :
192 : #endif // INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
193 :
194 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|