blob: 1b29d9d8f3a3a79ebb78f3cb1123cd3b08d9143a [file] [log] [blame]
// © 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 __UNITSROUTER_H__
#define __UNITSROUTER_H__
#include <limits>
#include "charstr.h" // CharString
#include "cmemory.h"
#include "complexunitsconverter.h"
#include "unicode/errorcode.h"
#include "unicode/measunit.h"
#include "unicode/measure.h"
#include "unicode/stringpiece.h"
#include "unitsdata.h"
U_NAMESPACE_BEGIN
/**
* 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;
ConverterPreference(MeasureUnit source, MeasureUnit complexTarget, double limit,
const ConversionRates &ratesInfo, UErrorCode &status)
: converter(source, complexTarget, ratesInfo, status), limit(limit) {}
ConverterPreference(MeasureUnit source, MeasureUnit complexTarget, const ConversionRates &ratesInfo,
UErrorCode &status)
: ConverterPreference(source, complexTarget, std::numeric_limits<double>::lowest(), ratesInfo,
status) {}
};
/**
* `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);
MaybeStackVector<Measure> route(double quantity, UErrorCode &status);
private:
MaybeStackVector<ConverterPreference> converterPreferences_;
};
U_NAMESPACE_END
#endif //__UNITSROUTER_H__
#endif /* #if !UCONFIG_NO_FORMATTING */