xref: /AOO41X/main/unotools/inc/unotools/digitgroupingiterator.hxx (revision bae3752ec30c258ca902793e4eea3c818b0bcaad)
1*bae3752eSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*bae3752eSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*bae3752eSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*bae3752eSAndrew Rist  * distributed with this work for additional information
6*bae3752eSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*bae3752eSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*bae3752eSAndrew Rist  * "License"); you may not use this file except in compliance
9*bae3752eSAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
11*bae3752eSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
13*bae3752eSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*bae3752eSAndrew Rist  * software distributed under the License is distributed on an
15*bae3752eSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*bae3752eSAndrew Rist  * KIND, either express or implied.  See the License for the
17*bae3752eSAndrew Rist  * specific language governing permissions and limitations
18*bae3752eSAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
20*bae3752eSAndrew Rist  *************************************************************/
21*bae3752eSAndrew Rist 
22*bae3752eSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir #ifndef INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
25cdf0e10cSrcweir #define INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include <com/sun/star/uno/Sequence.hxx>
28cdf0e10cSrcweir 
29cdf0e10cSrcweir namespace utl {
30cdf0e10cSrcweir 
31cdf0e10cSrcweir /** Iterator to be used with a digit grouping as obtained through
32cdf0e10cSrcweir     LocaleDataWrapper::getDigitGrouping().
33cdf0e10cSrcweir 
34cdf0e10cSrcweir     The iterator advances over the digit groupings, returning the number of
35cdf0e10cSrcweir     digits per group. If the last group was encountered the iterator will
36cdf0e10cSrcweir     always return the last grouping.
37cdf0e10cSrcweir 
38cdf0e10cSrcweir     Grouping values are sanitized to be 0 <= value <= SAL_MAX_UINT16, even if
39cdf0e10cSrcweir     originally Int32, to be able to easily cast it down to String's xub_StrLen.
40cdf0e10cSrcweir     This shouldn't make any difference in practice.
41cdf0e10cSrcweir 
42cdf0e10cSrcweir     Usage example with a string buffer containing a decimal representation of
43cdf0e10cSrcweir     an integer number. Note that of course this loop could be optimized to not
44cdf0e10cSrcweir     count single characters but hunks of groups instead using the get() method,
45cdf0e10cSrcweir     this is just for illustrating usage. Anyway, for double values it is highly
46cdf0e10cSrcweir     more efficient to use ::rtl::math::doubleToString() and pass the grouping
47cdf0e10cSrcweir     sequence, instead of using this iterator and inserting charcters into
48cdf0e10cSrcweir     strings.
49cdf0e10cSrcweir 
50cdf0e10cSrcweir     DigitGroupingIterator aGrouping(...)
51cdf0e10cSrcweir     sal_Int32 nCount = 0;
52cdf0e10cSrcweir     sal_Int32 n = aBuffer.getLength();
53cdf0e10cSrcweir     // >1 because we don't want to insert a separator if there is no leading digit.
54cdf0e10cSrcweir     while (n-- > 1)
55cdf0e10cSrcweir     {
56cdf0e10cSrcweir         if (++nCount >= aGrouping.getPos())
57cdf0e10cSrcweir         {
58cdf0e10cSrcweir             aBuffer.insert( n, cSeparator);
59cdf0e10cSrcweir             nGroupDigits = aGrouping.advance();
60cdf0e10cSrcweir         }
61cdf0e10cSrcweir     }
62cdf0e10cSrcweir 
63cdf0e10cSrcweir  */
64cdf0e10cSrcweir 
65cdf0e10cSrcweir class DigitGroupingIterator
66cdf0e10cSrcweir {
67cdf0e10cSrcweir     const ::com::sun::star::uno::Sequence< sal_Int32 > maGroupings;
68cdf0e10cSrcweir 
69cdf0e10cSrcweir     sal_Int32   mnGroup;        // current active grouping
70cdf0e10cSrcweir     sal_Int32   mnDigits;       // current active digits per group
71cdf0e10cSrcweir     sal_Int32   mnNextPos;      // position (in digits) of next grouping
72cdf0e10cSrcweir 
setInfinite()73cdf0e10cSrcweir     void setInfinite()
74cdf0e10cSrcweir     {
75cdf0e10cSrcweir         mnGroup = maGroupings.getLength();
76cdf0e10cSrcweir     }
77cdf0e10cSrcweir 
isInfinite() const78cdf0e10cSrcweir     bool isInfinite() const
79cdf0e10cSrcweir     {
80cdf0e10cSrcweir         return mnGroup >= maGroupings.getLength();
81cdf0e10cSrcweir     }
82cdf0e10cSrcweir 
getGrouping() const83cdf0e10cSrcweir     sal_Int32 getGrouping() const
84cdf0e10cSrcweir     {
85cdf0e10cSrcweir         if (mnGroup < maGroupings.getLength())
86cdf0e10cSrcweir         {
87cdf0e10cSrcweir             sal_Int32 n = maGroupings[mnGroup];
88cdf0e10cSrcweir             OSL_ENSURE( 0 <= n && n <= SAL_MAX_UINT16, "DigitGroupingIterator::getGrouping: far out");
89cdf0e10cSrcweir             if (n < 0)
90cdf0e10cSrcweir                 n = 0;                  // sanitize ...
91cdf0e10cSrcweir             else if (n > SAL_MAX_UINT16)
92cdf0e10cSrcweir                 n = SAL_MAX_UINT16;     // limit for use with xub_StrLen
93cdf0e10cSrcweir             return n;
94cdf0e10cSrcweir         }
95cdf0e10cSrcweir         return 0;
96cdf0e10cSrcweir     }
97cdf0e10cSrcweir 
setPos()98cdf0e10cSrcweir     void setPos()
99cdf0e10cSrcweir     {
100cdf0e10cSrcweir         // someone might be playing jokes on us, so check for overflow
101cdf0e10cSrcweir         if (mnNextPos <= SAL_MAX_INT32 - mnDigits)
102cdf0e10cSrcweir             mnNextPos += mnDigits;
103cdf0e10cSrcweir     }
104cdf0e10cSrcweir 
setDigits()105cdf0e10cSrcweir     void setDigits()
106cdf0e10cSrcweir     {
107cdf0e10cSrcweir         sal_Int32 nPrev = mnDigits;
108cdf0e10cSrcweir         mnDigits = getGrouping();
109cdf0e10cSrcweir         if (!mnDigits)
110cdf0e10cSrcweir         {
111cdf0e10cSrcweir             mnDigits = nPrev;
112cdf0e10cSrcweir             setInfinite();
113cdf0e10cSrcweir         }
114cdf0e10cSrcweir         setPos();
115cdf0e10cSrcweir     }
116cdf0e10cSrcweir 
initGrouping()117cdf0e10cSrcweir     void initGrouping()
118cdf0e10cSrcweir     {
119cdf0e10cSrcweir         mnDigits = 3;       // just in case of constructed with empty grouping
120cdf0e10cSrcweir         mnGroup = 0;
121cdf0e10cSrcweir         mnNextPos = 0;
122cdf0e10cSrcweir         setDigits();
123cdf0e10cSrcweir     }
124cdf0e10cSrcweir 
125cdf0e10cSrcweir     // not implemented, prevent usage
126cdf0e10cSrcweir     DigitGroupingIterator();
127cdf0e10cSrcweir     DigitGroupingIterator( const DigitGroupingIterator & );
128cdf0e10cSrcweir     DigitGroupingIterator & operator=( const DigitGroupingIterator & );
129cdf0e10cSrcweir 
130cdf0e10cSrcweir public:
131cdf0e10cSrcweir 
DigitGroupingIterator(const::com::sun::star::uno::Sequence<sal_Int32> & rGroupings)132cdf0e10cSrcweir     explicit DigitGroupingIterator( const ::com::sun::star::uno::Sequence< sal_Int32 > & rGroupings )
133cdf0e10cSrcweir         : maGroupings( rGroupings)
134cdf0e10cSrcweir     {
135cdf0e10cSrcweir         initGrouping();
136cdf0e10cSrcweir     }
137cdf0e10cSrcweir 
138cdf0e10cSrcweir     /** Advance iterator to next grouping. */
advance()139cdf0e10cSrcweir     DigitGroupingIterator & advance()
140cdf0e10cSrcweir     {
141cdf0e10cSrcweir         if (isInfinite())
142cdf0e10cSrcweir             setPos();
143cdf0e10cSrcweir         else
144cdf0e10cSrcweir         {
145cdf0e10cSrcweir             ++mnGroup;
146cdf0e10cSrcweir             setDigits();
147cdf0e10cSrcweir         }
148cdf0e10cSrcweir         return *this;
149cdf0e10cSrcweir     }
150cdf0e10cSrcweir 
151cdf0e10cSrcweir     /** Obtain current grouping. Always > 0. */
get() const152cdf0e10cSrcweir     sal_Int32 get() const
153cdf0e10cSrcweir     {
154cdf0e10cSrcweir         return mnDigits;
155cdf0e10cSrcweir     }
156cdf0e10cSrcweir 
157cdf0e10cSrcweir     /** The next position (in integer digits) from the right where to insert a
158cdf0e10cSrcweir         group separator. */
getPos()159cdf0e10cSrcweir     sal_Int32 getPos()
160cdf0e10cSrcweir     {
161cdf0e10cSrcweir         return mnNextPos;
162cdf0e10cSrcweir     }
163cdf0e10cSrcweir 
164cdf0e10cSrcweir     /** Reset iterator to start again from the right beginning. */
reset()165cdf0e10cSrcweir     void reset()
166cdf0e10cSrcweir     {
167cdf0e10cSrcweir         initGrouping();
168cdf0e10cSrcweir     }
169cdf0e10cSrcweir 
170cdf0e10cSrcweir     /** Create a sequence of bool values containing positions where to add a
171cdf0e10cSrcweir         separator when iterating forward over a string and copying digit per
172cdf0e10cSrcweir         digit. For example, for grouping in thousands and nIntegerDigits==7 the
173cdf0e10cSrcweir         sequence returned would be {1,0,0,1,0,0,0} so the caller would add a
174cdf0e10cSrcweir         separator after the 1st and the 4th digit. */
createForwardSequence(sal_Int32 nIntegerDigits,const::com::sun::star::uno::Sequence<sal_Int32> & rGroupings)175cdf0e10cSrcweir     static ::com::sun::star::uno::Sequence< sal_Bool > createForwardSequence(
176cdf0e10cSrcweir             sal_Int32 nIntegerDigits,
177cdf0e10cSrcweir             const ::com::sun::star::uno::Sequence< sal_Int32 > & rGroupings )
178cdf0e10cSrcweir     {
179cdf0e10cSrcweir         if (nIntegerDigits <= 0)
180cdf0e10cSrcweir             return ::com::sun::star::uno::Sequence< sal_Bool >();
181cdf0e10cSrcweir         DigitGroupingIterator aIterator( rGroupings);
182cdf0e10cSrcweir         ::com::sun::star::uno::Sequence< sal_Bool > aSeq( nIntegerDigits);
183cdf0e10cSrcweir         sal_Bool* pArr = aSeq.getArray();
184cdf0e10cSrcweir         for (sal_Int32 j = 0; --nIntegerDigits >= 0; ++j)
185cdf0e10cSrcweir         {
186cdf0e10cSrcweir             if (j == aIterator.getPos())
187cdf0e10cSrcweir             {
188cdf0e10cSrcweir                 pArr[nIntegerDigits] = sal_True;
189cdf0e10cSrcweir                 aIterator.advance();
190cdf0e10cSrcweir             }
191cdf0e10cSrcweir             else
192cdf0e10cSrcweir                 pArr[nIntegerDigits] = sal_False;
193cdf0e10cSrcweir         }
194cdf0e10cSrcweir         return aSeq;
195cdf0e10cSrcweir     }
196cdf0e10cSrcweir };
197cdf0e10cSrcweir 
198cdf0e10cSrcweir } // namespace utl
199cdf0e10cSrcweir 
200cdf0e10cSrcweir #endif // INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
201