update credits
[LibreOffice.git] / include / unotools / digitgroupingiterator.hxx
blobd7bca117756b19b3c804f283ad11052f0a10e956
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #ifndef INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
21 #define INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
23 #include <com/sun/star/uno/Sequence.hxx>
25 namespace utl {
27 /** Iterator to be used with a digit grouping as obtained through
28 LocaleDataWrapper::getDigitGrouping().
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.
34 Grouping values are sanitized to be 0 <= value <= SAL_MAX_UINT16, even if
35 originally Int32, to be able to easily cast it down to String's xub_StrLen.
36 This shouldn't make any difference in practice.
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.
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)
52 if (++nCount >= aGrouping.getPos())
54 aBuffer.insert( n, cSeparator);
55 nGroupDigits = aGrouping.advance();
61 class DigitGroupingIterator
63 const ::com::sun::star::uno::Sequence< sal_Int32 > maGroupings;
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
69 void setInfinite()
71 mnGroup = maGroupings.getLength();
74 bool isInfinite() const
76 return mnGroup >= maGroupings.getLength();
79 sal_Int32 getGrouping() const
81 if (mnGroup < maGroupings.getLength())
83 sal_Int32 n = maGroupings[mnGroup];
84 OSL_ENSURE( 0 <= n && n <= SAL_MAX_UINT16, "DigitGroupingIterator::getGrouping: far out");
85 if (n < 0)
86 n = 0; // sanitize ...
87 else if (n > SAL_MAX_UINT16)
88 n = SAL_MAX_UINT16; // limit for use with xub_StrLen
89 return n;
91 return 0;
94 void setPos()
96 // someone might be playing jokes on us, so check for overflow
97 if (mnNextPos <= SAL_MAX_INT32 - mnDigits)
98 mnNextPos += mnDigits;
101 void setDigits()
103 sal_Int32 nPrev = mnDigits;
104 mnDigits = getGrouping();
105 if (!mnDigits)
107 mnDigits = nPrev;
108 setInfinite();
110 setPos();
113 void initGrouping()
115 mnDigits = 3; // just in case of constructed with empty grouping
116 mnGroup = 0;
117 mnNextPos = 0;
118 setDigits();
121 // not implemented, prevent usage
122 DigitGroupingIterator();
123 DigitGroupingIterator( const DigitGroupingIterator & );
124 DigitGroupingIterator & operator=( const DigitGroupingIterator & );
126 public:
128 explicit DigitGroupingIterator( const ::com::sun::star::uno::Sequence< sal_Int32 > & rGroupings )
129 : maGroupings( rGroupings)
131 initGrouping();
134 /** Advance iterator to next grouping. */
135 DigitGroupingIterator & advance()
137 if (isInfinite())
138 setPos();
139 else
141 ++mnGroup;
142 setDigits();
144 return *this;
147 /** Obtain current grouping. Always > 0. */
148 sal_Int32 get() const
150 return mnDigits;
153 /** The next position (in integer digits) from the right where to insert a
154 group separator. */
155 sal_Int32 getPos()
157 return mnNextPos;
160 /** Reset iterator to start again from the right beginning. */
161 void reset()
163 initGrouping();
166 /** Create a sequence of bool values containing positions where to add a
167 separator when iterating forward over a string and copying digit per
168 digit. For example, for grouping in thousands and nIntegerDigits==7 the
169 sequence returned would be {1,0,0,1,0,0,0} so the caller would add a
170 separator after the 1st and the 4th digit. */
171 static ::com::sun::star::uno::Sequence< sal_Bool > createForwardSequence(
172 sal_Int32 nIntegerDigits,
173 const ::com::sun::star::uno::Sequence< sal_Int32 > & rGroupings )
175 if (nIntegerDigits <= 0)
176 return ::com::sun::star::uno::Sequence< sal_Bool >();
177 DigitGroupingIterator aIterator( rGroupings);
178 ::com::sun::star::uno::Sequence< sal_Bool > aSeq( nIntegerDigits);
179 sal_Bool* pArr = aSeq.getArray();
180 for (sal_Int32 j = 0; --nIntegerDigits >= 0; ++j)
182 if (j == aIterator.getPos())
184 pArr[nIntegerDigits] = sal_True;
185 aIterator.advance();
187 else
188 pArr[nIntegerDigits] = sal_False;
190 return aSeq;
194 } // namespace utl
196 #endif // INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
198 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */