You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
6.1 KiB
163 lines
6.1 KiB
// © 2020 and later: Unicode, Inc. and others.
|
|
// License & terms of use: http://www.unicode.org/copyright.html
|
|
|
|
#include "unicode/utypes.h"
|
|
|
|
#if !UCONFIG_NO_FORMATTING
|
|
#ifndef __UNITS_ROUTER_H__
|
|
#define __UNITS_ROUTER_H__
|
|
|
|
#include <limits>
|
|
|
|
#include "cmemory.h"
|
|
#include "measunit_impl.h"
|
|
#include "unicode/measunit.h"
|
|
#include "unicode/stringpiece.h"
|
|
#include "unicode/uobject.h"
|
|
#include "units_complexconverter.h"
|
|
#include "units_data.h"
|
|
|
|
U_NAMESPACE_BEGIN
|
|
|
|
// Forward declarations
|
|
class Measure;
|
|
namespace number {
|
|
class Precision;
|
|
}
|
|
|
|
namespace units {
|
|
|
|
struct RouteResult : UMemory {
|
|
// A list of measures: a single measure for single units, multiple measures
|
|
// for mixed units.
|
|
//
|
|
// TODO(icu-units/icu#21): figure out the right mixed unit API.
|
|
MaybeStackVector<Measure> measures;
|
|
|
|
// The output unit for this RouteResult. This may be a MIXED unit - for
|
|
// example: "yard-and-foot-and-inch", for which `measures` will have three
|
|
// elements.
|
|
MeasureUnitImpl outputUnit;
|
|
|
|
RouteResult(MaybeStackVector<Measure> measures, MeasureUnitImpl outputUnit)
|
|
: measures(std::move(measures)), outputUnit(std::move(outputUnit)) {}
|
|
};
|
|
|
|
/**
|
|
* Contains the complex unit converter and the limit which representing the smallest value that the
|
|
* converter should accept. For example, if the converter is converting to `foot+inch` and the limit
|
|
* equals 3.0, thus means the converter should not convert to a value less than `3.0 feet`.
|
|
*
|
|
* NOTE:
|
|
* if the limit doest not has a value `i.e. (std::numeric_limits<double>::lowest())`, this mean there
|
|
* is no limit for the converter.
|
|
*/
|
|
struct ConverterPreference : UMemory {
|
|
ComplexUnitsConverter converter;
|
|
double limit;
|
|
UnicodeString precision;
|
|
|
|
// The output unit for this ConverterPreference. This may be a MIXED unit -
|
|
// for example: "yard-and-foot-and-inch".
|
|
MeasureUnitImpl targetUnit;
|
|
|
|
// In case there is no limit, the limit will be -inf.
|
|
ConverterPreference(const MeasureUnitImpl &source, const MeasureUnitImpl &complexTarget,
|
|
UnicodeString precision, const ConversionRates &ratesInfo, UErrorCode &status)
|
|
: ConverterPreference(source, complexTarget, std::numeric_limits<double>::lowest(), precision,
|
|
ratesInfo, status) {}
|
|
|
|
ConverterPreference(const MeasureUnitImpl &source, const MeasureUnitImpl &complexTarget,
|
|
double limit, UnicodeString precision, const ConversionRates &ratesInfo,
|
|
UErrorCode &status)
|
|
: converter(source, complexTarget, ratesInfo, status), limit(limit),
|
|
precision(std::move(precision)), targetUnit(complexTarget.copy(status)) {}
|
|
};
|
|
|
|
} // namespace units
|
|
|
|
// Export explicit template instantiations of MaybeStackArray, MemoryPool and
|
|
// MaybeStackVector. This is required when building DLLs for Windows. (See
|
|
// datefmt.h, collationiterator.h, erarules.h and others for similar examples.)
|
|
//
|
|
// Note: These need to be outside of the units namespace, or Clang will generate
|
|
// a compile error.
|
|
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
|
|
template class U_I18N_API MaybeStackArray<units::ConverterPreference*, 8>;
|
|
template class U_I18N_API MemoryPool<units::ConverterPreference, 8>;
|
|
template class U_I18N_API MaybeStackVector<units::ConverterPreference, 8>;
|
|
#endif
|
|
|
|
namespace units {
|
|
|
|
/**
|
|
* `UnitsRouter` responsible for converting from a single unit (such as `meter` or `meter-per-second`) to
|
|
* one of the complex units based on the limits.
|
|
* For example:
|
|
* if the input is `meter` and the output as following
|
|
* {`foot+inch`, limit: 3.0}
|
|
* {`inch` , limit: no value (-inf)}
|
|
* Thus means if the input in `meter` is greater than or equal to `3.0 feet`, the output will be in
|
|
* `foot+inch`, otherwise, the output will be in `inch`.
|
|
*
|
|
* NOTE:
|
|
* the output units and the their limits MUST BE in order, for example, if the output units, from the
|
|
* previous example, are the following:
|
|
* {`inch` , limit: no value (-inf)}
|
|
* {`foot+inch`, limit: 3.0}
|
|
* IN THIS CASE THE OUTPUT WILL BE ALWAYS IN `inch`.
|
|
*
|
|
* NOTE:
|
|
* the output units and their limits will be extracted from the units preferences database by knowing
|
|
* the followings:
|
|
* - input unit
|
|
* - locale
|
|
* - usage
|
|
*
|
|
* DESIGN:
|
|
* `UnitRouter` uses internally `ComplexUnitConverter` in order to convert the input units to the
|
|
* desired complex units and to check the limit too.
|
|
*/
|
|
class U_I18N_API UnitsRouter {
|
|
public:
|
|
UnitsRouter(MeasureUnit inputUnit, StringPiece locale, StringPiece usage, UErrorCode &status);
|
|
|
|
/**
|
|
* Performs locale and usage sensitive unit conversion.
|
|
* @param quantity The quantity to convert, expressed in terms of inputUnit.
|
|
* @param rounder If not null, this RoundingImpl will be used to do rounding
|
|
* on the converted value. If the rounder lacks an fPrecision, the
|
|
* rounder will be modified to use the preferred precision for the usage
|
|
* and locale preference, alternatively with the default precision.
|
|
* @param status Receives status.
|
|
*/
|
|
RouteResult route(double quantity, icu::number::impl::RoundingImpl *rounder, UErrorCode &status) const;
|
|
|
|
/**
|
|
* Returns the list of possible output units, i.e. the full set of
|
|
* preferences, for the localized, usage-specific unit preferences.
|
|
*
|
|
* The returned pointer should be valid for the lifetime of the
|
|
* UnitsRouter instance.
|
|
*/
|
|
const MaybeStackVector<MeasureUnit> *getOutputUnits() const;
|
|
|
|
private:
|
|
// List of possible output units. TODO: converterPreferences_ now also has
|
|
// this data available. Maybe drop outputUnits_ and have getOutputUnits
|
|
// construct a the list from data in converterPreferences_ instead?
|
|
MaybeStackVector<MeasureUnit> outputUnits_;
|
|
|
|
MaybeStackVector<ConverterPreference> converterPreferences_;
|
|
|
|
static number::Precision parseSkeletonToPrecision(icu::UnicodeString precisionSkeleton,
|
|
UErrorCode &status);
|
|
};
|
|
|
|
} // namespace units
|
|
U_NAMESPACE_END
|
|
|
|
#endif //__UNITS_ROUTER_H__
|
|
|
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|