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