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 :
25 : namespace utl {
26 :
27 : /** Iterator to be used with a digit grouping as obtained through
28 : LocaleDataWrapper::getDigitGrouping().
29 :
30 : The iterator advances over the digit groupings, returning the number of
31 : digits per group. If the last group was encountered the iterator will
32 : always return the last grouping.
33 :
34 : Grouping values are sanitized to be >= 0, even if originally signed
35 : sal_Int32.
36 :
37 : Usage example with a string buffer containing a decimal representation of
38 : an integer number. Note that of course this loop could be optimized to not
39 : count single characters but hunks of groups instead using the get() method,
40 : this is just for illustrating usage. Anyway, for double values it is highly
41 : more efficient to use ::rtl::math::doubleToString() and pass the grouping
42 : sequence, instead of using this iterator and inserting characters into
43 : strings.
44 :
45 : DigitGroupingIterator aGrouping(...)
46 : sal_Int32 nCount = 0;
47 : sal_Int32 n = aBuffer.getLength();
48 : // >1 because we don't want to insert a separator if there is no leading digit.
49 : while (n-- > 1)
50 : {
51 : if (++nCount >= aGrouping.getPos())
52 : {
53 : aBuffer.insert( n, cSeparator);
54 : nGroupDigits = aGrouping.advance();
55 : }
56 : }
57 :
58 : */
59 :
60 370284 : class DigitGroupingIterator
61 : {
62 : const ::com::sun::star::uno::Sequence< sal_Int32 > maGroupings;
63 :
64 : sal_Int32 mnGroup; // current active grouping
65 : sal_Int32 mnDigits; // current active digits per group
66 : sal_Int32 mnNextPos; // position (in digits) of next grouping
67 :
68 263475 : void setInfinite()
69 : {
70 263475 : mnGroup = maGroupings.getLength();
71 263475 : }
72 :
73 263861 : bool isInfinite() const
74 : {
75 263861 : return mnGroup >= maGroupings.getLength();
76 : }
77 :
78 638091 : sal_Int32 getGrouping() const
79 : {
80 638091 : if (mnGroup < maGroupings.getLength())
81 : {
82 638091 : sal_Int32 n = maGroupings[mnGroup];
83 : SAL_WARN_IF( n < 0, "unotools.i18n", "DigitGroupingIterator::getGrouping: negative grouping");
84 638091 : if (n < 0)
85 0 : n = 0; // sanitize ...
86 638091 : return n;
87 : }
88 0 : return 0;
89 : }
90 :
91 638221 : void setPos()
92 : {
93 : // someone might be playing jokes on us, so check for overflow
94 638221 : if (mnNextPos <= SAL_MAX_INT32 - mnDigits)
95 638221 : mnNextPos += mnDigits;
96 638221 : }
97 :
98 638091 : void setDigits()
99 : {
100 638091 : sal_Int32 nPrev = mnDigits;
101 638091 : mnDigits = getGrouping();
102 638091 : if (!mnDigits)
103 : {
104 263475 : mnDigits = nPrev;
105 263475 : setInfinite();
106 : }
107 638091 : setPos();
108 638091 : }
109 :
110 374360 : void initGrouping()
111 : {
112 374360 : mnDigits = 3; // just in case of constructed with empty grouping
113 374360 : mnGroup = 0;
114 374360 : mnNextPos = 0;
115 374360 : setDigits();
116 374360 : }
117 :
118 : // not implemented, prevent usage
119 : DigitGroupingIterator();
120 : DigitGroupingIterator( const DigitGroupingIterator & );
121 : DigitGroupingIterator & operator=( const DigitGroupingIterator & );
122 :
123 : public:
124 :
125 370284 : explicit DigitGroupingIterator( const ::com::sun::star::uno::Sequence< sal_Int32 > & rGroupings )
126 370284 : : maGroupings( rGroupings)
127 : {
128 370284 : initGrouping();
129 370284 : }
130 :
131 : /** Advance iterator to next grouping. */
132 263861 : DigitGroupingIterator & advance()
133 : {
134 263861 : if (isInfinite())
135 130 : setPos();
136 : else
137 : {
138 263731 : ++mnGroup;
139 263731 : setDigits();
140 : }
141 263861 : return *this;
142 : }
143 :
144 : /** Obtain current grouping. Always > 0. */
145 2520 : sal_Int32 get() const
146 : {
147 2520 : return mnDigits;
148 : }
149 :
150 : /** The next position (in integer digits) from the right where to insert a
151 : group separator. */
152 1159881 : sal_Int32 getPos()
153 : {
154 1159881 : return mnNextPos;
155 : }
156 :
157 : /** Reset iterator to start again from the right beginning. */
158 4076 : void reset()
159 : {
160 4076 : initGrouping();
161 4076 : }
162 :
163 : /** Create a sequence of bool values containing positions where to add a
164 : separator when iterating forward over a string and copying digit per
165 : digit. For example, for grouping in thousands and nIntegerDigits==7 the
166 : sequence returned would be {1,0,0,1,0,0,0} so the caller would add a
167 : separator after the 1st and the 4th digit. */
168 101084 : static ::com::sun::star::uno::Sequence< sal_Bool > createForwardSequence(
169 : sal_Int32 nIntegerDigits,
170 : const ::com::sun::star::uno::Sequence< sal_Int32 > & rGroupings )
171 : {
172 101084 : if (nIntegerDigits <= 0)
173 0 : return ::com::sun::star::uno::Sequence< sal_Bool >();
174 101084 : DigitGroupingIterator aIterator( rGroupings);
175 202168 : ::com::sun::star::uno::Sequence< sal_Bool > aSeq( nIntegerDigits);
176 101084 : sal_Bool* pArr = aSeq.getArray();
177 268554 : for (sal_Int32 j = 0; --nIntegerDigits >= 0; ++j)
178 : {
179 167470 : if (j == aIterator.getPos())
180 : {
181 240 : pArr[nIntegerDigits] = sal_True;
182 240 : aIterator.advance();
183 : }
184 : else
185 167230 : pArr[nIntegerDigits] = sal_False;
186 : }
187 202168 : return aSeq;
188 : }
189 : };
190 :
191 : } // namespace utl
192 :
193 : #endif // INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
194 :
195 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|