Config.hpp 104 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300
  1. #ifndef slic3r_Config_hpp_
  2. #define slic3r_Config_hpp_
  3. #include <assert.h>
  4. #include <map>
  5. #include <climits>
  6. #include <cstdio>
  7. #include <cstdlib>
  8. #include <functional>
  9. #include <iostream>
  10. #include <stdexcept>
  11. #include <string>
  12. #include <vector>
  13. #include "libslic3r.h"
  14. #include "clonable_ptr.hpp"
  15. #include "Exception.hpp"
  16. #include "Point.hpp"
  17. #include <boost/algorithm/string/predicate.hpp>
  18. #include <boost/algorithm/string/trim.hpp>
  19. #include <boost/format/format_fwd.hpp>
  20. #include <boost/property_tree/ptree_fwd.hpp>
  21. #include <cereal/access.hpp>
  22. #include <cereal/types/base_class.hpp>
  23. namespace Slic3r {
  24. // Name of the configuration option.
  25. typedef std::string t_config_option_key;
  26. typedef std::vector<std::string> t_config_option_keys;
  27. extern std::string escape_string_cstyle(const std::string &str);
  28. extern std::string escape_strings_cstyle(const std::vector<std::string> &strs);
  29. extern bool unescape_string_cstyle(const std::string &str, std::string &out);
  30. extern bool unescape_strings_cstyle(const std::string &str, std::vector<std::string> &out);
  31. extern std::string escape_ampersand(const std::string& str);
  32. enum OptionCategory : int
  33. {
  34. none,
  35. perimeter,
  36. slicing,
  37. infill,
  38. ironing,
  39. skirtBrim,
  40. support,
  41. speed,
  42. width,
  43. extruders,
  44. output,
  45. notes,
  46. dependencies,
  47. filament,
  48. cooling,
  49. advanced,
  50. filoverride,
  51. customgcode,
  52. general,
  53. limits,
  54. mmsetup,
  55. firmware,
  56. pad,
  57. padSupp,
  58. wipe,
  59. hollowing,
  60. milling_extruders,
  61. milling,
  62. };
  63. std::string toString(OptionCategory opt);
  64. namespace ConfigHelpers {
  65. inline bool looks_like_enum_value(std::string value)
  66. {
  67. boost::trim(value);
  68. if (value.empty() || value.size() > 64 || ! isalpha(value.front()))
  69. return false;
  70. for (const char c : value)
  71. if (! (isalnum(c) || c == '_' || c == '-'))
  72. return false;
  73. return true;
  74. }
  75. inline bool enum_looks_like_true_value(std::string value) {
  76. boost::trim(value);
  77. return boost::iequals(value, "enabled") || boost::iequals(value, "on");
  78. }
  79. enum class DeserializationSubstitution {
  80. Disabled,
  81. DefaultsToFalse,
  82. DefaultsToTrue
  83. };
  84. enum class DeserializationResult {
  85. Loaded,
  86. Substituted,
  87. Failed,
  88. };
  89. };
  90. // Base for all exceptions thrown by the configuration layer.
  91. class ConfigurationError : public Slic3r::RuntimeError {
  92. public:
  93. using RuntimeError::RuntimeError;
  94. };
  95. // Specialization of std::exception to indicate that an unknown config option has been encountered.
  96. class UnknownOptionException : public ConfigurationError {
  97. public:
  98. UnknownOptionException() :
  99. ConfigurationError("Unknown option exception") {}
  100. UnknownOptionException(const std::string &opt_key) :
  101. ConfigurationError(std::string("Unknown option exception: ") + opt_key) {}
  102. };
  103. // Indicate that the ConfigBase derived class does not provide config definition (the method def() returns null).
  104. class NoDefinitionException : public ConfigurationError
  105. {
  106. public:
  107. NoDefinitionException() :
  108. ConfigurationError("No definition exception") {}
  109. NoDefinitionException(const std::string &opt_key) :
  110. ConfigurationError(std::string("No definition exception: ") + opt_key) {}
  111. };
  112. // a bit more specific than a runtime_error
  113. class ConfigurationException : public std::runtime_error
  114. {
  115. public:
  116. ConfigurationException() :
  117. std::runtime_error("Configuration exception") {}
  118. ConfigurationException(const std::string &opt_key) :
  119. std::runtime_error(std::string("Configuration exception: ") + opt_key) {}
  120. };
  121. // Indicate that an unsupported accessor was called on a config option.
  122. class BadOptionTypeException : public ConfigurationError
  123. {
  124. public:
  125. BadOptionTypeException() : ConfigurationError("Bad option type exception") {}
  126. BadOptionTypeException(const std::string &message) : ConfigurationError(message) {}
  127. BadOptionTypeException(const char* message) : ConfigurationError(message) {}
  128. };
  129. // Indicate that an option has been deserialized from an invalid value.
  130. class BadOptionValueException : public ConfigurationError
  131. {
  132. public:
  133. BadOptionValueException() : ConfigurationError("Bad option value exception") {}
  134. BadOptionValueException(const std::string &message) : ConfigurationError(message) {}
  135. BadOptionValueException(const char* message) : ConfigurationError(message) {}
  136. };
  137. // Type of a configuration value.
  138. enum ConfigOptionType : uint16_t{
  139. coVectorType = 0x4000,
  140. coNone = 0,
  141. // single float
  142. coFloat = 1,
  143. // vector of floats
  144. coFloats = coFloat + coVectorType,
  145. // single int
  146. coInt = 2,
  147. // vector of ints
  148. coInts = coInt + coVectorType,
  149. // single string
  150. coString = 3,
  151. // vector of strings
  152. coStrings = coString + coVectorType,
  153. // percent value. Currently only used for infill & flow ratio.
  154. coPercent = 4,
  155. // percents value. Currently used for retract before wipe only.
  156. coPercents = coPercent + coVectorType,
  157. // a fraction or an absolute value
  158. coFloatOrPercent = 5,
  159. // vector of the above
  160. coFloatsOrPercents = coFloatOrPercent + coVectorType,
  161. // single 2d point (Point2f). Currently not used.
  162. coPoint = 6,
  163. // vector of 2d points (Point2f). Currently used for the definition of the print bed and for the extruder offsets.
  164. coPoints = coPoint + coVectorType,
  165. coPoint3 = 7,
  166. // coPoint3s = coPoint3 + coVectorType,
  167. // single boolean value
  168. coBool = 8,
  169. // vector of boolean values
  170. coBools = coBool + coVectorType,
  171. // a generic enum
  172. coEnum = 9,
  173. };
  174. enum ConfigOptionMode {
  175. comSimple = 0,
  176. comAdvanced,
  177. comExpert
  178. };
  179. enum PrinterTechnology : uint8_t
  180. {
  181. // Fused Filament Fabrication
  182. ptFFF = 1 << 0,
  183. // Stereolitography
  184. ptSLA = 1 << 1,
  185. // Selective Laser-Sintering
  186. ptSLS = 1 << 2,
  187. // CNC
  188. ptMill = 1 << 3,
  189. // Laser engraving
  190. ptLaser = 1 << 4,
  191. // Any technology, useful for parameters compatible with both ptFFF and ptSLA
  192. ptAny = ptFFF | ptSLA | ptSLS | ptMill | ptLaser,
  193. // Unknown, useful for command line processing
  194. ptUnknown = 1 << 7
  195. };
  196. inline PrinterTechnology operator|(PrinterTechnology a, PrinterTechnology b) {
  197. return static_cast<PrinterTechnology>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
  198. }
  199. inline PrinterTechnology operator&(PrinterTechnology a, PrinterTechnology b) {
  200. return static_cast<PrinterTechnology>(static_cast<uint8_t>(a)& static_cast<uint8_t>(b));
  201. }
  202. inline PrinterTechnology operator|=(PrinterTechnology& a, PrinterTechnology b) {
  203. a = a | b; return a;
  204. }
  205. inline PrinterTechnology operator&=(PrinterTechnology& a, PrinterTechnology b) {
  206. a = a & b; return a;
  207. }
  208. ///
  209. enum OutputFormat : uint16_t
  210. {
  211. ofMaskedCWS = 1 << 0,
  212. ofSL1 = 1 << 1,
  213. ofGCode = 1 << 2,
  214. ofUnknown = 1 << 15
  215. };
  216. inline OutputFormat operator|(OutputFormat a, OutputFormat b) {
  217. return static_cast<OutputFormat>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
  218. }
  219. inline OutputFormat operator&(OutputFormat a, OutputFormat b) {
  220. return static_cast<OutputFormat>(static_cast<uint8_t>(a)& static_cast<uint8_t>(b));
  221. }
  222. inline OutputFormat operator|=(OutputFormat& a, OutputFormat b) {
  223. a = a | b; return a;
  224. }
  225. inline OutputFormat operator&=(OutputFormat& a, OutputFormat b) {
  226. a = a & b; return a;
  227. }
  228. enum ForwardCompatibilitySubstitutionRule
  229. {
  230. // Disable susbtitution, throw exception if an option value is not recognized.
  231. Disable,
  232. // Enable substitution of an unknown option value with default. Log the substitution.
  233. Enable,
  234. // Enable substitution of an unknown option value with default. Don't log the substitution.
  235. EnableSilent,
  236. // Enable substitution of an unknown option value with default. Log substitutions in user profiles, don't log substitutions in system profiles.
  237. EnableSystemSilent,
  238. // Enable silent substitution of an unknown option value with default when loading user profiles. Throw on an unknown option value in a system profile.
  239. EnableSilentDisableSystem,
  240. };
  241. class ConfigOption;
  242. class ConfigOptionDef;
  243. // For forward definition of ConfigOption in ConfigOptionUniquePtr, we have to define a custom deleter.
  244. struct ConfigOptionDeleter { void operator()(ConfigOption* p); };
  245. using ConfigOptionUniquePtr = std::unique_ptr<ConfigOption, ConfigOptionDeleter>;
  246. // When parsing a configuration value, if the old_value is not understood by this PrusaSlicer version,
  247. // it is being substituted with some default value that this PrusaSlicer could work with.
  248. // This structure serves to inform the user about the substitutions having been done during file import.
  249. struct ConfigSubstitution {
  250. const ConfigOptionDef *opt_def { nullptr };
  251. std::string old_value;
  252. ConfigOptionUniquePtr new_value;
  253. ConfigSubstitution() = default;
  254. ConfigSubstitution(const ConfigOptionDef* def, std::string old, ConfigOptionUniquePtr&& new_v) : opt_def(def), old_value(old), new_value(std::move(new_v)) {}
  255. };
  256. using ConfigSubstitutions = std::vector<ConfigSubstitution>;
  257. // Filled in by ConfigBase::set_deserialize_raw(), which based on "rule" either bails out
  258. // or performs substitutions when encountering an unknown configuration value.
  259. struct ConfigSubstitutionContext
  260. {
  261. ConfigSubstitutionContext(ForwardCompatibilitySubstitutionRule rl) : rule(rl) {}
  262. bool empty() const throw() { return substitutions.empty(); }
  263. ForwardCompatibilitySubstitutionRule rule;
  264. ConfigSubstitutions substitutions;
  265. };
  266. // A generic value of a configuration option.
  267. class ConfigOption {
  268. public:
  269. // if true, this option doesn't need to be saved, it's a computed value from an other configOption.
  270. // uint32_t because macos crash if it's a bool. and it doesn't change the size of the object because of alignment.
  271. uint32_t flags;
  272. enum FlagsConfigOption : uint32_t {
  273. FCO_PHONY = 1,
  274. FCO_EXTRUDER_ARRAY = 1 << 1,
  275. FCO_PLACEHOLDER_TEMP = 1 << 2,
  276. };
  277. ConfigOption() : flags(uint32_t(0)) {}
  278. ConfigOption(bool phony) : flags(phony ? uint32_t(FlagsConfigOption::FCO_PHONY) : uint32_t(0)) {}
  279. virtual ~ConfigOption() {}
  280. virtual ConfigOptionType type() const = 0;
  281. virtual std::string serialize() const = 0;
  282. virtual bool deserialize(const std::string &str, bool append = false) = 0;
  283. virtual ConfigOption* clone() const = 0;
  284. // Set a value from a ConfigOption. The two options should be compatible.
  285. virtual void set(const ConfigOption *option) = 0;
  286. virtual int32_t getInt() const { throw BadOptionTypeException("Calling ConfigOption::getInt on a non-int ConfigOption"); }
  287. virtual double getFloat() const { throw BadOptionTypeException("Calling ConfigOption::getFloat on a non-float ConfigOption"); }
  288. virtual bool getBool() const { throw BadOptionTypeException("Calling ConfigOption::getBool on a non-boolean ConfigOption"); }
  289. virtual void setInt(int32_t /* val */) { throw BadOptionTypeException("Calling ConfigOption::setInt on a non-int ConfigOption"); }
  290. virtual bool operator==(const ConfigOption &rhs) const = 0;
  291. bool operator!=(const ConfigOption &rhs) const { return ! (*this == rhs); }
  292. bool is_scalar() const { return (int(this->type()) & int(coVectorType)) == 0; }
  293. bool is_vector() const { return ! this->is_scalar(); }
  294. // If this option is nullable, then it may have its value or values set to nil.
  295. virtual bool nullable() const { return false; }
  296. // A scalar is nil, or all values of a vector are nil.
  297. virtual bool is_nil() const { return false; }
  298. bool is_phony() const { return (flags & FCO_PHONY) != 0; }
  299. void set_phony(bool phony) { if (phony) this->flags |= FCO_PHONY; else this->flags &= uint8_t(0xFF ^ FCO_PHONY); }
  300. // Is this option overridden by another option?
  301. // An option overrides another option if it is not nil and not equal.
  302. virtual bool overriden_by(const ConfigOption *rhs) const {
  303. assert(! this->nullable() && ! rhs->nullable());
  304. return *this != *rhs;
  305. }
  306. // Apply an override option, possibly a nullable one.
  307. virtual bool apply_override(const ConfigOption *rhs) {
  308. if (*this == *rhs)
  309. return false;
  310. *this = *rhs;
  311. return true;
  312. }
  313. private:
  314. friend class cereal::access;
  315. template<class Archive> void serialize(Archive& ar) { ar(this->flags); }
  316. };
  317. typedef ConfigOption* ConfigOptionPtr;
  318. typedef const ConfigOption* ConfigOptionConstPtr;
  319. // Value of a single valued option (bool, int, float, string, point, enum)
  320. template <class T>
  321. class ConfigOptionSingle : public ConfigOption {
  322. public:
  323. T value;
  324. explicit ConfigOptionSingle(T value) : value(value) {}
  325. explicit ConfigOptionSingle(T value, bool phony) : ConfigOption(phony), value(value) {}
  326. operator T() const { return this->value; }
  327. void set(const ConfigOption *rhs) override
  328. {
  329. if (rhs->type() != this->type())
  330. throw ConfigurationError("ConfigOptionSingle: Assigning an incompatible type");
  331. assert(dynamic_cast<const ConfigOptionSingle<T>*>(rhs));
  332. this->value = static_cast<const ConfigOptionSingle<T>*>(rhs)->value;
  333. this->flags = rhs->flags;
  334. }
  335. bool operator==(const ConfigOption &rhs) const override
  336. {
  337. if (rhs.type() != this->type())
  338. throw ConfigurationError("ConfigOptionSingle: Comparing incompatible types");
  339. assert(dynamic_cast<const ConfigOptionSingle<T>*>(&rhs));
  340. return this->value == static_cast<const ConfigOptionSingle<T>*>(&rhs)->value;
  341. }
  342. bool operator==(const T &rhs) const { return this->value == rhs; }
  343. bool operator!=(const T &rhs) const { return this->value != rhs; }
  344. private:
  345. friend class cereal::access;
  346. template<class Archive> void serialize(Archive & ar) { ar(this->flags); ar(this->value); }
  347. };
  348. // Value of a vector valued option (bools, ints, floats, strings, points)
  349. class ConfigOptionVectorBase : public ConfigOption {
  350. public:
  351. // Currently used only to initialize the PlaceholderParser.
  352. virtual std::vector<std::string> vserialize() const = 0;
  353. // Set from a vector of ConfigOptions.
  354. // If the rhs ConfigOption is scalar, then its value is used,
  355. // otherwise for each of rhs, the first value of a vector is used.
  356. // This function is useful to collect values for multiple extrder / filament settings.
  357. virtual void set(const std::vector<const ConfigOption*> &rhs) = 0;
  358. // Set a single vector item from either a scalar option or the first value of a vector option.vector of ConfigOptions.
  359. // This function is useful to split values from multiple extrder / filament settings into separate configurations.
  360. virtual void set_at(const ConfigOption *rhs, size_t i, size_t j) = 0;
  361. // Resize the vector of values, copy the newly added values from opt_default if provided.
  362. virtual void resize(size_t n, const ConfigOption *opt_default = nullptr) = 0;
  363. // Clear the values vector.
  364. virtual void clear() = 0;
  365. // Get size of this vector.
  366. virtual size_t size() const = 0;
  367. // Is this vector empty?
  368. virtual bool empty() const = 0;
  369. // Is the value nil? That should only be possible if this->nullable().
  370. virtual bool is_nil(size_t idx) const = 0;
  371. // Get if the size of this vector is/should be the same as nozzle_diameter
  372. bool is_extruder_size() const { return (flags & FCO_EXTRUDER_ARRAY) != 0; }
  373. ConfigOptionVectorBase* set_is_extruder_size(bool is_extruder_size) {
  374. if (is_extruder_size) this->flags |= FCO_EXTRUDER_ARRAY; else this->flags &= uint8_t(0xFF ^ FCO_EXTRUDER_ARRAY);
  375. return this;
  376. }
  377. virtual double getFloat(int idx) const { throw BadOptionTypeException("Calling ConfigOption::getFloat(idx) on a non-numeric arrray ConfigOptionVectorBase"); }
  378. // We just overloaded and hid two base class virtual methods.
  379. // Let's show it was intentional (warnings).
  380. using ConfigOption::set;
  381. using ConfigOption::is_nil;
  382. protected:
  383. // Used to verify type compatibility when assigning to / from a scalar ConfigOption.
  384. ConfigOptionType scalar_type() const { return static_cast<ConfigOptionType>(this->type() - coVectorType); }
  385. };
  386. // Value of a vector valued option (bools, ints, floats, strings, points), template
  387. template <class T>
  388. class ConfigOptionVector : public ConfigOptionVectorBase
  389. {
  390. public:
  391. ConfigOptionVector() {}
  392. explicit ConfigOptionVector(const T& default_val) : default_value(default_val) {}
  393. explicit ConfigOptionVector(size_t n, const T& value) : values(n, value) {}
  394. explicit ConfigOptionVector(std::initializer_list<T> il) : values(std::move(il)) {}
  395. explicit ConfigOptionVector(const std::vector<T> &values) : values(values) {}
  396. explicit ConfigOptionVector(std::vector<T> &&values) : values(std::move(values)) {}
  397. std::vector<T> values;
  398. T default_value;
  399. void set(const ConfigOption *rhs) override
  400. {
  401. if (rhs->type() != this->type())
  402. throw ConfigurationError("ConfigOptionVector: Assigning an incompatible type");
  403. assert(dynamic_cast<const ConfigOptionVector<T>*>(rhs));
  404. this->values = static_cast<const ConfigOptionVector<T>*>(rhs)->values;
  405. this->flags = rhs->flags;
  406. }
  407. // Set from a vector of ConfigOptions.
  408. // If the rhs ConfigOption is scalar, then its value is used,
  409. // otherwise for each of rhs, the first value of a vector is used.
  410. // This function is useful to collect values for multiple extrder / filament settings.
  411. void set(const std::vector<const ConfigOption*> &rhs) override
  412. {
  413. this->values.clear();
  414. this->values.reserve(rhs.size());
  415. for (const ConfigOption *opt : rhs) {
  416. if (opt->type() == this->type()) {
  417. auto other = static_cast<const ConfigOptionVector<T>*>(opt);
  418. if (other->values.empty())
  419. throw ConfigurationError("ConfigOptionVector::set(): Assigning from an empty vector");
  420. this->values.emplace_back(other->values.front());
  421. } else if (opt->type() == this->scalar_type())
  422. this->values.emplace_back(static_cast<const ConfigOptionSingle<T>*>(opt)->value);
  423. else
  424. throw ConfigurationError("ConfigOptionVector::set():: Assigning an incompatible type");
  425. }
  426. }
  427. // Set a single vector item from either a scalar option or the first value of a vector option.vector of ConfigOptions.
  428. // This function is useful to split values from multiple extrder / filament settings into separate configurations.
  429. void set_at(const ConfigOption *rhs, size_t i, size_t j) override
  430. {
  431. // It is expected that the vector value has at least one value, which is the default, if not overwritten.
  432. assert(! this->values.empty());
  433. if (this->values.size() <= i) {
  434. // Resize this vector, fill in the new vector fields with the copy of the first field.
  435. T v = this->values.front();
  436. this->values.resize(i + 1, v);
  437. }
  438. if (rhs->type() == this->type()) {
  439. // Assign the first value of the rhs vector.
  440. auto other = static_cast<const ConfigOptionVector<T>*>(rhs);
  441. if (other->values.empty())
  442. throw ConfigurationError("ConfigOptionVector::set_at(): Assigning from an empty vector");
  443. this->values[i] = other->get_at(j);
  444. } else if (rhs->type() == this->scalar_type())
  445. this->values[i] = static_cast<const ConfigOptionSingle<T>*>(rhs)->value;
  446. else
  447. throw ConfigurationError("ConfigOptionVector::set_at(): Assigning an incompatible type");
  448. }
  449. const T& get_at(size_t i) const
  450. {
  451. //assert(! this->values.empty());
  452. return (i < this->values.size()) ? this->values[i] : (this->values.empty()? default_value : this->values.front());
  453. }
  454. T& get_at(size_t i) { return const_cast<T&>(std::as_const(*this).get_at(i)); }
  455. // Resize this vector by duplicating the /*last*/first value.
  456. // If the current vector is empty, the default value is used instead.
  457. void resize(size_t n, const ConfigOption *opt_default = nullptr) override
  458. {
  459. assert(opt_default == nullptr || opt_default->is_vector());
  460. // assert(opt_default == nullptr || dynamic_cast<ConfigOptionVector<T>>(opt_default));
  461. assert(! this->values.empty() || opt_default != nullptr);
  462. if (n == 0)
  463. this->values.clear();
  464. else if (n < this->values.size())
  465. this->values.erase(this->values.begin() + n, this->values.end());
  466. else if (n > this->values.size()) {
  467. if (this->values.empty()) {
  468. if (opt_default == nullptr)
  469. this->values.resize(n, this->default_value);
  470. if (opt_default->type() != this->type())
  471. throw ConfigurationError("ConfigOptionVector::resize(): Extending with an incompatible type.");
  472. if(static_cast<const ConfigOptionVector<T>*>(opt_default)->values.empty())
  473. this->values.resize(n, this->default_value);
  474. else
  475. this->values.resize(n, static_cast<const ConfigOptionVector<T>*>(opt_default)->values.front());
  476. } else {
  477. // Resize by duplicating the last value.
  478. this->values.resize(n, this->values./*back*/front());
  479. }
  480. }
  481. }
  482. // Clear the values vector.
  483. void clear() override { this->values.clear(); }
  484. size_t size() const override { return this->values.size(); }
  485. bool empty() const override { return this->values.empty(); }
  486. bool operator==(const ConfigOption &rhs) const override
  487. {
  488. if (rhs.type() != this->type())
  489. throw ConfigurationError("ConfigOptionVector: Comparing incompatible types");
  490. assert(dynamic_cast<const ConfigOptionVector<T>*>(&rhs));
  491. return this->values == static_cast<const ConfigOptionVector<T>*>(&rhs)->values;
  492. }
  493. bool operator==(const std::vector<T> &rhs) const { return this->values == rhs; }
  494. bool operator!=(const std::vector<T> &rhs) const { return this->values != rhs; }
  495. // Is this option overridden by another option?
  496. // An option overrides another option if it is not nil and not equal.
  497. bool overriden_by(const ConfigOption *rhs) const override {
  498. if (this->nullable())
  499. throw ConfigurationError("Cannot override a nullable ConfigOption.");
  500. if (rhs->type() != this->type())
  501. throw ConfigurationError("ConfigOptionVector.overriden_by() applied to different types.");
  502. auto rhs_vec = static_cast<const ConfigOptionVector<T>*>(rhs);
  503. if (! rhs->nullable())
  504. // Overridding a non-nullable object with another non-nullable object.
  505. return this->values != rhs_vec->values;
  506. size_t i = 0;
  507. size_t cnt = std::min(this->size(), rhs_vec->size());
  508. for (; i < cnt; ++ i)
  509. if (! rhs_vec->is_nil(i) && this->values[i] != rhs_vec->values[i])
  510. return true;
  511. for (; i < rhs_vec->size(); ++ i)
  512. if (! rhs_vec->is_nil(i))
  513. return true;
  514. return false;
  515. }
  516. // Apply an override option, possibly a nullable one.
  517. bool apply_override(const ConfigOption *rhs) override {
  518. if (this->nullable())
  519. throw ConfigurationError("Cannot override a nullable ConfigOption.");
  520. if (rhs->type() != this->type())
  521. throw ConfigurationError("ConfigOptionVector.apply_override() applied to different types.");
  522. auto rhs_vec = static_cast<const ConfigOptionVector<T>*>(rhs);
  523. if (! rhs->nullable()) {
  524. // Overridding a non-nullable object with another non-nullable object.
  525. if (this->values != rhs_vec->values) {
  526. this->values = rhs_vec->values;
  527. return true;
  528. }
  529. return false;
  530. }
  531. size_t i = 0;
  532. size_t cnt = std::min(this->size(), rhs_vec->size());
  533. bool modified = false;
  534. for (; i < cnt; ++ i)
  535. if (! rhs_vec->is_nil(i) && this->values[i] != rhs_vec->values[i]) {
  536. this->values[i] = rhs_vec->values[i];
  537. modified = true;
  538. }
  539. for (; i < rhs_vec->size(); ++ i)
  540. if (! rhs_vec->is_nil(i)) {
  541. if (this->values.empty())
  542. this->values.resize(i + 1);
  543. else
  544. this->values.resize(i + 1, this->values.front());
  545. this->values[i] = rhs_vec->values[i];
  546. modified = true;
  547. }
  548. return modified;
  549. }
  550. private:
  551. friend class cereal::access;
  552. template<class Archive> void serialize(Archive & ar) { ar(this->flags); ar(this->values); }
  553. };
  554. class ConfigOptionFloat : public ConfigOptionSingle<double>
  555. {
  556. public:
  557. ConfigOptionFloat() : ConfigOptionSingle<double>(0) {}
  558. explicit ConfigOptionFloat(double _value) : ConfigOptionSingle<double>(_value) {}
  559. explicit ConfigOptionFloat(double _value, bool _phony) : ConfigOptionSingle<double>(_value, _phony) {}
  560. static ConfigOptionType static_type() { return coFloat; }
  561. ConfigOptionType type() const override { return static_type(); }
  562. double getFloat() const override { return this->value; }
  563. ConfigOption* clone() const override { return new ConfigOptionFloat(*this); }
  564. bool operator==(const ConfigOptionFloat &rhs) const { return this->value == rhs.value; }
  565. std::string serialize() const override
  566. {
  567. std::ostringstream ss;
  568. ss << this->value;
  569. return ss.str();
  570. }
  571. bool deserialize(const std::string &str, bool append = false) override
  572. {
  573. UNUSED(append);
  574. std::istringstream iss(str);
  575. iss >> this->value;
  576. return !iss.fail();
  577. }
  578. ConfigOptionFloat& operator=(const ConfigOption *opt)
  579. {
  580. this->set(opt);
  581. return *this;
  582. }
  583. private:
  584. friend class cereal::access;
  585. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<double>>(this)); }
  586. };
  587. template<bool NULLABLE>
  588. class ConfigOptionFloatsTempl : public ConfigOptionVector<double>
  589. {
  590. public:
  591. ConfigOptionFloatsTempl() : ConfigOptionVector<double>() {}
  592. explicit ConfigOptionFloatsTempl(double default_value) : ConfigOptionVector<double>(default_value) {}
  593. explicit ConfigOptionFloatsTempl(size_t n, double value) : ConfigOptionVector<double>(n, value) {}
  594. explicit ConfigOptionFloatsTempl(std::initializer_list<double> il) : ConfigOptionVector<double>(std::move(il)) {}
  595. explicit ConfigOptionFloatsTempl(const std::vector<double> &vec) : ConfigOptionVector<double>(vec) {}
  596. explicit ConfigOptionFloatsTempl(std::vector<double> &&vec) : ConfigOptionVector<double>(std::move(vec)) {}
  597. static ConfigOptionType static_type() { return coFloats; }
  598. ConfigOptionType type() const override { return static_type(); }
  599. ConfigOption* clone() const override { return new ConfigOptionFloatsTempl(*this); }
  600. bool operator==(const ConfigOptionFloatsTempl &rhs) const { return vectors_equal(this->values, rhs.values); }
  601. bool operator==(const ConfigOption &rhs) const override {
  602. if (rhs.type() != this->type())
  603. throw ConfigurationError("ConfigOptionFloatsTempl: Comparing incompatible types");
  604. assert(dynamic_cast<const ConfigOptionVector<double>*>(&rhs));
  605. return vectors_equal(this->values, static_cast<const ConfigOptionVector<double>*>(&rhs)->values);
  606. }
  607. // Could a special "nil" value be stored inside the vector, indicating undefined value?
  608. bool nullable() const override { return NULLABLE; }
  609. // Special "nil" value to be stored into the vector if this->supports_nil().
  610. static double nil_value() { return std::numeric_limits<double>::quiet_NaN(); }
  611. // A scalar is nil, or all values of a vector are nil.
  612. bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v)) return false; return true; }
  613. bool is_nil(size_t idx) const override { return std::isnan(this->values[idx]); }
  614. virtual double getFloat(int idx) const override { return values[idx]; }
  615. std::string serialize() const override
  616. {
  617. std::ostringstream ss;
  618. for (const double &v : this->values) {
  619. if (&v != &this->values.front())
  620. ss << ",";
  621. serialize_single_value(ss, v);
  622. }
  623. return ss.str();
  624. }
  625. std::vector<std::string> vserialize() const override
  626. {
  627. std::vector<std::string> vv;
  628. vv.reserve(this->values.size());
  629. for (const double v : this->values) {
  630. std::ostringstream ss;
  631. serialize_single_value(ss, v);
  632. vv.push_back(ss.str());
  633. }
  634. return vv;
  635. }
  636. bool deserialize(const std::string &str, bool append = false) override
  637. {
  638. if (! append)
  639. this->values.clear();
  640. std::istringstream is(str);
  641. std::string item_str;
  642. while (std::getline(is, item_str, ',')) {
  643. boost::trim(item_str);
  644. if (item_str == "nil") {
  645. if (NULLABLE)
  646. this->values.push_back(nil_value());
  647. else
  648. throw ConfigurationError("Deserializing nil into a non-nullable object");
  649. } else {
  650. std::istringstream iss(item_str);
  651. double value;
  652. iss >> value;
  653. this->values.push_back(value);
  654. }
  655. }
  656. return true;
  657. }
  658. ConfigOptionFloatsTempl& operator=(const ConfigOption *opt)
  659. {
  660. this->set(opt);
  661. return *this;
  662. }
  663. protected:
  664. void serialize_single_value(std::ostringstream &ss, const double v) const {
  665. if (std::isfinite(v))
  666. ss << v;
  667. else if (std::isnan(v)) {
  668. if (NULLABLE)
  669. ss << "nil";
  670. else
  671. throw ConfigurationError("Serializing NaN");
  672. } else
  673. throw ConfigurationError("Serializing invalid number");
  674. }
  675. static bool vectors_equal(const std::vector<double> &v1, const std::vector<double> &v2) {
  676. if (NULLABLE) {
  677. if (v1.size() != v2.size())
  678. return false;
  679. for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end(); ++ it1, ++ it2)
  680. if (! ((std::isnan(*it1) && std::isnan(*it2)) || *it1 == *it2))
  681. return false;
  682. return true;
  683. } else
  684. // Not supporting nullable values, the default vector compare is cheaper.
  685. return v1 == v2;
  686. }
  687. private:
  688. friend class cereal::access;
  689. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<double>>(this)); }
  690. };
  691. using ConfigOptionFloats = ConfigOptionFloatsTempl<false>;
  692. using ConfigOptionFloatsNullable = ConfigOptionFloatsTempl<true>;
  693. class ConfigOptionInt : public ConfigOptionSingle<int32_t>
  694. {
  695. public:
  696. ConfigOptionInt() : ConfigOptionSingle<int32_t>(0) {}
  697. explicit ConfigOptionInt(int32_t value) : ConfigOptionSingle<int32_t>(value) {}
  698. explicit ConfigOptionInt(double _value) : ConfigOptionSingle<int32_t>(int32_t(floor(_value + 0.5))) {}
  699. static ConfigOptionType static_type() { return coInt; }
  700. ConfigOptionType type() const override { return static_type(); }
  701. int32_t getInt() const override { return this->value; }
  702. void setInt(int32_t val) override { this->value = val; }
  703. ConfigOption* clone() const override { return new ConfigOptionInt(*this); }
  704. bool operator==(const ConfigOptionInt &rhs) const { return this->value == rhs.value; }
  705. std::string serialize() const override
  706. {
  707. std::ostringstream ss;
  708. ss << this->value;
  709. return ss.str();
  710. }
  711. bool deserialize(const std::string &str, bool append = false) override
  712. {
  713. UNUSED(append);
  714. std::istringstream iss(str);
  715. iss >> this->value;
  716. return !iss.fail();
  717. }
  718. ConfigOptionInt& operator=(const ConfigOption *opt)
  719. {
  720. this->set(opt);
  721. return *this;
  722. }
  723. private:
  724. friend class cereal::access;
  725. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<int32_t>>(this)); }
  726. };
  727. template<bool NULLABLE>
  728. class ConfigOptionIntsTempl : public ConfigOptionVector<int32_t>
  729. {
  730. public:
  731. ConfigOptionIntsTempl() : ConfigOptionVector<int32_t>() {}
  732. explicit ConfigOptionIntsTempl(int32_t default_value) : ConfigOptionVector<int32_t>(default_value) {}
  733. explicit ConfigOptionIntsTempl(size_t n, int32_t value) : ConfigOptionVector<int32_t>(n, value) {}
  734. explicit ConfigOptionIntsTempl(std::initializer_list<int32_t> il) : ConfigOptionVector<int32_t>(std::move(il)) {}
  735. static ConfigOptionType static_type() { return coInts; }
  736. ConfigOptionType type() const override { return static_type(); }
  737. ConfigOption* clone() const override { return new ConfigOptionIntsTempl(*this); }
  738. ConfigOptionIntsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
  739. bool operator==(const ConfigOptionIntsTempl &rhs) const { return this->values == rhs.values; }
  740. // Could a special "nil" value be stored inside the vector, indicating undefined value?
  741. bool nullable() const override { return NULLABLE; }
  742. // Special "nil" value to be stored into the vector if this->supports_nil().
  743. static int32_t nil_value() { return std::numeric_limits<int32_t>::max(); }
  744. // A scalar is nil, or all values of a vector are nil.
  745. bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; }
  746. bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); }
  747. virtual double getFloat(int idx) const override { return values[idx]; }
  748. std::string serialize() const override
  749. {
  750. std::ostringstream ss;
  751. for (const int32_t &v : this->values) {
  752. if (&v != &this->values.front())
  753. ss << ",";
  754. serialize_single_value(ss, v);
  755. }
  756. return ss.str();
  757. }
  758. std::vector<std::string> vserialize() const override
  759. {
  760. std::vector<std::string> vv;
  761. vv.reserve(this->values.size());
  762. for (const int32_t v : this->values) {
  763. std::ostringstream ss;
  764. serialize_single_value(ss, v);
  765. vv.push_back(ss.str());
  766. }
  767. return vv;
  768. }
  769. bool deserialize(const std::string &str, bool append = false) override
  770. {
  771. if (! append)
  772. this->values.clear();
  773. std::istringstream is(str);
  774. std::string item_str;
  775. while (std::getline(is, item_str, ',')) {
  776. boost::trim(item_str);
  777. if (item_str == "nil") {
  778. if (NULLABLE)
  779. this->values.push_back(nil_value());
  780. else
  781. throw ConfigurationError("Deserializing nil into a non-nullable object");
  782. } else {
  783. std::istringstream iss(item_str);
  784. int32_t value;
  785. iss >> value;
  786. this->values.push_back(value);
  787. }
  788. }
  789. return true;
  790. }
  791. private:
  792. void serialize_single_value(std::ostringstream &ss, const int32_t v) const {
  793. if (v == nil_value()) {
  794. if (NULLABLE)
  795. ss << "nil";
  796. else
  797. throw ConfigurationError("Serializing NaN");
  798. } else
  799. ss << v;
  800. }
  801. friend class cereal::access;
  802. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<int32_t>>(this)); }
  803. };
  804. using ConfigOptionInts = ConfigOptionIntsTempl<false>;
  805. using ConfigOptionIntsNullable = ConfigOptionIntsTempl<true>;
  806. class ConfigOptionString : public ConfigOptionSingle<std::string>
  807. {
  808. public:
  809. ConfigOptionString() : ConfigOptionSingle<std::string>("") {}
  810. explicit ConfigOptionString(const std::string &value) : ConfigOptionSingle<std::string>(value) {}
  811. static ConfigOptionType static_type() { return coString; }
  812. ConfigOptionType type() const override { return static_type(); }
  813. ConfigOption* clone() const override { return new ConfigOptionString(*this); }
  814. ConfigOptionString& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
  815. bool operator==(const ConfigOptionString &rhs) const { return this->value == rhs.value; }
  816. bool empty() const { return this->value.empty(); }
  817. std::string serialize() const override
  818. {
  819. return escape_string_cstyle(this->value);
  820. }
  821. bool deserialize(const std::string &str, bool append = false) override
  822. {
  823. UNUSED(append);
  824. return unescape_string_cstyle(str, this->value);
  825. }
  826. private:
  827. friend class cereal::access;
  828. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<std::string>>(this)); }
  829. };
  830. // semicolon-separated strings
  831. class ConfigOptionStrings : public ConfigOptionVector<std::string>
  832. {
  833. public:
  834. ConfigOptionStrings() : ConfigOptionVector<std::string>() {}
  835. explicit ConfigOptionStrings(const std::string& value) : ConfigOptionVector<std::string>(value) {}
  836. explicit ConfigOptionStrings(size_t n, const std::string& value) : ConfigOptionVector<std::string>(n, value) {}
  837. explicit ConfigOptionStrings(const std::vector<std::string> &values) : ConfigOptionVector<std::string>(values) {}
  838. explicit ConfigOptionStrings(std::vector<std::string> &&values) : ConfigOptionVector<std::string>(std::move(values)) {}
  839. explicit ConfigOptionStrings(std::initializer_list<std::string> il) : ConfigOptionVector<std::string>(std::move(il)) {}
  840. static ConfigOptionType static_type() { return coStrings; }
  841. ConfigOptionType type() const override { return static_type(); }
  842. ConfigOption* clone() const override { return new ConfigOptionStrings(*this); }
  843. ConfigOptionStrings& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
  844. bool operator==(const ConfigOptionStrings &rhs) const { return this->values == rhs.values; }
  845. bool is_nil(size_t) const override { return false; }
  846. std::string serialize() const override
  847. {
  848. return escape_strings_cstyle(this->values);
  849. }
  850. std::vector<std::string> vserialize() const override
  851. {
  852. return this->values;
  853. }
  854. bool deserialize(const std::string &str, bool append = false) override
  855. {
  856. if (! append)
  857. this->values.clear();
  858. return unescape_strings_cstyle(str, this->values);
  859. }
  860. private:
  861. friend class cereal::access;
  862. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<std::string>>(this)); }
  863. };
  864. class ConfigOptionPercent : public ConfigOptionFloat
  865. {
  866. public:
  867. ConfigOptionPercent() : ConfigOptionFloat(0) {}
  868. explicit ConfigOptionPercent(double _value) : ConfigOptionFloat(_value) {}
  869. explicit ConfigOptionPercent(double _value, bool _phony) : ConfigOptionFloat(_value, _phony) {}
  870. static ConfigOptionType static_type() { return coPercent; }
  871. ConfigOptionType type() const override { return static_type(); }
  872. ConfigOption* clone() const override { return new ConfigOptionPercent(*this); }
  873. ConfigOptionPercent& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
  874. bool operator==(const ConfigOptionPercent &rhs) const { return this->value == rhs.value; }
  875. double get_abs_value(double ratio_over) const { return ratio_over * this->value / 100.; }
  876. std::string serialize() const override
  877. {
  878. std::ostringstream ss;
  879. ss << this->value;
  880. std::string s(ss.str());
  881. s += "%";
  882. return s;
  883. }
  884. bool deserialize(const std::string &str, bool append = false) override
  885. {
  886. UNUSED(append);
  887. // don't try to parse the trailing % since it's optional
  888. std::istringstream iss(str);
  889. iss >> this->value;
  890. return !iss.fail();
  891. }
  892. private:
  893. friend class cereal::access;
  894. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloat>(this)); }
  895. };
  896. template<bool NULLABLE>
  897. class ConfigOptionPercentsTempl : public ConfigOptionFloatsTempl<NULLABLE>
  898. {
  899. public:
  900. ConfigOptionPercentsTempl() : ConfigOptionFloatsTempl<NULLABLE>() {}
  901. explicit ConfigOptionPercentsTempl(double default_value) : ConfigOptionFloatsTempl<NULLABLE>(default_value) {}
  902. explicit ConfigOptionPercentsTempl(size_t n, double value) : ConfigOptionFloatsTempl<NULLABLE>(n, value) {}
  903. explicit ConfigOptionPercentsTempl(std::initializer_list<double> il) : ConfigOptionFloatsTempl<NULLABLE>(std::move(il)) {}
  904. explicit ConfigOptionPercentsTempl(const std::vector<double>& vec) : ConfigOptionFloatsTempl<NULLABLE>(vec) {}
  905. explicit ConfigOptionPercentsTempl(std::vector<double>&& vec) : ConfigOptionFloatsTempl<NULLABLE>(std::move(vec)) {}
  906. static ConfigOptionType static_type() { return coPercents; }
  907. ConfigOptionType type() const override { return static_type(); }
  908. ConfigOption* clone() const override { return new ConfigOptionPercentsTempl(*this); }
  909. ConfigOptionPercentsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
  910. bool operator==(const ConfigOptionPercentsTempl &rhs) const { return this->values == rhs.values; }
  911. double get_abs_value(size_t i, double ratio_over) const { return this->is_nil(i) ? 0 : ratio_over * this->get_at(i) / 100; }
  912. std::string serialize() const override
  913. {
  914. std::ostringstream ss;
  915. for (const double &v : this->values) {
  916. if (&v != &this->values.front())
  917. ss << ",";
  918. this->serialize_single_value(ss, v);
  919. if (! std::isnan(v))
  920. ss << "%";
  921. }
  922. std::string str = ss.str();
  923. return str;
  924. }
  925. std::vector<std::string> vserialize() const override
  926. {
  927. std::vector<std::string> vv;
  928. vv.reserve(this->values.size());
  929. for (const double v : this->values) {
  930. std::ostringstream ss;
  931. this->serialize_single_value(ss, v);
  932. if (! std::isnan(v))
  933. ss << "%";
  934. vv.push_back(ss.str());
  935. }
  936. return vv;
  937. }
  938. // The float's deserialize function shall ignore the trailing optional %.
  939. // bool deserialize(const std::string &str, bool append = false) override;
  940. private:
  941. friend class cereal::access;
  942. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloatsTempl<NULLABLE>>(this)); }
  943. };
  944. using ConfigOptionPercents = ConfigOptionPercentsTempl<false>;
  945. using ConfigOptionPercentsNullable = ConfigOptionPercentsTempl<true>;
  946. class ConfigOptionFloatOrPercent : public ConfigOptionPercent
  947. {
  948. public:
  949. bool percent;
  950. ConfigOptionFloatOrPercent() : ConfigOptionPercent(0), percent(false) {}
  951. explicit ConfigOptionFloatOrPercent(double _value, bool _percent) : ConfigOptionPercent(_value), percent(_percent) {}
  952. explicit ConfigOptionFloatOrPercent(double _value, bool _percent, bool _phony) : ConfigOptionPercent(_value, _phony), percent(_percent) {}
  953. static ConfigOptionType static_type() { return coFloatOrPercent; }
  954. ConfigOptionType type() const override { return static_type(); }
  955. ConfigOption* clone() const override { return new ConfigOptionFloatOrPercent(*this); }
  956. ConfigOptionFloatOrPercent& operator=(const ConfigOption* opt) { this->set(opt); return *this; }
  957. bool operator==(const ConfigOption &rhs) const override
  958. {
  959. if (rhs.type() != this->type())
  960. throw ConfigurationError("ConfigOptionFloatOrPercent: Comparing incompatible types");
  961. assert(dynamic_cast<const ConfigOptionFloatOrPercent*>(&rhs));
  962. return *this == *static_cast<const ConfigOptionFloatOrPercent*>(&rhs);
  963. }
  964. bool operator==(const ConfigOptionFloatOrPercent &rhs) const
  965. { return this->value == rhs.value && this->percent == rhs.percent; }
  966. double get_abs_value(double ratio_over) const
  967. { return this->percent ? (ratio_over * this->value / 100) : this->value; }
  968. void set(const ConfigOption *rhs) override {
  969. if (rhs->type() != this->type())
  970. throw ConfigurationError("ConfigOptionFloatOrPercent: Assigning an incompatible type");
  971. assert(dynamic_cast<const ConfigOptionFloatOrPercent*>(rhs));
  972. *this = *static_cast<const ConfigOptionFloatOrPercent*>(rhs);
  973. }
  974. std::string serialize() const override
  975. {
  976. std::ostringstream ss;
  977. ss << this->value;
  978. std::string s(ss.str());
  979. if (this->percent) s += "%";
  980. return s;
  981. }
  982. bool deserialize(const std::string &str, bool append = false) override
  983. {
  984. UNUSED(append);
  985. this->percent = str.find_first_of("%") != std::string::npos;
  986. std::istringstream iss(str);
  987. iss >> this->value;
  988. return !iss.fail();
  989. }
  990. private:
  991. friend class cereal::access;
  992. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionPercent>(this), percent); }
  993. };
  994. struct FloatOrPercent
  995. {
  996. public:
  997. double value;
  998. bool percent;
  999. double get_abs_value(double ratio) const { return percent ? value * ratio : value; }
  1000. private:
  1001. friend class cereal::access;
  1002. template<class Archive> void serialize(Archive & ar) {ar(this->value); ar(this->percent); }
  1003. };
  1004. inline bool operator==(const FloatOrPercent &l, const FloatOrPercent &r)
  1005. {
  1006. return l.value == r.value && l.percent == r.percent;
  1007. }
  1008. inline bool operator!=(const FloatOrPercent& l, const FloatOrPercent& r)
  1009. {
  1010. return !(l == r);
  1011. }
  1012. template<bool NULLABLE>
  1013. class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVector<FloatOrPercent>
  1014. {
  1015. public:
  1016. ConfigOptionFloatsOrPercentsTempl() : ConfigOptionVector<FloatOrPercent>() {}
  1017. explicit ConfigOptionFloatsOrPercentsTempl(FloatOrPercent default_value) : ConfigOptionVector<FloatOrPercent>(default_value) {}
  1018. explicit ConfigOptionFloatsOrPercentsTempl(size_t n, FloatOrPercent value) : ConfigOptionVector<FloatOrPercent>(n, value) {}
  1019. explicit ConfigOptionFloatsOrPercentsTempl(std::initializer_list<FloatOrPercent> il) : ConfigOptionVector<FloatOrPercent>(std::move(il)) {}
  1020. explicit ConfigOptionFloatsOrPercentsTempl(const std::vector<FloatOrPercent> &vec) : ConfigOptionVector<FloatOrPercent>(vec) {}
  1021. explicit ConfigOptionFloatsOrPercentsTempl(std::vector<FloatOrPercent> &&vec) : ConfigOptionVector<FloatOrPercent>(std::move(vec)) {}
  1022. static ConfigOptionType static_type() { return coFloatsOrPercents; }
  1023. ConfigOptionType type() const override { return static_type(); }
  1024. ConfigOption* clone() const override { return new ConfigOptionFloatsOrPercentsTempl(*this); }
  1025. bool operator==(const ConfigOptionFloatsOrPercentsTempl &rhs) const { return vectors_equal(this->values, rhs.values); }
  1026. bool operator==(const ConfigOption &rhs) const override {
  1027. if (rhs.type() != this->type())
  1028. throw ConfigurationError("ConfigOptionFloatsOrPercentsTempl: Comparing incompatible types");
  1029. assert(dynamic_cast<const ConfigOptionVector<FloatOrPercent>*>(&rhs));
  1030. return vectors_equal(this->values, static_cast<const ConfigOptionVector<FloatOrPercent>*>(&rhs)->values);
  1031. }
  1032. // Could a special "nil" value be stored inside the vector, indicating undefined value?
  1033. bool nullable() const override { return NULLABLE; }
  1034. // Special "nil" value to be stored into the vector if this->supports_nil().
  1035. static FloatOrPercent nil_value() { return { std::numeric_limits<double>::quiet_NaN(), false }; }
  1036. // A scalar is nil, or all values of a vector are nil.
  1037. bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v.value)) return false; return true; }
  1038. bool is_nil(size_t idx) const override { return std::isnan(this->values[idx].value); }
  1039. double get_abs_value(size_t i, double ratio_over) const {
  1040. if (this->is_nil(i)) return 0;
  1041. const FloatOrPercent& data = this->get_at(i);
  1042. if (data.percent) return ratio_over * data.value / 100;
  1043. return data.value;
  1044. }
  1045. std::string serialize() const override
  1046. {
  1047. std::ostringstream ss;
  1048. for (const FloatOrPercent &v : this->values) {
  1049. if (&v != &this->values.front())
  1050. ss << ",";
  1051. serialize_single_value(ss, v);
  1052. }
  1053. return ss.str();
  1054. }
  1055. std::vector<std::string> vserialize() const override
  1056. {
  1057. std::vector<std::string> vv;
  1058. vv.reserve(this->values.size());
  1059. for (const FloatOrPercent &v : this->values) {
  1060. std::ostringstream ss;
  1061. serialize_single_value(ss, v);
  1062. vv.push_back(ss.str());
  1063. }
  1064. return vv;
  1065. }
  1066. bool deserialize(const std::string &str, bool append = false) override
  1067. {
  1068. if (! append)
  1069. this->values.clear();
  1070. std::istringstream is(str);
  1071. std::string item_str;
  1072. while (std::getline(is, item_str, ',')) {
  1073. boost::trim(item_str);
  1074. if (item_str == "nil") {
  1075. if (NULLABLE)
  1076. this->values.push_back(nil_value());
  1077. else
  1078. throw ConfigurationError("Deserializing nil into a non-nullable object");
  1079. } else {
  1080. bool percent = item_str.find_first_of("%") != std::string::npos;
  1081. std::istringstream iss(item_str);
  1082. double value;
  1083. iss >> value;
  1084. this->values.push_back({ value, percent });
  1085. }
  1086. }
  1087. return true;
  1088. }
  1089. ConfigOptionFloatsOrPercentsTempl& operator=(const ConfigOption *opt)
  1090. {
  1091. this->set(opt);
  1092. return *this;
  1093. }
  1094. protected:
  1095. void serialize_single_value(std::ostringstream &ss, const FloatOrPercent &v) const {
  1096. if (std::isfinite(v.value)) {
  1097. ss << v.value;
  1098. if (v.percent)
  1099. ss << "%";
  1100. } else if (std::isnan(v.value)) {
  1101. if (NULLABLE)
  1102. ss << "nil";
  1103. else
  1104. throw ConfigurationError("Serializing NaN");
  1105. } else
  1106. throw ConfigurationError("Serializing invalid number");
  1107. }
  1108. static bool vectors_equal(const std::vector<FloatOrPercent> &v1, const std::vector<FloatOrPercent> &v2) {
  1109. if (NULLABLE) {
  1110. if (v1.size() != v2.size())
  1111. return false;
  1112. for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end(); ++ it1, ++ it2)
  1113. if (! ((std::isnan(it1->value) && std::isnan(it2->value)) || *it1 == *it2))
  1114. return false;
  1115. return true;
  1116. } else
  1117. // Not supporting nullable values, the default vector compare is cheaper.
  1118. return v1 == v2;
  1119. }
  1120. private:
  1121. friend class cereal::access;
  1122. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<FloatOrPercent>>(this)); }
  1123. };
  1124. using ConfigOptionFloatsOrPercents = ConfigOptionFloatsOrPercentsTempl<false>;
  1125. using ConfigOptionFloatsOrPercentsNullable = ConfigOptionFloatsOrPercentsTempl<true>;
  1126. class ConfigOptionPoint : public ConfigOptionSingle<Vec2d>
  1127. {
  1128. public:
  1129. ConfigOptionPoint() : ConfigOptionSingle<Vec2d>(Vec2d(0,0)) {}
  1130. explicit ConfigOptionPoint(const Vec2d &value) : ConfigOptionSingle<Vec2d>(value) {}
  1131. static ConfigOptionType static_type() { return coPoint; }
  1132. ConfigOptionType type() const override { return static_type(); }
  1133. ConfigOption* clone() const override { return new ConfigOptionPoint(*this); }
  1134. ConfigOptionPoint& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
  1135. bool operator==(const ConfigOptionPoint &rhs) const { return this->value == rhs.value; }
  1136. std::string serialize() const override
  1137. {
  1138. std::ostringstream ss;
  1139. ss << this->value(0);
  1140. ss << ",";
  1141. ss << this->value(1);
  1142. return ss.str();
  1143. }
  1144. bool deserialize(const std::string &str, bool append = false) override
  1145. {
  1146. UNUSED(append);
  1147. char dummy;
  1148. return sscanf(str.data(), " %lf , %lf %c", &this->value(0), &this->value(1), &dummy) == 2 ||
  1149. sscanf(str.data(), " %lf x %lf %c", &this->value(0), &this->value(1), &dummy) == 2;
  1150. }
  1151. private:
  1152. friend class cereal::access;
  1153. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<Vec2d>>(this)); }
  1154. };
  1155. class ConfigOptionPoints : public ConfigOptionVector<Vec2d>
  1156. {
  1157. public:
  1158. ConfigOptionPoints() : ConfigOptionVector<Vec2d>() {}
  1159. explicit ConfigOptionPoints(const Vec2d& value) : ConfigOptionVector<Vec2d>(value) {}
  1160. explicit ConfigOptionPoints(size_t n, const Vec2d& value) : ConfigOptionVector<Vec2d>(n, value) {}
  1161. explicit ConfigOptionPoints(std::initializer_list<Vec2d> il) : ConfigOptionVector<Vec2d>(std::move(il)) {}
  1162. explicit ConfigOptionPoints(const std::vector<Vec2d> &values) : ConfigOptionVector<Vec2d>(values) {}
  1163. static ConfigOptionType static_type() { return coPoints; }
  1164. ConfigOptionType type() const override { return static_type(); }
  1165. ConfigOption* clone() const override { return new ConfigOptionPoints(*this); }
  1166. ConfigOptionPoints& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
  1167. bool operator==(const ConfigOptionPoints &rhs) const { return this->values == rhs.values; }
  1168. bool is_nil(size_t) const override { return false; }
  1169. std::string serialize() const override
  1170. {
  1171. std::ostringstream ss;
  1172. for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
  1173. if (it - this->values.begin() != 0) ss << ",";
  1174. ss << (*it)(0);
  1175. ss << "x";
  1176. ss << (*it)(1);
  1177. }
  1178. return ss.str();
  1179. }
  1180. std::vector<std::string> vserialize() const override
  1181. {
  1182. std::vector<std::string> vv;
  1183. for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
  1184. std::ostringstream ss;
  1185. ss << *it;
  1186. vv.push_back(ss.str());
  1187. }
  1188. return vv;
  1189. }
  1190. bool deserialize(const std::string &str, bool append = false) override
  1191. {
  1192. if (! append)
  1193. this->values.clear();
  1194. std::istringstream is(str);
  1195. std::string point_str;
  1196. while (std::getline(is, point_str, ',')) {
  1197. Vec2d point(Vec2d::Zero());
  1198. std::istringstream iss(point_str);
  1199. std::string coord_str;
  1200. if (std::getline(iss, coord_str, 'x')) {
  1201. std::istringstream(coord_str) >> point(0);
  1202. if (std::getline(iss, coord_str, 'x')) {
  1203. std::istringstream(coord_str) >> point(1);
  1204. }
  1205. }
  1206. this->values.push_back(point);
  1207. }
  1208. return true;
  1209. }
  1210. private:
  1211. friend class cereal::access;
  1212. template<class Archive> void save(Archive& archive) const {
  1213. archive(flags);
  1214. size_t cnt = this->values.size();
  1215. archive(cnt);
  1216. archive.saveBinary((const char*)this->values.data(), sizeof(Vec2d) * cnt);
  1217. }
  1218. template<class Archive> void load(Archive& archive) {
  1219. archive(flags);
  1220. size_t cnt;
  1221. archive(cnt);
  1222. this->values.assign(cnt, Vec2d());
  1223. archive.loadBinary((char*)this->values.data(), sizeof(Vec2d) * cnt);
  1224. }
  1225. };
  1226. class ConfigOptionPoint3 : public ConfigOptionSingle<Vec3d>
  1227. {
  1228. public:
  1229. ConfigOptionPoint3() : ConfigOptionSingle<Vec3d>(Vec3d(0,0,0)) {}
  1230. explicit ConfigOptionPoint3(const Vec3d &value) : ConfigOptionSingle<Vec3d>(value) {}
  1231. static ConfigOptionType static_type() { return coPoint3; }
  1232. ConfigOptionType type() const override { return static_type(); }
  1233. ConfigOption* clone() const override { return new ConfigOptionPoint3(*this); }
  1234. ConfigOptionPoint3& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
  1235. bool operator==(const ConfigOptionPoint3 &rhs) const { return this->value == rhs.value; }
  1236. std::string serialize() const override
  1237. {
  1238. std::ostringstream ss;
  1239. ss << this->value(0);
  1240. ss << ",";
  1241. ss << this->value(1);
  1242. ss << ",";
  1243. ss << this->value(2);
  1244. return ss.str();
  1245. }
  1246. bool deserialize(const std::string &str, bool append = false) override
  1247. {
  1248. UNUSED(append);
  1249. char dummy;
  1250. return sscanf(str.data(), " %lf , %lf , %lf %c", &this->value(0), &this->value(1), &this->value(2), &dummy) == 2 ||
  1251. sscanf(str.data(), " %lf x %lf x %lf %c", &this->value(0), &this->value(1), &this->value(2), &dummy) == 2;
  1252. }
  1253. private:
  1254. friend class cereal::access;
  1255. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<Vec3d>>(this)); }
  1256. };
  1257. class ConfigOptionBool : public ConfigOptionSingle<bool>
  1258. {
  1259. public:
  1260. ConfigOptionBool() : ConfigOptionSingle<bool>(false) {}
  1261. explicit ConfigOptionBool(bool _value) : ConfigOptionSingle<bool>(_value) {}
  1262. static ConfigOptionType static_type() { return coBool; }
  1263. ConfigOptionType type() const override { return static_type(); }
  1264. bool getBool() const override { return this->value; }
  1265. ConfigOption* clone() const override { return new ConfigOptionBool(*this); }
  1266. ConfigOptionBool& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
  1267. bool operator==(const ConfigOptionBool &rhs) const { return this->value == rhs.value; }
  1268. std::string serialize() const override
  1269. {
  1270. return std::string(this->value ? "1" : "0");
  1271. }
  1272. bool deserialize(const std::string &str, bool append = false) override
  1273. {
  1274. UNUSED(append);
  1275. if (str == "1") {
  1276. this->value = true;
  1277. return true;
  1278. }
  1279. if (str == "0") {
  1280. this->value = false;
  1281. return true;
  1282. }
  1283. return false;
  1284. }
  1285. private:
  1286. friend class cereal::access;
  1287. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<bool>>(this)); }
  1288. };
  1289. template<bool NULLABLE>
  1290. class ConfigOptionBoolsTempl : public ConfigOptionVector<unsigned char>
  1291. {
  1292. public:
  1293. ConfigOptionBoolsTempl() : ConfigOptionVector<unsigned char>() {}
  1294. explicit ConfigOptionBoolsTempl(size_t n, bool value) : ConfigOptionVector<unsigned char>(n, (unsigned char)value) {}
  1295. explicit ConfigOptionBoolsTempl(std::initializer_list<bool> il) { values.reserve(il.size()); for (bool b : il) values.emplace_back((unsigned char)b); }
  1296. explicit ConfigOptionBoolsTempl(std::initializer_list<unsigned char> il) { values.reserve(il.size()); for (unsigned char b : il) values.emplace_back(b); }
  1297. explicit ConfigOptionBoolsTempl(const std::vector<unsigned char>& vec) : ConfigOptionVector<unsigned char>(vec) {}
  1298. explicit ConfigOptionBoolsTempl(std::vector<unsigned char>&& vec) : ConfigOptionVector<unsigned char>(std::move(vec)) {}
  1299. static ConfigOptionType static_type() { return coBools; }
  1300. ConfigOptionType type() const override { return static_type(); }
  1301. ConfigOption* clone() const override { return new ConfigOptionBoolsTempl(*this); }
  1302. ConfigOptionBoolsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
  1303. bool operator==(const ConfigOptionBoolsTempl &rhs) const { return this->values == rhs.values; }
  1304. // Could a special "nil" value be stored inside the vector, indicating undefined value?
  1305. bool nullable() const override { return NULLABLE; }
  1306. // Special "nil" value to be stored into the vector if this->supports_nil().
  1307. static unsigned char nil_value() { return std::numeric_limits<unsigned char>::max(); }
  1308. // A scalar is nil, or all values of a vector are nil.
  1309. bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; }
  1310. bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); }
  1311. virtual double getFloat(int idx) const override { return values[idx] ? 1 : 0; }
  1312. bool& get_at(size_t i) {
  1313. assert(! this->values.empty());
  1314. return *reinterpret_cast<bool*>(&((i < this->values.size()) ? this->values[i] : this->values.front()));
  1315. }
  1316. //FIXME this smells, the parent class has the method declared returning (unsigned char&).
  1317. bool get_at(size_t i) const { return ((i < this->values.size()) ? this->values[i] : this->values.front()) != 0; }
  1318. std::string serialize() const override
  1319. {
  1320. std::ostringstream ss;
  1321. for (const unsigned char &v : this->values) {
  1322. if (&v != &this->values.front())
  1323. ss << ",";
  1324. this->serialize_single_value(ss, v);
  1325. }
  1326. return ss.str();
  1327. }
  1328. std::vector<std::string> vserialize() const override
  1329. {
  1330. std::vector<std::string> vv;
  1331. for (const unsigned char v : this->values) {
  1332. std::ostringstream ss;
  1333. this->serialize_single_value(ss, v);
  1334. vv.push_back(ss.str());
  1335. }
  1336. return vv;
  1337. }
  1338. ConfigHelpers::DeserializationResult deserialize_with_substitutions(const std::string &str, bool append, ConfigHelpers::DeserializationSubstitution substitution)
  1339. {
  1340. if (! append)
  1341. this->values.clear();
  1342. std::istringstream is(str);
  1343. std::string item_str;
  1344. bool substituted = false;
  1345. while (std::getline(is, item_str, ',')) {
  1346. boost::trim(item_str);
  1347. unsigned char new_value = 0;
  1348. if (item_str == "nil") {
  1349. if (NULLABLE)
  1350. new_value = nil_value();
  1351. else
  1352. throw ConfigurationError("Deserializing nil into a non-nullable object");
  1353. } else if (item_str == "1") {
  1354. new_value = true;
  1355. } else if (item_str == "0") {
  1356. new_value = false;
  1357. } else if (substitution != ConfigHelpers::DeserializationSubstitution::Disabled && ConfigHelpers::looks_like_enum_value(item_str)) {
  1358. new_value = ConfigHelpers::enum_looks_like_true_value(item_str) || substitution == ConfigHelpers::DeserializationSubstitution::DefaultsToTrue;
  1359. substituted = true;
  1360. } else
  1361. return ConfigHelpers::DeserializationResult::Failed;
  1362. this->values.push_back(new_value);
  1363. }
  1364. return substituted ? ConfigHelpers::DeserializationResult::Substituted : ConfigHelpers::DeserializationResult::Loaded;
  1365. }
  1366. bool deserialize(const std::string &str, bool append = false) override
  1367. {
  1368. return this->deserialize_with_substitutions(str, append, ConfigHelpers::DeserializationSubstitution::Disabled) == ConfigHelpers::DeserializationResult::Loaded;
  1369. }
  1370. protected:
  1371. void serialize_single_value(std::ostringstream &ss, const unsigned char v) const {
  1372. if (v == nil_value()) {
  1373. if (NULLABLE)
  1374. ss << "nil";
  1375. else
  1376. throw ConfigurationError("Serializing NaN");
  1377. } else
  1378. ss << (v ? "1" : "0");
  1379. }
  1380. private:
  1381. friend class cereal::access;
  1382. template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<unsigned char>>(this)); }
  1383. };
  1384. using ConfigOptionBools = ConfigOptionBoolsTempl<false>;
  1385. using ConfigOptionBoolsNullable = ConfigOptionBoolsTempl<true>;
  1386. // Map from an enum integer value to an enum name.
  1387. typedef std::vector<std::string> t_config_enum_names;
  1388. // Map from an enum name to an enum integer value.
  1389. typedef std::map<std::string,int32_t> t_config_enum_values;
  1390. template <class T>
  1391. class ConfigOptionEnum : public ConfigOptionSingle<T>
  1392. {
  1393. public:
  1394. // by default, use the first value (0) of the T enum type
  1395. ConfigOptionEnum() : ConfigOptionSingle<T>(static_cast<T>(0)) {}
  1396. explicit ConfigOptionEnum(T _value) : ConfigOptionSingle<T>(_value) {}
  1397. static ConfigOptionType static_type() { return coEnum; }
  1398. ConfigOptionType type() const override { return static_type(); }
  1399. ConfigOption* clone() const override { return new ConfigOptionEnum<T>(*this); }
  1400. ConfigOptionEnum<T>& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
  1401. bool operator==(const ConfigOptionEnum<T> &rhs) const { return this->value == rhs.value; }
  1402. int32_t getInt() const override { return (int32_t)this->value; }
  1403. bool operator==(const ConfigOption &rhs) const override
  1404. {
  1405. if (rhs.type() != this->type())
  1406. throw ConfigurationError("ConfigOptionEnum<T>: Comparing incompatible types");
  1407. // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
  1408. return this->value == (T)rhs.getInt();
  1409. }
  1410. void set(const ConfigOption *rhs) override {
  1411. if (rhs->type() != this->type())
  1412. throw ConfigurationError("ConfigOptionEnum<T>: Assigning an incompatible type");
  1413. // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
  1414. this->value = (T)rhs->getInt();
  1415. this->flags = rhs->flags;
  1416. }
  1417. std::string serialize() const override
  1418. {
  1419. // as names are static-initialized, it's thread safe
  1420. static t_config_enum_names names = ConfigOptionEnum<T>::create_enum_names();
  1421. assert(static_cast<int32_t>(this->value) < int32_t(names.size()));
  1422. return names[static_cast<int32_t>(this->value)];
  1423. }
  1424. bool deserialize(const std::string &str, bool append = false) override
  1425. {
  1426. UNUSED(append);
  1427. return from_string(str, this->value);
  1428. }
  1429. static bool has(T value)
  1430. {
  1431. for (const std::pair<std::string, int32_t> &kvp : ConfigOptionEnum<T>::get_enum_values())
  1432. if (kvp.second == value)
  1433. return true;
  1434. return false;
  1435. }
  1436. // Map from an enum name to an enum integer value. Can be used for static initialisation
  1437. static t_config_enum_names create_enum_names()
  1438. {
  1439. t_config_enum_names names;
  1440. if (names.empty()) {
  1441. // Initialize the map.
  1442. const t_config_enum_values &enum_keys_map = ConfigOptionEnum<T>::get_enum_values();
  1443. int32_t cnt = 0;
  1444. for (const std::pair<std::string, int32_t> &kvp : enum_keys_map)
  1445. cnt = std::max(cnt, kvp.second);
  1446. cnt += 1;
  1447. names.assign(cnt, "");
  1448. for (const std::pair<std::string, int32_t> &kvp : enum_keys_map)
  1449. names[kvp.second] = kvp.first;
  1450. }
  1451. return names;
  1452. }
  1453. // Map from an enum name to an enum integer value.
  1454. static const t_config_enum_values& get_enum_values();
  1455. static bool from_string(const std::string &str, T &value)
  1456. {
  1457. const t_config_enum_values &enum_keys_map = ConfigOptionEnum<T>::get_enum_values();
  1458. auto it = enum_keys_map.find(str);
  1459. if (it == enum_keys_map.end())
  1460. return false;
  1461. value = static_cast<T>(it->second);
  1462. return true;
  1463. }
  1464. };
  1465. // Generic enum configuration value.
  1466. // We use this one in DynamicConfig objects when creating a config value object for ConfigOptionType == coEnum.
  1467. // In the StaticConfig, it is better to use the specialized ConfigOptionEnum<T> containers.
  1468. class ConfigOptionEnumGeneric : public ConfigOptionInt
  1469. {
  1470. public:
  1471. ConfigOptionEnumGeneric(const t_config_enum_values* keys_map = nullptr) : keys_map(keys_map) {}
  1472. explicit ConfigOptionEnumGeneric(const t_config_enum_values* keys_map, int32_t value) : ConfigOptionInt(value), keys_map(keys_map) {}
  1473. const t_config_enum_values* keys_map;
  1474. static ConfigOptionType static_type() { return coEnum; }
  1475. ConfigOptionType type() const override { return static_type(); }
  1476. ConfigOption* clone() const override { return new ConfigOptionEnumGeneric(*this); }
  1477. ConfigOptionEnumGeneric& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
  1478. bool operator==(const ConfigOptionEnumGeneric &rhs) const { return this->value == rhs.value; }
  1479. bool operator==(const ConfigOption &rhs) const override
  1480. {
  1481. if (rhs.type() != this->type())
  1482. throw ConfigurationError("ConfigOptionEnumGeneric: Comparing incompatible types");
  1483. // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
  1484. return this->value == rhs.getInt();
  1485. }
  1486. void set(const ConfigOption *rhs) override {
  1487. if (rhs->type() != this->type())
  1488. throw ConfigurationError("ConfigOptionEnumGeneric: Assigning an incompatible type");
  1489. // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
  1490. this->value = rhs->getInt();
  1491. this->flags = rhs->flags;
  1492. }
  1493. std::string serialize() const override
  1494. {
  1495. for (const auto &kvp : *this->keys_map)
  1496. if (kvp.second == this->value)
  1497. return kvp.first;
  1498. return std::string();
  1499. }
  1500. bool deserialize(const std::string &str, bool append = false) override
  1501. {
  1502. UNUSED(append);
  1503. auto it = this->keys_map->find(str);
  1504. if (it == this->keys_map->end())
  1505. return false;
  1506. this->value = it->second;
  1507. return true;
  1508. }
  1509. private:
  1510. friend class cereal::access;
  1511. template<class Archive> void serialize(Archive& ar) { ar(cereal::base_class<ConfigOptionInt>(this)); }
  1512. };
  1513. // Definition of a configuration value for the purpose of GUI presentation, editing, value mapping and config file handling.
  1514. class ConfigOptionDef
  1515. {
  1516. public:
  1517. // Identifier of this option. It is stored here so that it is accessible through the by_serialization_key_ordinal map.
  1518. t_config_option_key opt_key;
  1519. // What type? bool, int, string etc.
  1520. ConfigOptionType type = coNone;
  1521. // If a type is nullable, then it accepts a "nil" value (scalar) or "nil" values (vector).
  1522. bool nullable = false;
  1523. // Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor.
  1524. Slic3r::clonable_ptr<const ConfigOption> default_value;
  1525. void set_default_value(const ConfigOption* ptr) {
  1526. this->default_value = Slic3r::clonable_ptr<const ConfigOption>(ptr);
  1527. }
  1528. void set_default_value(ConfigOptionVectorBase* ptr) {
  1529. ptr->set_is_extruder_size(this->is_vector_extruder);
  1530. this->default_value = Slic3r::clonable_ptr<const ConfigOption>(ptr);
  1531. }
  1532. template<typename T> const T* get_default_value() const { return static_cast<const T*>(this->default_value.get()); }
  1533. // Create an empty option to be used as a base for deserialization of DynamicConfig.
  1534. ConfigOption* create_empty_option() const;
  1535. // Create a default option to be inserted into a DynamicConfig.
  1536. ConfigOption* create_default_option() const;
  1537. template<class Archive> ConfigOption* load_option_from_archive(Archive &archive) const {
  1538. if (this->nullable) {
  1539. switch (this->type) {
  1540. case coFloats: { auto opt = new ConfigOptionFloatsNullable(); archive(*opt); opt->set_is_extruder_size(this->is_vector_extruder); return opt; }
  1541. case coInts: { auto opt = new ConfigOptionIntsNullable(); archive(*opt); opt->set_is_extruder_size(this->is_vector_extruder); return opt; }
  1542. case coPercents: { auto opt = new ConfigOptionPercentsNullable();archive(*opt); opt->set_is_extruder_size(this->is_vector_extruder); return opt; }
  1543. case coFloatsOrPercents:{ auto opt = new ConfigOptionFloatsOrPercentsNullable();archive(*opt); opt->set_is_extruder_size(this->is_vector_extruder); return opt; }
  1544. case coBools: { auto opt = new ConfigOptionBoolsNullable(); archive(*opt); opt->set_is_extruder_size(this->is_vector_extruder); return opt; }
  1545. default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key);
  1546. }
  1547. } else {
  1548. switch (this->type) {
  1549. case coFloat: { auto opt = new ConfigOptionFloat(); archive(*opt); return opt; }
  1550. case coFloats: { auto opt = new ConfigOptionFloats(); archive(*opt); opt->set_is_extruder_size(this->is_vector_extruder); return opt; }
  1551. case coInt: { auto opt = new ConfigOptionInt(); archive(*opt); return opt; }
  1552. case coInts: { auto opt = new ConfigOptionInts(); archive(*opt); opt->set_is_extruder_size(this->is_vector_extruder); return opt; }
  1553. case coString: { auto opt = new ConfigOptionString(); archive(*opt); return opt; }
  1554. case coStrings: { auto opt = new ConfigOptionStrings(); archive(*opt); opt->set_is_extruder_size(this->is_vector_extruder); return opt; }
  1555. case coPercent: { auto opt = new ConfigOptionPercent(); archive(*opt); return opt; }
  1556. case coPercents: { auto opt = new ConfigOptionPercents(); archive(*opt); opt->set_is_extruder_size(this->is_vector_extruder); return opt; }
  1557. case coFloatOrPercent: { auto opt = new ConfigOptionFloatOrPercent(); archive(*opt); return opt; }
  1558. case coFloatsOrPercents:{ auto opt = new ConfigOptionFloatsOrPercents();archive(*opt); opt->set_is_extruder_size(this->is_vector_extruder); return opt; }
  1559. case coPoint: { auto opt = new ConfigOptionPoint(); archive(*opt); return opt; }
  1560. case coPoints: { auto opt = new ConfigOptionPoints(); archive(*opt); opt->set_is_extruder_size(this->is_vector_extruder); return opt; }
  1561. case coPoint3: { auto opt = new ConfigOptionPoint3(); archive(*opt); return opt; }
  1562. case coBool: { auto opt = new ConfigOptionBool(); archive(*opt); return opt; }
  1563. case coBools: { auto opt = new ConfigOptionBools(); archive(*opt); opt->set_is_extruder_size(this->is_vector_extruder); return opt; }
  1564. case coEnum: { auto opt = new ConfigOptionEnumGeneric(this->enum_keys_map); archive(*opt); return opt; }
  1565. default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key);
  1566. }
  1567. }
  1568. }
  1569. template<class Archive> ConfigOption* save_option_to_archive(Archive &archive, const ConfigOption *opt) const {
  1570. if (this->nullable) {
  1571. switch (this->type) {
  1572. case coFloats: archive(*static_cast<const ConfigOptionFloatsNullable*>(opt)); break;
  1573. case coInts: archive(*static_cast<const ConfigOptionIntsNullable*>(opt)); break;
  1574. case coPercents: archive(*static_cast<const ConfigOptionPercentsNullable*>(opt));break;
  1575. case coFloatsOrPercents:archive(*static_cast<const ConfigOptionFloatsOrPercentsNullable*>(opt));break;
  1576. case coBools: archive(*static_cast<const ConfigOptionBoolsNullable*>(opt)); break;
  1577. default: throw ConfigurationError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key);
  1578. }
  1579. } else {
  1580. switch (this->type) {
  1581. case coFloat: archive(*static_cast<const ConfigOptionFloat*>(opt)); break;
  1582. case coFloats: archive(*static_cast<const ConfigOptionFloats*>(opt)); break;
  1583. case coInt: archive(*static_cast<const ConfigOptionInt*>(opt)); break;
  1584. case coInts: archive(*static_cast<const ConfigOptionInts*>(opt)); break;
  1585. case coString: archive(*static_cast<const ConfigOptionString*>(opt)); break;
  1586. case coStrings: archive(*static_cast<const ConfigOptionStrings*>(opt)); break;
  1587. case coPercent: archive(*static_cast<const ConfigOptionPercent*>(opt)); break;
  1588. case coPercents: archive(*static_cast<const ConfigOptionPercents*>(opt)); break;
  1589. case coFloatOrPercent: archive(*static_cast<const ConfigOptionFloatOrPercent*>(opt)); break;
  1590. case coFloatsOrPercents:archive(*static_cast<const ConfigOptionFloatsOrPercents*>(opt));break;
  1591. case coPoint: archive(*static_cast<const ConfigOptionPoint*>(opt)); break;
  1592. case coPoints: archive(*static_cast<const ConfigOptionPoints*>(opt)); break;
  1593. case coPoint3: archive(*static_cast<const ConfigOptionPoint3*>(opt)); break;
  1594. case coBool: archive(*static_cast<const ConfigOptionBool*>(opt)); break;
  1595. case coBools: archive(*static_cast<const ConfigOptionBools*>(opt)); break;
  1596. case coEnum: archive(*static_cast<const ConfigOptionEnumGeneric*>(opt)); break;
  1597. default: throw ConfigurationError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key);
  1598. }
  1599. }
  1600. // Make the compiler happy, shut up the warnings.
  1601. return nullptr;
  1602. }
  1603. // Usually empty.
  1604. // Special values - "i_enum_open", "f_enum_open" to provide combo box for int or float selection,
  1605. // "select_open" - to open a selection dialog (currently only a serial port selection).
  1606. std::string gui_type;
  1607. // Usually empty. Otherwise "serialized" or "show_value"
  1608. // The flags may be combined.
  1609. // "serialized" - vector valued option is entered in a single edit field. Values are separated by a semicolon.
  1610. // "show_value" - even if enum_values / enum_labels are set, still display the value, not the enum label.
  1611. std::string gui_flags;
  1612. // Label of the GUI input field.
  1613. // In case the GUI input fields are grouped in some views, the label defines a short label of a grouped value,
  1614. // while full_label contains a label of a stand-alone field.
  1615. // The full label is shown, when adding an override parameter for an object or a modified object.
  1616. std::string label;
  1617. std::string full_label;
  1618. std::string get_full_label() const { return !full_label.empty() ? full_label : label; }
  1619. // With which printer technology is this configuration valid?
  1620. PrinterTechnology printer_technology = ptUnknown;
  1621. // Category of a configuration field, from the GUI perspective.
  1622. OptionCategory category = OptionCategory::none;
  1623. // A tooltip text shown in the GUI.
  1624. std::string tooltip;
  1625. // Text right from the input field, usually a unit of measurement.
  1626. std::string sidetext;
  1627. // Format of this parameter on a command line.
  1628. std::string cli;
  1629. // Set for type == coFloatOrPercent.
  1630. // It provides a link to a configuration value, of which this option provides a ratio.
  1631. // For example,
  1632. // For example external_perimeter_speed may be defined as a fraction of perimeter_speed.
  1633. t_config_option_key ratio_over;
  1634. // True for multiline strings.
  1635. bool multiline = false;
  1636. // For text input: If true, the GUI text box spans the complete page width.
  1637. bool full_width = false;
  1638. // For text input: If true, the GUI formats text as code (fixed-width)
  1639. bool is_code = false;
  1640. // For array setting: If true, It has the same size as the number of extruders.
  1641. bool is_vector_extruder = false;
  1642. // Not editable. Currently only used for the display of the number of threads.
  1643. bool readonly = false;
  1644. // Can be phony. if not present at laoding, mark it as phony. Also adapt the gui to look for phony status.
  1645. bool can_phony = false;
  1646. // Height of a multiline GUI text box.
  1647. int height = -1;
  1648. // Optional width of an input field.
  1649. int width = -1;
  1650. // Optional label width of the label (if in a line).
  1651. int label_width = -1;
  1652. // Optional label alignement to the left instead of the right
  1653. bool aligned_label_left = false;
  1654. // Optional label width of the sidetext (if in a line).
  1655. int sidetext_width = -1;
  1656. // <min, max> limit of a numeric input.
  1657. // If not set, the <min, max> is set to <INT_MIN, INT_MAX>
  1658. // By setting min=0, only nonnegative input is allowed.
  1659. double min = INT_MIN;
  1660. double max = INT_MAX;
  1661. // To check if it's not a typo and a % is missing
  1662. FloatOrPercent max_literal = FloatOrPercent{ 0., false };
  1663. // max precision after the dot, only for display
  1664. int precision = 6;
  1665. ConfigOptionMode mode = comSimple;
  1666. // Legacy names for this configuration option.
  1667. // Used when parsing legacy configuration file.
  1668. std::vector<t_config_option_key> aliases;
  1669. // Sometimes a single value may well define multiple values in a "beginner" mode.
  1670. // Currently used for aliasing "solid_layers" to "top_solid_layers", "bottom_solid_layers".
  1671. std::vector<t_config_option_key> shortcut;
  1672. // Definition of values / labels for a combo box.
  1673. // Mostly used for enums (when type == coEnum), but may be used for ints resp. floats, if gui_type is set to "i_enum_open" resp. "f_enum_open".
  1674. std::vector<std::string> enum_values;
  1675. std::vector<std::string> enum_labels;
  1676. // For enums (when type == coEnum). Maps enum_values to enums.
  1677. // Initialized by ConfigOptionEnum<xxx>::get_enum_values()
  1678. const t_config_enum_values *enum_keys_map = nullptr;
  1679. bool has_enum_value(const std::string &value) const {
  1680. for (const std::string &v : enum_values)
  1681. if (v == value)
  1682. return true;
  1683. return false;
  1684. }
  1685. // 0 is an invalid key.
  1686. size_t serialization_key_ordinal = 0;
  1687. // Returns the alternative CLI arguments for the given option.
  1688. // If there are no cli arguments defined, use the key and replace underscores with dashes.
  1689. std::vector<std::string> cli_args(const std::string &key) const;
  1690. // Assign this key to cli to disable CLI for this option.
  1691. static const constexpr char *nocli = "~~~noCLI";
  1692. };
  1693. inline bool operator<(const ConfigSubstitution &lhs, const ConfigSubstitution &rhs) throw() {
  1694. return lhs.opt_def->opt_key < rhs.opt_def->opt_key ||
  1695. (lhs.opt_def->opt_key == rhs.opt_def->opt_key && lhs.old_value < rhs.old_value);
  1696. }
  1697. inline bool operator==(const ConfigSubstitution &lhs, const ConfigSubstitution &rhs) throw() {
  1698. return lhs.opt_def == rhs.opt_def && lhs.old_value == rhs.old_value;
  1699. }
  1700. // Map from a config option name to its definition.
  1701. // The definition does not carry an actual value of the config option, only its constant default value.
  1702. // t_config_option_key is std::string
  1703. typedef std::map<t_config_option_key, ConfigOptionDef> t_optiondef_map;
  1704. // Definition of configuration values for the purpose of GUI presentation, editing, value mapping and config file handling.
  1705. // The configuration definition is static: It does not carry the actual configuration values,
  1706. // but it carries the defaults of the configuration values.
  1707. class ConfigDef
  1708. {
  1709. public:
  1710. t_optiondef_map options;
  1711. std::map<size_t, const ConfigOptionDef*> by_serialization_key_ordinal;
  1712. bool has(const t_config_option_key &opt_key) const { return this->options.count(opt_key) > 0; }
  1713. const ConfigOptionDef* get(const t_config_option_key &opt_key) const {
  1714. t_optiondef_map::iterator it = const_cast<ConfigDef*>(this)->options.find(opt_key);
  1715. return (it == this->options.end()) ? nullptr : &it->second;
  1716. }
  1717. std::vector<std::string> keys() const {
  1718. std::vector<std::string> out;
  1719. out.reserve(options.size());
  1720. for(auto const& kvp : options)
  1721. out.push_back(kvp.first);
  1722. return out;
  1723. }
  1724. // Iterate through all of the CLI options and write them to a stream.
  1725. std::ostream& print_cli_help(
  1726. std::ostream& out, bool show_defaults,
  1727. std::function<bool(const ConfigOptionDef &)> filter = [](const ConfigOptionDef &){ return true; }) const;
  1728. protected:
  1729. ConfigOptionDef* add(const t_config_option_key &opt_key, ConfigOptionType type);
  1730. ConfigOptionDef* add_nullable(const t_config_option_key &opt_key, ConfigOptionType type);
  1731. };
  1732. // A pure interface to resolving ConfigOptions.
  1733. // This pure interface is useful as a base of ConfigBase, also it may be overriden to combine
  1734. // various config sources.
  1735. class ConfigOptionResolver
  1736. {
  1737. public:
  1738. ConfigOptionResolver() {}
  1739. virtual ~ConfigOptionResolver() {}
  1740. // Find a ConfigOption instance for a given name.
  1741. virtual const ConfigOption* optptr(const t_config_option_key &opt_key) const = 0;
  1742. bool has(const t_config_option_key &opt_key) const { return this->optptr(opt_key) != nullptr; }
  1743. const ConfigOption* option(const t_config_option_key &opt_key) const { return this->optptr(opt_key); }
  1744. template<typename TYPE>
  1745. const TYPE* option(const t_config_option_key& opt_key) const
  1746. {
  1747. const ConfigOption* opt = this->optptr(opt_key);
  1748. return (opt == nullptr || opt->type() != TYPE::static_type()) ? nullptr : static_cast<const TYPE*>(opt);
  1749. }
  1750. const ConfigOption* option_throw(const t_config_option_key& opt_key) const
  1751. {
  1752. const ConfigOption* opt = this->optptr(opt_key);
  1753. if (opt == nullptr)
  1754. throw UnknownOptionException(opt_key);
  1755. return opt;
  1756. }
  1757. template<typename TYPE>
  1758. const TYPE* option_throw(const t_config_option_key& opt_key) const
  1759. {
  1760. const ConfigOption* opt = this->option_throw(opt_key);
  1761. if (opt->type() != TYPE::static_type())
  1762. throw BadOptionTypeException("Conversion to a wrong type");
  1763. return static_cast<TYPE*>(opt);
  1764. }
  1765. };
  1766. // An abstract configuration store.
  1767. class ConfigBase : public ConfigOptionResolver
  1768. {
  1769. public:
  1770. // Definition of configuration values for the purpose of GUI presentation, editing, value mapping and config file handling.
  1771. // The configuration definition is static: It does not carry the actual configuration values,
  1772. // but it carries the defaults of the configuration values.
  1773. ConfigBase() {}
  1774. ~ConfigBase() override {}
  1775. // to get to the config more generic than this one, if available
  1776. const ConfigBase* parent = nullptr;
  1777. // Virtual overridables:
  1778. public:
  1779. // Static configuration definition. Any value stored into this ConfigBase shall have its definition here.
  1780. // will search in parent definition if not found here.
  1781. virtual const ConfigDef* def() const = 0;
  1782. // Find ando/or create a ConfigOption instance for a given name.
  1783. // won't search in parent definition, as you can't change a parent value
  1784. virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) = 0;
  1785. // Collect names of all configuration values maintained by this configuration store.
  1786. virtual t_config_option_keys keys() const = 0;
  1787. protected:
  1788. // Verify whether the opt_key has not been obsoleted or renamed.
  1789. // Both opt_key and value may be modified by handle_legacy().
  1790. // If the opt_key is no more valid in this version of Slic3r, opt_key is cleared by handle_legacy().
  1791. // handle_legacy() is called internally by set_deserialize().
  1792. virtual void handle_legacy(t_config_option_key&/*opt_key*/, std::string&/*value*/) const {}
  1793. // Verify whether the opt_key has to be converted or isn't present int prusaslicer
  1794. // Both opt_key and value may be modified by to_prusa().
  1795. // If the opt_key is no more valid in this version of Slic3r, opt_key is cleared by to_prusa().
  1796. virtual void to_prusa(t_config_option_key&/*opt_key*/, std::string&/*value*/) const {}
  1797. public:
  1798. using ConfigOptionResolver::option;
  1799. using ConfigOptionResolver::option_throw;
  1800. // Non-virtual methods:
  1801. ConfigOption* option(const t_config_option_key &opt_key, bool create = false)
  1802. { return this->optptr(opt_key, create); }
  1803. template<typename TYPE>
  1804. TYPE* option(const t_config_option_key &opt_key, bool create = false)
  1805. {
  1806. ConfigOption *opt = this->optptr(opt_key, create);
  1807. return (opt == nullptr || opt->type() != TYPE::static_type()) ? nullptr : static_cast<TYPE*>(opt);
  1808. }
  1809. ConfigOption* option_throw(const t_config_option_key &opt_key, bool create = false)
  1810. {
  1811. ConfigOption *opt = this->optptr(opt_key, create);
  1812. if (opt == nullptr)
  1813. throw UnknownOptionException(opt_key);
  1814. return opt;
  1815. }
  1816. template<typename TYPE>
  1817. TYPE* option_throw(const t_config_option_key &opt_key, bool create = false)
  1818. {
  1819. ConfigOption *opt = this->option_throw(opt_key, create);
  1820. if (opt->type() != TYPE::static_type())
  1821. throw BadOptionTypeException("Conversion to a wrong type");
  1822. return static_cast<TYPE*>(opt);
  1823. }
  1824. // Apply all keys of other ConfigBase defined by this->def() to this ConfigBase.
  1825. // An UnknownOptionException is thrown in case some option keys of other are not defined by this->def(),
  1826. // or this ConfigBase is of a StaticConfig type and it does not support some of the keys, and ignore_nonexistent is not set.
  1827. void apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->apply_only(other, other.keys(), ignore_nonexistent); }
  1828. // Apply explicitely enumerated keys of other ConfigBase defined by this->def() to this ConfigBase.
  1829. // An UnknownOptionException is thrown in case some option keys are not defined by this->def(),
  1830. // or this ConfigBase is of a StaticConfig type and it does not support some of the keys, and ignore_nonexistent is not set.
  1831. void apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false);
  1832. bool equals(const ConfigBase &other) const { return this->keys().size() == other.keys().size() && this->diff(other).empty(); }
  1833. t_config_option_keys diff(const ConfigBase &other, bool even_phony = true) const;
  1834. t_config_option_keys equal(const ConfigBase &other) const;
  1835. std::string opt_serialize(const t_config_option_key &opt_key) const;
  1836. // Set a value. Convert numeric types using a C style implicit conversion / promotion model.
  1837. // Throw if option is not avaiable and create is not enabled,
  1838. // or if the conversion is not possible.
  1839. // Conversion to string is always possible.
  1840. void set(const std::string &opt_key, bool value, bool create = false)
  1841. { this->option_throw<ConfigOptionBool>(opt_key, create)->value = value; }
  1842. void set(const std::string &opt_key, int32_t value, bool create = false);
  1843. void set(const std::string &opt_key, double value, bool create = false);
  1844. void set(const std::string &opt_key, const char *value, bool create = false)
  1845. { this->option_throw<ConfigOptionString>(opt_key, create)->value = value; }
  1846. void set(const std::string &opt_key, const std::string &value, bool create = false)
  1847. { this->option_throw<ConfigOptionString>(opt_key, create)->value = value; }
  1848. // Set a configuration value from a string, it will call an overridable handle_legacy()
  1849. // to resolve renamed and removed configuration keys.
  1850. bool set_deserialize_nothrow(const t_config_option_key &opt_key_src, const std::string &value_src, ConfigSubstitutionContext& substitutions, bool append = false);
  1851. // May throw BadOptionTypeException() if the operation fails.
  1852. void set_deserialize(const t_config_option_key &opt_key, const std::string &str, ConfigSubstitutionContext& config_substitutions, bool append = false);
  1853. void set_deserialize_strict(const t_config_option_key &opt_key, const std::string &str, bool append = false)
  1854. { ConfigSubstitutionContext ctxt{ ForwardCompatibilitySubstitutionRule::Disable }; this->set_deserialize(opt_key, str, ctxt, append); }
  1855. struct SetDeserializeItem {
  1856. SetDeserializeItem(const char *opt_key, const char *opt_value, bool append = false) : opt_key(opt_key), opt_value(opt_value), append(append) {}
  1857. SetDeserializeItem(const std::string &opt_key, const std::string &opt_value, bool append = false) : opt_key(opt_key), opt_value(opt_value), append(append) {}
  1858. SetDeserializeItem(const char *opt_key, const bool value, bool append = false) : opt_key(opt_key), opt_value(value ? "1" : "0"), append(append) {}
  1859. SetDeserializeItem(const std::string &opt_key, const bool value, bool append = false) : opt_key(opt_key), opt_value(value ? "1" : "0"), append(append) {}
  1860. SetDeserializeItem(const char *opt_key, const int32_t value, bool append = false) : opt_key(opt_key), opt_value(std::to_string(value)), append(append) {}
  1861. SetDeserializeItem(const std::string &opt_key, const int32_t value, bool append = false) : opt_key(opt_key), opt_value(std::to_string(value)), append(append) {}
  1862. SetDeserializeItem(const char *opt_key, const float value, bool append = false) : opt_key(opt_key), opt_value(std::to_string(value)), append(append) {}
  1863. SetDeserializeItem(const std::string &opt_key, const float value, bool append = false) : opt_key(opt_key), opt_value(std::to_string(value)), append(append) {}
  1864. SetDeserializeItem(const char *opt_key, const double value, bool append = false) : opt_key(opt_key), opt_value(std::to_string(value)), append(append) {}
  1865. SetDeserializeItem(const std::string &opt_key, const double value, bool append = false) : opt_key(opt_key), opt_value(std::to_string(value)), append(append) {}
  1866. std::string opt_key; std::string opt_value; bool append = false;
  1867. };
  1868. // May throw BadOptionTypeException() if the operation fails.
  1869. void set_deserialize(std::initializer_list<SetDeserializeItem> items, ConfigSubstitutionContext& substitutions);
  1870. void set_deserialize_strict(std::initializer_list<SetDeserializeItem> items)
  1871. { ConfigSubstitutionContext ctxt{ ForwardCompatibilitySubstitutionRule::Disable }; this->set_deserialize(items, ctxt); }
  1872. const ConfigOptionDef* get_option_def(const t_config_option_key& opt_key) const;
  1873. double get_computed_value(const t_config_option_key &opt_key, int extruder_id = -1) const;
  1874. double get_abs_value(const t_config_option_key &opt_key, double ratio_over) const;
  1875. void setenv_() const;
  1876. ConfigSubstitutions load(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule);
  1877. ConfigSubstitutions load_from_ini(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule);
  1878. ConfigSubstitutions load_from_gcode_file(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule);
  1879. // Returns number of key/value pairs extracted.
  1880. size_t load_from_gcode_string(const char* str, ConfigSubstitutionContext& substitutions);
  1881. ConfigSubstitutions load(const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule);
  1882. void save(const std::string &file, bool to_prusa = false) const;
  1883. // Set all the nullable values to nils.
  1884. void null_nullables();
  1885. private:
  1886. // Set a configuration value from a string.
  1887. bool set_deserialize_raw(const t_config_option_key& opt_key_src, const std::string& value, ConfigSubstitutionContext& substitutions, bool append);
  1888. };
  1889. // Configuration store with dynamic number of configuration values.
  1890. // In Slic3r, the dynamic config is mostly used at the user interface layer.
  1891. class DynamicConfig : public virtual ConfigBase
  1892. {
  1893. public:
  1894. DynamicConfig() {}
  1895. DynamicConfig(const DynamicConfig &rhs) { *this = rhs; }
  1896. DynamicConfig(DynamicConfig &&rhs) noexcept : options(std::move(rhs.options)) { rhs.options.clear(); }
  1897. explicit DynamicConfig(const ConfigBase &rhs, const t_config_option_keys &keys);
  1898. explicit DynamicConfig(const ConfigBase& rhs) : DynamicConfig(rhs, rhs.keys()) {}
  1899. virtual ~DynamicConfig() override { clear(); }
  1900. // Copy a content of one DynamicConfig to another DynamicConfig.
  1901. // If rhs.def() is not null, then it has to be equal to this->def().
  1902. DynamicConfig& operator=(const DynamicConfig &rhs)
  1903. {
  1904. assert(this->def() == nullptr || this->def() == rhs.def());
  1905. this->clear();
  1906. for (const auto &kvp : rhs.options)
  1907. this->options[kvp.first].reset(kvp.second->clone());
  1908. return *this;
  1909. }
  1910. // Move a content of one DynamicConfig to another DynamicConfig.
  1911. // If rhs.def() is not null, then it has to be equal to this->def().
  1912. DynamicConfig& operator=(DynamicConfig &&rhs) noexcept
  1913. {
  1914. assert(this->def() == nullptr || this->def() == rhs.def());
  1915. this->clear();
  1916. this->options = std::move(rhs.options);
  1917. rhs.options.clear();
  1918. return *this;
  1919. }
  1920. // Add a content of one DynamicConfig to another DynamicConfig.
  1921. // If rhs.def() is not null, then it has to be equal to this->def().
  1922. DynamicConfig& operator+=(const DynamicConfig &rhs)
  1923. {
  1924. assert(this->def() == nullptr || this->def() == rhs.def());
  1925. for (const auto &kvp : rhs.options) {
  1926. auto it = this->options.find(kvp.first);
  1927. if (it == this->options.end())
  1928. this->options[kvp.first].reset(kvp.second->clone());
  1929. else {
  1930. assert(it->second->type() == kvp.second->type());
  1931. if (it->second->type() == kvp.second->type())
  1932. *it->second = *kvp.second;
  1933. else
  1934. it->second.reset(kvp.second->clone());
  1935. }
  1936. }
  1937. return *this;
  1938. }
  1939. // Move a content of one DynamicConfig to another DynamicConfig.
  1940. // If rhs.def() is not null, then it has to be equal to this->def().
  1941. DynamicConfig& operator+=(DynamicConfig &&rhs)
  1942. {
  1943. assert(this->def() == nullptr || this->def() == rhs.def());
  1944. for (auto &kvp : rhs.options) {
  1945. auto it = this->options.find(kvp.first);
  1946. if (it == this->options.end()) {
  1947. this->options.insert(std::make_pair(kvp.first, std::move(kvp.second)));
  1948. } else {
  1949. assert(it->second->type() == kvp.second->type());
  1950. it->second = std::move(kvp.second);
  1951. }
  1952. }
  1953. rhs.options.clear();
  1954. return *this;
  1955. }
  1956. bool operator==(const DynamicConfig &rhs) const;
  1957. bool operator!=(const DynamicConfig &rhs) const { return ! (*this == rhs); }
  1958. void swap(DynamicConfig &other)
  1959. {
  1960. std::swap(this->options, other.options);
  1961. }
  1962. void clear()
  1963. {
  1964. this->options.clear();
  1965. }
  1966. bool erase(const t_config_option_key &opt_key)
  1967. {
  1968. auto it = this->options.find(opt_key);
  1969. if (it == this->options.end())
  1970. return false;
  1971. this->options.erase(it);
  1972. return true;
  1973. }
  1974. // Remove options with all nil values, those are optional and it does not help to hold them.
  1975. size_t remove_nil_options();
  1976. // Allow DynamicConfig to be instantiated on ints own without a definition.
  1977. // If the definition is not defined, the method requiring the definition will throw NoDefinitionException.
  1978. const ConfigDef* def() const override { return nullptr; }
  1979. template<class T> T* opt(const t_config_option_key &opt_key, bool create = false)
  1980. { return dynamic_cast<T*>(this->option(opt_key, create)); }
  1981. template<class T> const T* opt(const t_config_option_key &opt_key) const
  1982. { return dynamic_cast<const T*>(this->option(opt_key)); }
  1983. // Overrides ConfigResolver::optptr().
  1984. const ConfigOption* optptr(const t_config_option_key &opt_key) const override;
  1985. // Overrides ConfigBase::optptr(). Find ando/or create a ConfigOption instance for a given name.
  1986. ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) override;
  1987. // Overrides ConfigBase::keys(). Collect names of all configuration values maintained by this configuration store.
  1988. t_config_option_keys keys() const override;
  1989. bool empty() const { return options.empty(); }
  1990. // Set a value for an opt_key. Returns true if the value did not exist yet.
  1991. // This DynamicConfig will take ownership of opt.
  1992. // Be careful, as this method does not test the existence of opt_key in this->def().
  1993. bool set_key_value(const std::string &opt_key, ConfigOption *opt)
  1994. {
  1995. auto it = this->options.find(opt_key);
  1996. if (it == this->options.end()) {
  1997. this->options[opt_key].reset(opt);
  1998. return true;
  1999. } else {
  2000. it->second.reset(opt);
  2001. return false;
  2002. }
  2003. }
  2004. std::string& opt_string(const t_config_option_key &opt_key, bool create = false) { return this->option<ConfigOptionString>(opt_key, create)->value; }
  2005. const std::string& opt_string(const t_config_option_key &opt_key) const { return const_cast<DynamicConfig*>(this)->opt_string(opt_key); }
  2006. std::string& opt_string(const t_config_option_key &opt_key, unsigned int idx) { return this->option<ConfigOptionStrings>(opt_key)->get_at(idx); }
  2007. const std::string& opt_string(const t_config_option_key &opt_key, unsigned int idx) const { return const_cast<DynamicConfig*>(this)->opt_string(opt_key, idx); }
  2008. double& opt_float(const t_config_option_key &opt_key) { return this->option<ConfigOptionFloat>(opt_key)->value; }
  2009. const double& opt_float(const t_config_option_key &opt_key) const { return dynamic_cast<const ConfigOptionFloat*>(this->option(opt_key))->value; }
  2010. double& opt_float(const t_config_option_key &opt_key, unsigned int idx) { return this->option<ConfigOptionFloats>(opt_key)->get_at(idx); }
  2011. const double& opt_float(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast<const ConfigOptionFloats*>(this->option(opt_key))->get_at(idx); }
  2012. int32_t& opt_int(const t_config_option_key &opt_key) { return this->option<ConfigOptionInt>(opt_key)->value; }
  2013. int32_t opt_int(const t_config_option_key &opt_key) const { return dynamic_cast<const ConfigOptionInt*>(this->option(opt_key))->value; }
  2014. int32_t& opt_int(const t_config_option_key &opt_key, unsigned int idx) { return this->option<ConfigOptionInts>(opt_key)->get_at(idx); }
  2015. int32_t opt_int(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast<const ConfigOptionInts*>(this->option(opt_key))->get_at(idx); }
  2016. template<typename ENUM>
  2017. ENUM opt_enum(const t_config_option_key &opt_key) const {
  2018. auto v1 = this->option<ConfigOptionEnumGeneric>(opt_key);
  2019. auto v2 = this->option<ConfigOptionEnum<ENUM>>(opt_key);
  2020. return v1==nullptr? v2->value : (ENUM)v1->value;
  2021. }
  2022. bool opt_bool(const t_config_option_key &opt_key) const { return this->option<ConfigOptionBool>(opt_key)->value != 0; }
  2023. bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option<ConfigOptionBools>(opt_key)->get_at(idx) != 0; }
  2024. // Command line processing
  2025. void read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra, t_config_option_keys* keys = nullptr);
  2026. bool read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys = nullptr);
  2027. std::map<t_config_option_key, std::unique_ptr<ConfigOption>>::const_iterator cbegin() const { return options.cbegin(); }
  2028. std::map<t_config_option_key, std::unique_ptr<ConfigOption>>::const_iterator cend() const { return options.cend(); }
  2029. size_t size() const { return options.size(); }
  2030. private:
  2031. std::map<t_config_option_key, std::unique_ptr<ConfigOption>> options;
  2032. friend class cereal::access;
  2033. template<class Archive> void serialize(Archive &ar) { ar(options); }
  2034. };
  2035. // Configuration store with a static definition of configuration values.
  2036. // In Slic3r, the static configuration stores are during the slicing / g-code generation for efficiency reasons,
  2037. // because the configuration values could be accessed directly.
  2038. class StaticConfig : public virtual ConfigBase
  2039. {
  2040. public:
  2041. /// Gets list of config option names for each config option of this->def, which has a static counter-part defined by the derived object
  2042. /// and which could be resolved by this->optptr(key) call.
  2043. t_config_option_keys keys() const;
  2044. /// Set all statically defined config options to their defaults defined by this->def().
  2045. /// used (only) by tests
  2046. void set_defaults();
  2047. protected:
  2048. StaticConfig() {}
  2049. };
  2050. }
  2051. #endif