10#ifndef poputil_OptionParsing_hpp
11#define poputil_OptionParsing_hpp
14#include <initializer_list>
17#include <poplar/StringRef.hpp>
18#include <poplar/exceptions.hpp>
26template <
typename T> T asInteger(
const poplar::StringRef &str) {
27 std::string stdStr = str.cloneAsString();
28 std::istringstream iss(stdStr);
30 if (stdStr.find(
"0x") != std::string::npos) {
31 iss >> std::hex >> result;
33 iss >> std::dec >> result;
35 if (iss.fail() || !iss.eof()) {
41template <
typename T> T asFloatingPoint(
const poplar::StringRef &str) {
42 std::stringstream s(str);
52static inline std::string
53describeEnumValues(
const std::map<std::string, T> &valueMap) {
56 if (!valueMap.empty()) {
57 auto it = valueMap.begin();
58 s <<
"'" << it->first <<
"'";
59 while (++it != valueMap.end()) {
60 s <<
", '" << it->first <<
"'";
68T asEnum(
const poplar::StringRef &value,
const std::map<std::string, T> &
map) {
69 auto it =
map.find(value);
70 if (it ==
map.end()) {
72 describeEnumValues(
map));
78inline bool asBool(
const poplar::StringRef &value) {
79 static const std::map<std::string, bool> enumMap = {{
"true",
true},
81 return asEnum<bool>(value, enumMap);
90 std::function<void(poplar::StringRef)> valueHandler;
95 : valueHandler(std::forward<T>(valueHandler)) {}
96 void parseValue(poplar::StringRef value)
const { valueHandler(value); }
99 template <
typename T,
typename ValueMapT = std::map<std::
string, T>>
100 static inline OptionHandler createWithEnum(T &output, ValueMapT &&valueMap) {
105 &output](poplar::StringRef value) {
106 output = parse::asEnum<T>(value,
map);
110 template <
typename T>
113 output = parse::asInteger<int>(value);
117 template <
typename T>
static inline OptionHandler createWithBool(T &output) {
118 static std::map<std::string, T> boolMap{{
"true",
static_cast<T
>(
true)},
119 {
"false",
static_cast<T
>(
false)}};
120 return createWithEnum(output, boolMap);
123 template <
typename T>
124 static inline void ensureValueIsWithinBounds(T value,
const T &lowerBound,
125 bool lowerBoundIsInclusive,
127 bool upperBoundIsInclusive) {
128 if (value < lowerBound || (!lowerBoundIsInclusive && value == lowerBound)) {
130 "Value must be greater than " +
131 std::string(lowerBoundIsInclusive ?
"or equal to " :
"") +
132 std::to_string(lowerBound));
135 if (value > upperBound || (!upperBoundIsInclusive && value == upperBound)) {
137 "Value must be less than " +
138 std::string(upperBoundIsInclusive ?
"or equal to " :
"") +
139 std::to_string(upperBound));
143 template <
typename T>
145 createWithDouble(T &output,
147 bool lowerBoundIsInclusive =
true,
149 bool upperBoundIsInclusive =
true) {
151 [&output, lowerBound, lowerBoundIsInclusive, upperBound,
152 upperBoundIsInclusive](poplar::StringRef value) {
153 double output_ = parse::asFloatingPoint<double>(value);
154 ensureValueIsWithinBounds(output_, lowerBound, lowerBoundIsInclusive,
155 upperBound, upperBoundIsInclusive);
161 static inline OptionHandler createWithString(std::string &output) {
163 [&output](poplar::StringRef value) { output = value; }};
166 template <
typename T>
167 static inline OptionHandler createWithList(std::vector<T> &output) {
169 std::istringstream iss(values);
170 for (std::string element; std::getline(iss, element,
',');) {
172 std::istringstream elementStream(element);
173 if (element.find(
"0x") != std::string::npos) {
174 elementStream >> std::hex >> value;
176 elementStream >> std::dec >> value;
178 if (elementStream.fail() || !elementStream.eof()) {
182 output.emplace_back(value);
191 using value_type = std::pair<const std::string, OptionHandler>;
192 using map_type = std::map<const std::string, OptionHandler>;
193 using initializer_list_t = std::initializer_list<value_type>;
197 OptionSpec(initializer_list_t &&handlers) : handlers(std::move(handlers)) {}
200 void parse(poplar::StringRef option, poplar::StringRef value,
201 bool ignoreUnknown =
false)
const {
202 auto it = handlers.find(option);
203 if (it == handlers.end()) {
208 s <<
"Unrecognised option '" << option <<
"'";
213 const auto &handler = it->second;
214 handler.parseValue(value);
217 s <<
"Invalid value '" << value <<
"'"
218 <<
" for option '" << option <<
"': " << e.what();
226 std::optional<T> &output,
228 bool lowerBoundIsInclusive =
true,
230 bool upperBoundIsInclusive =
true) {
231 return OptionHandler{[&output, lowerBound, lowerBoundIsInclusive, upperBound,
232 upperBoundIsInclusive](poplar::StringRef value) {
233 T output_ = parse::asFloatingPoint<double>(value);
234 OptionHandler::ensureValueIsWithinBounds(output_, lowerBound,
235 lowerBoundIsInclusive, upperBound,
236 upperBoundIsInclusive);
241template <
typename T,
typename ValueMapT = std::map<std::
string, T>>
242inline OptionHandler createOptionalEnumHandler(std::optional<T> &output,
243 ValueMapT &&valueMap) {
244 return OptionHandler{[&output,
map = std::forward<ValueMapT>(valueMap)](
245 poplar::StringRef value) {
246 if (value ==
"none") {
247 output = std::nullopt;
250 output = parse::asEnum(value,
map);
Represents the various options types.
Definition: OptionParsing.hpp:89
Represents a set of options and their values.
Definition: OptionParsing.hpp:190
half2 max(half2 src0, half2 src1)
Targets the f16v2max instruction.
Definition: ipu_intrinsics:333
half2 min(half2 src0, half2 src1)
Targets the f16v2min instruction.
Definition: ipu_intrinsics:384
PopLibs classes and functions.
Definition: OptionParsing.hpp:23
poplar::Tensor map(poplar::Graph &graph, const expr::Expr &expr, const std::vector< poplar::Tensor > &ts, poplar::program::Sequence &prog, const poplar::DebugContext &debugContext={}, const poplar::OptionFlags &options={})
Map an expression across tensors.
This exception is thrown when an unrecognised or invalid option is passed to a Poplar API.
Definition: exceptions.hpp:292