b9fd0d1c42
Change-Id: If92869e19c413e11f1f299a97f96b9637aaba65d Reviewed-on: https://gerrit.libreoffice.org/43864 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
194 lines
5.8 KiB
C++
194 lines
5.8 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#ifndef INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
|
|
#define INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
|
|
|
|
#include <com/sun/star/uno/Sequence.hxx>
|
|
#include <sal/log.hxx>
|
|
|
|
namespace utl {
|
|
|
|
/** Iterator to be used with a digit grouping as obtained through
|
|
LocaleDataWrapper::getDigitGrouping().
|
|
|
|
The iterator advances over the digit groupings, returning the number of
|
|
digits per group. If the last group was encountered the iterator will
|
|
always return the last grouping.
|
|
|
|
Grouping values are sanitized to be >= 0, even if originally signed
|
|
sal_Int32.
|
|
|
|
Usage example with a string buffer containing a decimal representation of
|
|
an integer number. Note that of course this loop could be optimized to not
|
|
count single characters but hunks of groups instead using the get() method,
|
|
this is just for illustrating usage. Anyway, for double values it is highly
|
|
more efficient to use ::rtl::math::doubleToString() and pass the grouping
|
|
sequence, instead of using this iterator and inserting characters into
|
|
strings.
|
|
|
|
DigitGroupingIterator aGrouping(...)
|
|
sal_Int32 nCount = 0;
|
|
sal_Int32 n = aBuffer.getLength();
|
|
// >1 because we don't want to insert a separator if there is no leading digit.
|
|
while (n-- > 1)
|
|
{
|
|
if (++nCount >= aGrouping.getPos())
|
|
{
|
|
aBuffer.insert( n, cSeparator);
|
|
nGroupDigits = aGrouping.advance();
|
|
}
|
|
}
|
|
|
|
*/
|
|
|
|
class DigitGroupingIterator
|
|
{
|
|
const css::uno::Sequence< sal_Int32 > maGroupings;
|
|
|
|
sal_Int32 mnGroup; // current active grouping
|
|
sal_Int32 mnDigits; // current active digits per group
|
|
sal_Int32 mnNextPos; // position (in digits) of next grouping
|
|
|
|
void setInfinite()
|
|
{
|
|
mnGroup = maGroupings.getLength();
|
|
}
|
|
|
|
bool isInfinite() const
|
|
{
|
|
return mnGroup >= maGroupings.getLength();
|
|
}
|
|
|
|
sal_Int32 getGrouping() const
|
|
{
|
|
if (mnGroup < maGroupings.getLength())
|
|
{
|
|
sal_Int32 n = maGroupings[mnGroup];
|
|
SAL_WARN_IF( n < 0, "unotools.i18n", "DigitGroupingIterator::getGrouping: negative grouping");
|
|
if (n < 0)
|
|
n = 0; // sanitize ...
|
|
return n;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void setPos()
|
|
{
|
|
// someone might be playing jokes on us, so check for overflow
|
|
if (mnNextPos <= SAL_MAX_INT32 - mnDigits)
|
|
mnNextPos += mnDigits;
|
|
}
|
|
|
|
void setDigits()
|
|
{
|
|
sal_Int32 nPrev = mnDigits;
|
|
mnDigits = getGrouping();
|
|
if (!mnDigits)
|
|
{
|
|
mnDigits = nPrev;
|
|
setInfinite();
|
|
}
|
|
setPos();
|
|
}
|
|
|
|
void initGrouping()
|
|
{
|
|
mnDigits = 3; // just in case of constructed with empty grouping
|
|
mnGroup = 0;
|
|
mnNextPos = 0;
|
|
setDigits();
|
|
}
|
|
|
|
DigitGroupingIterator( const DigitGroupingIterator & ) = delete;
|
|
DigitGroupingIterator & operator=( const DigitGroupingIterator & ) = delete;
|
|
|
|
public:
|
|
|
|
explicit DigitGroupingIterator( const css::uno::Sequence< sal_Int32 > & rGroupings )
|
|
: maGroupings( rGroupings)
|
|
{
|
|
initGrouping();
|
|
}
|
|
|
|
/** Advance iterator to next grouping. */
|
|
DigitGroupingIterator & advance()
|
|
{
|
|
if (isInfinite())
|
|
setPos();
|
|
else
|
|
{
|
|
++mnGroup;
|
|
setDigits();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/** Obtain current grouping. Always > 0. */
|
|
sal_Int32 get() const
|
|
{
|
|
return mnDigits;
|
|
}
|
|
|
|
/** The next position (in integer digits) from the right where to insert a
|
|
group separator. */
|
|
sal_Int32 getPos() const
|
|
{
|
|
return mnNextPos;
|
|
}
|
|
|
|
/** Reset iterator to start again from the right beginning. */
|
|
void reset()
|
|
{
|
|
initGrouping();
|
|
}
|
|
|
|
/** Create a sequence of bool values containing positions where to add a
|
|
separator when iterating forward over a string and copying digit per
|
|
digit. For example, for grouping in thousands and nIntegerDigits==7 the
|
|
sequence returned would be {1,0,0,1,0,0,0} so the caller would add a
|
|
separator after the 1st and the 4th digit. */
|
|
static css::uno::Sequence< sal_Bool > createForwardSequence(
|
|
sal_Int32 nIntegerDigits,
|
|
const css::uno::Sequence< sal_Int32 > & rGroupings )
|
|
{
|
|
if (nIntegerDigits <= 0)
|
|
return css::uno::Sequence< sal_Bool >();
|
|
DigitGroupingIterator aIterator( rGroupings);
|
|
css::uno::Sequence< sal_Bool > aSeq( nIntegerDigits);
|
|
sal_Bool* pArr = aSeq.getArray();
|
|
for (sal_Int32 j = 0; --nIntegerDigits >= 0; ++j)
|
|
{
|
|
if (j == aIterator.getPos())
|
|
{
|
|
pArr[nIntegerDigits] = true;
|
|
aIterator.advance();
|
|
}
|
|
else
|
|
pArr[nIntegerDigits] = false;
|
|
}
|
|
return aSeq;
|
|
}
|
|
};
|
|
|
|
} // namespace utl
|
|
|
|
#endif // INCLUDED_UNOTOOLS_DIGITGROUPINGITERATOR_HXX
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|