1 #ifndef _ValueRefs_h_
2 #define _ValueRefs_h_
3
4 #include "ScriptingContext.h"
5 #include "ValueRef.h"
6 #include "Condition.h"
7 #include "Universe.h"
8 #include "../util/Export.h"
9 #include "../util/i18n.h"
10 #include "../util/Random.h"
11 #include "../util/CheckSums.h"
12
13 #include <boost/algorithm/string/case_conv.hpp>
14 #include <boost/lexical_cast.hpp>
15 #include <boost/format.hpp>
16 #include <boost/serialization/nvp.hpp>
17
18 #include <iterator>
19 #include <map>
20 #include <set>
21
22 namespace CheckSums {
23 template <typename T>
CheckSumCombine(unsigned int & sum,const typename ValueRef::ValueRef<T> & c)24 void CheckSumCombine(unsigned int& sum, const typename ValueRef::ValueRef<T>& c)
25 {
26 TraceLogger() << "CheckSumCombine(ValueRef::ValueRef<T>): " << typeid(c).name();
27 sum += c.GetCheckSum();
28 sum %= CHECKSUM_MODULUS;
29 }
30 }
31
32 class UniverseObject;
33
34 namespace ValueRef {
35 /** the constant value leaf ValueRef class. */
36 template <typename T>
37 struct FO_COMMON_API Constant final : public ValueRef<T>
38 {
39 explicit Constant(T value);
40
41 bool operator==(const ValueRef<T>& rhs) const override;
42 T Eval(const ScriptingContext& context) const override;
43
RootCandidateInvariantfinal44 bool RootCandidateInvariant() const override
45 { return true; }
46
LocalCandidateInvariantfinal47 bool LocalCandidateInvariant() const override
48 { return true; }
49
TargetInvariantfinal50 bool TargetInvariant() const override
51 { return true; }
52
SourceInvariantfinal53 bool SourceInvariant() const override
54 { return true; }
55
ConstantExprfinal56 bool ConstantExpr() const override
57 { return true; }
58
59 std::string Description() const override;
60 std::string Dump(unsigned short ntabs = 0) const override;
61 void SetTopLevelContent(const std::string& content_name) override;
62 T Value() const;
63 unsigned int GetCheckSum() const override;
64
65 private:
66 T m_value;
67 std::string m_top_level_content; // in the special case that T is std::string and m_value is "CurrentContent", return this instead
68
69 friend class boost::serialization::access;
70 template <typename Archive>
71 void serialize(Archive& ar, const unsigned int version);
72 };
73
74 enum ReferenceType : int {
75 INVALID_REFERENCE_TYPE = -1,
76 NON_OBJECT_REFERENCE, // ValueRef::Variable is not evalulated on any specific object
77 SOURCE_REFERENCE, // ValueRef::Variable is evaluated on the source object
78 EFFECT_TARGET_REFERENCE, // ValueRef::Variable is evaluated on the target object of an effect while it is being executed
79 EFFECT_TARGET_VALUE_REFERENCE, // ValueRef::Variable is evaluated on the target object value of an effect while it is being executed
80 CONDITION_LOCAL_CANDIDATE_REFERENCE,// ValueRef::Variable is evaluated on an object that is a candidate to be matched by a condition. In a subcondition, this will reference the local candidate, and not the candidate of an enclosing condition.
81 CONDITION_ROOT_CANDIDATE_REFERENCE // ValueRef::Variable is evaluated on an object that is a candidate to be matched by a condition. In a subcondition, this will still reference the root candidate, and not the candidate of the local condition.
82 };
83
84 /** The variable value ValueRef class. The value returned by this node is
85 * taken from the gamestate, most often from the Source or Target objects. */
86 template <typename T>
87 struct FO_COMMON_API Variable : public ValueRef<T>
88 {
89 explicit Variable(ReferenceType ref_type, const std::string& property_name = "",
90 bool return_immediate_value = false);
91 Variable(ReferenceType ref_type, const std::vector<std::string>& property_name,
92 bool return_immediate_value = false);
93 Variable(ReferenceType ref_type,
94 const boost::optional<std::string>& container_name,
95 const std::string& property_name,
96 bool return_immediate_value = false);
97
98 bool operator==(const ValueRef<T>& rhs) const override;
99 T Eval(const ScriptingContext& context) const override;
100 bool RootCandidateInvariant() const override;
101 bool LocalCandidateInvariant() const override;
102 bool TargetInvariant() const override;
103 bool SourceInvariant() const override;
104 std::string Description() const override;
105 std::string Dump(unsigned short ntabs = 0) const override;
106 ReferenceType GetReferenceType() const;
107 const std::vector<std::string>& PropertyName() const;
108 bool ReturnImmediateValue() const;
109 unsigned int GetCheckSum() const override;
110
111 protected:
112 ReferenceType m_ref_type = INVALID_REFERENCE_TYPE;
113 std::vector<std::string> m_property_name;
114 bool m_return_immediate_value = false;
115
116 private:
117 friend class boost::serialization::access;
118 template <typename Archive>
119 void serialize(Archive& ar, const unsigned int version);
120 };
121
122 /** The variable statistic class. The value returned by this node is
123 * computed from the general gamestate; the value of the indicated
124 * \a property_name is computed for each object that matches
125 * \a sampling_condition and the statistic indicated by \a stat_type is
126 * calculated from them and returned. */
127 template <typename T>
128 struct FO_COMMON_API Statistic final : public Variable<T>
129 {
130 Statistic(std::unique_ptr<ValueRef<T>>&& value_ref,
131 StatisticType stat_type,
132 std::unique_ptr<Condition::Condition>&& sampling_condition);
133
134 bool operator==(const ValueRef<T>& rhs) const override;
135 T Eval(const ScriptingContext& context) const override;
136 bool RootCandidateInvariant() const override;
137 bool LocalCandidateInvariant() const override;
138 bool TargetInvariant() const override;
139 bool SourceInvariant() const override;
140 std::string Description() const override;
141 std::string Dump(unsigned short ntabs = 0) const override;
142 void SetTopLevelContent(const std::string& content_name) override;
143
GetStatisticTypefinal144 StatisticType GetStatisticType() const
145 { return m_stat_type; }
146
GetSamplingConditionfinal147 const Condition::Condition* GetSamplingCondition() const
148 { return m_sampling_condition.get(); }
149
GetValueReffinal150 const ValueRef<T>* GetValueRef() const
151 { return m_value_ref.get(); }
152
153 unsigned int GetCheckSum() const override;
154
155 protected:
156 /** Gets the set of objects in the Universe that match the sampling condition. */
157 void GetConditionMatches(const ScriptingContext& context,
158 Condition::ObjectSet& condition_targets,
159 Condition::Condition* condition) const;
160
161 /** Evaluates the property for the specified objects. */
162 void GetObjectPropertyValues(const ScriptingContext& context,
163 const Condition::ObjectSet& objects,
164 std::map<std::shared_ptr<const UniverseObject>, T>& object_property_values) const;
165
166 /** Computes the statistic from the specified set of property values. */
167 T ReduceData(const std::map<std::shared_ptr<const UniverseObject>, T>& object_property_values) const;
168
169 private:
170 StatisticType m_stat_type;
171 std::unique_ptr<Condition::Condition> m_sampling_condition;
172 std::unique_ptr<ValueRef<T>> m_value_ref;
173
174 friend class boost::serialization::access;
175 template <typename Archive>
176 void serialize(Archive& ar, const unsigned int version);
177 };
178
179 /** The complex variable ValueRef class. The value returned by this node
180 * is taken from the gamestate. */
181 template <typename T>
182 struct FO_COMMON_API ComplexVariable final : public Variable<T>
183 {
184 explicit ComplexVariable(const std::string& variable_name,
185 std::unique_ptr<ValueRef<int>>&& int_ref1 = nullptr,
186 std::unique_ptr<ValueRef<int>>&& int_ref2 = nullptr,
187 std::unique_ptr<ValueRef<int>>&& int_ref3 = nullptr,
188 std::unique_ptr<ValueRef<std::string>>&& string_ref1 = nullptr,
189 std::unique_ptr<ValueRef<std::string>>&& string_ref2 = nullptr,
190 bool return_immediate_value = false);
191
192 bool operator==(const ValueRef<T>& rhs) const override;
193 T Eval(const ScriptingContext& context) const override;
194 bool RootCandidateInvariant() const override;
195 bool LocalCandidateInvariant() const override;
196 bool TargetInvariant() const override;
197 bool SourceInvariant() const override;
198 std::string Description() const override;
199 std::string Dump(unsigned short ntabs = 0) const override;
200 void SetTopLevelContent(const std::string& content_name) override;
201 const ValueRef<int>* IntRef1() const;
202 const ValueRef<int>* IntRef2() const;
203 const ValueRef<int>* IntRef3() const;
204 const ValueRef<std::string>* StringRef1() const;
205 const ValueRef<std::string>* StringRef2() const;
206 unsigned int GetCheckSum() const override;
207
208 protected:
209 std::unique_ptr<ValueRef<int>> m_int_ref1;
210 std::unique_ptr<ValueRef<int>> m_int_ref2;
211 std::unique_ptr<ValueRef<int>> m_int_ref3;
212 std::unique_ptr<ValueRef<std::string>> m_string_ref1;
213 std::unique_ptr<ValueRef<std::string>> m_string_ref2;
214
215 private:
216 friend class boost::serialization::access;
217 template <typename Archive>
218 void serialize(Archive& ar, const unsigned int version);
219 };
220
221 /** The variable static_cast class. The value returned by this node is taken
222 * from the ctor \a value_ref parameter's FromType value, static_cast to
223 * ToType. */
224 template <typename FromType, typename ToType>
225 struct FO_COMMON_API StaticCast final : public Variable<ToType>
226 {
227 template <typename T>
228 StaticCast(T&& value_ref,
229 typename std::enable_if<std::is_convertible<T, std::unique_ptr<Variable<FromType>>>::value>::type* = nullptr);
230
231 template <typename T>
232 StaticCast(T&& value_ref,
233 typename std::enable_if<
234 std::is_convertible<T, std::unique_ptr<ValueRef<FromType>>>::value
235 && !std::is_convertible<T, std::unique_ptr<Variable<FromType>>>::value>::type* = nullptr);
236
237 bool operator==(const ValueRef<ToType>& rhs) const override;
238 ToType Eval(const ScriptingContext& context) const override;
239 bool RootCandidateInvariant() const override;
240 bool LocalCandidateInvariant() const override;
241 bool TargetInvariant() const override;
242 bool SourceInvariant() const override;
243 std::string Description() const override;
244 std::string Dump(unsigned short ntabs = 0) const override;
245 void SetTopLevelContent(const std::string& content_name) override;
246
GetValueReffinal247 const ValueRef<FromType>* GetValueRef() const
248 { return m_value_ref.get(); }
249
250 unsigned int GetCheckSum() const override;
251
252 private:
253 std::unique_ptr<ValueRef<FromType>> m_value_ref;
254
255 friend class boost::serialization::access;
256 template <typename Archive>
257 void serialize(Archive& ar, const unsigned int version);
258 };
259
260 /** The variable lexical_cast to string class. The value returned by this node
261 * is taken from the ctor \a value_ref parameter's FromType value,
262 * lexical_cast to std::string */
263 template <typename FromType>
264 struct FO_COMMON_API StringCast final : public Variable<std::string>
265 {
266 StringCast(std::unique_ptr<ValueRef<FromType>>&& value_ref);
267
268 bool operator==(const ValueRef<std::string>& rhs) const override;
269 std::string Eval(const ScriptingContext& context) const override;
270 bool RootCandidateInvariant() const override;
271 bool LocalCandidateInvariant() const override;
272 bool TargetInvariant() const override;
273 bool SourceInvariant() const override;
274 std::string Description() const override;
275 std::string Dump(unsigned short ntabs = 0) const override;
276 void SetTopLevelContent(const std::string& content_name) override;
277
GetValueReffinal278 const ValueRef<FromType>* GetValueRef() const
279 { return m_value_ref; }
280
281 unsigned int GetCheckSum() const override;
282
283 private:
284 std::unique_ptr<ValueRef<FromType>> m_value_ref;
285
286 friend class boost::serialization::access;
287 template <typename Archive>
288 void serialize(Archive& ar, const unsigned int version);
289 };
290
291 /** Looks up a string ValueRef or vector of string ValueRefs, and returns
292 * and returns the UserString equivalent(s). */
293 template <typename FromType>
294 struct FO_COMMON_API UserStringLookup final : public Variable<std::string> {
295 explicit UserStringLookup(std::unique_ptr<ValueRef<FromType>>&& value_ref);
296
297 bool operator==(const ValueRef<std::string>& rhs) const override;
298 std::string Eval(const ScriptingContext& context) const override;
299 bool RootCandidateInvariant() const override;
300 bool LocalCandidateInvariant() const override;
301 bool TargetInvariant() const override;
302 bool SourceInvariant() const override;
303 std::string Description() const override;
304 std::string Dump(unsigned short ntabs = 0) const override;
305 void SetTopLevelContent(const std::string& content_name) override;
306
GetValueReffinal307 const ValueRef<FromType>* GetValueRef() const
308 { return m_value_ref; }
309
310 unsigned int GetCheckSum() const override;
311
312 private:
313 std::unique_ptr<ValueRef<FromType>> m_value_ref;
314
315 friend class boost::serialization::access;
316 template <typename Archive>
317 void serialize(Archive& ar, const unsigned int version);
318 };
319
320 /** Returns the in-game name of the object / empire / etc. with a specified id. */
321 struct FO_COMMON_API NameLookup final : public Variable<std::string> {
322 enum LookupType : int {
323 INVALID_LOOKUP = -1,
324 OBJECT_NAME,
325 EMPIRE_NAME,
326 SHIP_DESIGN_NAME
327 };
328
329 NameLookup(std::unique_ptr<ValueRef<int>>&& value_ref, LookupType lookup_type);
330
331 bool operator==(const ValueRef<std::string>& rhs) const override;
332 std::string Eval(const ScriptingContext& context) const override;
333 bool RootCandidateInvariant() const override;
334 bool LocalCandidateInvariant() const override;
335 bool TargetInvariant() const override;
336 bool SourceInvariant() const override;
337 std::string Description() const override;
338 std::string Dump(unsigned short ntabs = 0) const override;
339 void SetTopLevelContent(const std::string& content_name) override;
340
GetValueReffinal341 const ValueRef<int>* GetValueRef() const
342 { return m_value_ref.get(); }
343
GetLookupTypefinal344 LookupType GetLookupType() const
345 { return m_lookup_type; }
346
347 unsigned int GetCheckSum() const override;
348
349 private:
350 std::unique_ptr<ValueRef<int>> m_value_ref;
351 LookupType m_lookup_type;
352
353 friend class boost::serialization::access;
354 template <typename Archive>
355 void serialize(Archive& ar, const unsigned int version);
356 };
357
358 enum OpType : int {
359 PLUS,
360 MINUS,
361 TIMES,
362 DIVIDE,
363 NEGATE,
364 EXPONENTIATE,
365 ABS,
366 LOGARITHM,
367 SINE,
368 COSINE,
369 MINIMUM,
370 MAXIMUM,
371 RANDOM_UNIFORM,
372 RANDOM_PICK,
373 SUBSTITUTION,
374 COMPARE_EQUAL,
375 COMPARE_GREATER_THAN,
376 COMPARE_GREATER_THAN_OR_EQUAL,
377 COMPARE_LESS_THAN,
378 COMPARE_LESS_THAN_OR_EQUAL,
379 COMPARE_NOT_EQUAL,
380 ROUND_NEAREST,
381 ROUND_UP,
382 ROUND_DOWN
383 };
384
385 /** An arithmetic operation node ValueRef class. Unary or binary operations such
386 * as addition, mutiplication, negation, exponentiation, rounding,
387 * value substitution, value comparisons, or random value selection or
388 * random number generation are performed on the child(ren) of this node, and
389 * the result is returned. */
390 template <typename T>
391 struct FO_COMMON_API Operation final : public ValueRef<T>
392 {
393 /** Binary operation ctor. */
394 Operation(OpType op_type, std::unique_ptr<ValueRef<T>>&& operand1,
395 std::unique_ptr<ValueRef<T>>&& operand2);
396
397 /** Unary operation ctor. */
398 Operation(OpType op_type, std::unique_ptr<ValueRef<T>>&& operand);
399
400 /* N-ary operation ctor. */
401 Operation(OpType op_type, std::vector<std::unique_ptr<ValueRef<T>>>&& operands);
402
403 bool operator==(const ValueRef<T>& rhs) const override;
404 T Eval(const ScriptingContext& context) const override;
405 bool RootCandidateInvariant() const override;
406 bool LocalCandidateInvariant() const override;
407 bool TargetInvariant() const override;
408 bool SourceInvariant() const override;
409 bool SimpleIncrement() const override;
ConstantExprfinal410 bool ConstantExpr() const override { return m_constant_expr; }
411 std::string Description() const override;
412 std::string Dump(unsigned short ntabs = 0) const override;
413 void SetTopLevelContent(const std::string& content_name) override;
414 OpType GetOpType() const;
415
416 /** 1st operand (or 0 if none exists). */
417 const ValueRef<T>* LHS() const;
418
419 /** 2nd operand (or 0 if only one exists) */
420 const ValueRef<T>* RHS() const;
421
422 /** all operands */
423 const std::vector<ValueRef<T>*> Operands() const;
424
425 unsigned int GetCheckSum() const override;
426
427 private:
428 void DetermineIfConstantExpr();
429 void CacheConstValue();
430 T EvalImpl(const ScriptingContext& context) const;
431
432 OpType m_op_type = TIMES;
433 std::vector<std::unique_ptr<ValueRef<T>>> m_operands;
434 bool m_constant_expr = false;
435 T m_cached_const_value = T();
436
437 friend class boost::serialization::access;
438 template <typename Archive>
439 void serialize(Archive& ar, const unsigned int version);
440 };
441
442 FO_COMMON_API MeterType NameToMeter(const std::string& name);
443 FO_COMMON_API std::string MeterToName(MeterType meter);
444 FO_COMMON_API std::string ReconstructName(const std::vector<std::string>& property_name,
445 ReferenceType ref_type,
446 bool return_immediate_value = false);
447
448 FO_COMMON_API std::string FormatedDescriptionPropertyNames(
449 ReferenceType ref_type, const std::vector<std::string>& property_names,
450 bool return_immediate_value = false);
451
452 FO_COMMON_API std::string ComplexVariableDescription(
453 const std::vector<std::string>& property_names,
454 const ValueRef<int>* int_ref1,
455 const ValueRef<int>* int_ref2,
456 const ValueRef<int>* int_ref3,
457 const ValueRef<std::string>* string_ref1,
458 const ValueRef<std::string>* string_ref2);
459
460 FO_COMMON_API std::string ComplexVariableDump(
461 const std::vector<std::string>& property_names,
462 const ValueRef<int>* int_ref1,
463 const ValueRef<int>* int_ref2,
464 const ValueRef<int>* int_ref3,
465 const ValueRef<std::string>* string_ref1,
466 const ValueRef<std::string>* string_ref2);
467
468 FO_COMMON_API std::string StatisticDescription(StatisticType stat_type,
469 const std::string& value_desc,
470 const std::string& condition_desc);
471
472 // Template Implementations
473 ///////////////////////////////////////////////////////////
474 // ValueRef //
475 ///////////////////////////////////////////////////////////
476 template <typename T>
477 bool ValueRef<T>::operator==(const ValueRef<T>& rhs) const
478 {
479 if (&rhs == this)
480 return true;
481 if (typeid(rhs) != typeid(*this))
482 return false;
483 return true;
484 }
485
486 template <typename T>
487 template <typename Archive>
serialize(Archive & ar,const unsigned int version)488 void ValueRef<T>::serialize(Archive& ar, const unsigned int version)
489 {}
490
491 ///////////////////////////////////////////////////////////
492 // Constant //
493 ///////////////////////////////////////////////////////////
494 template <typename T>
Constant(T value)495 Constant<T>::Constant(T value) :
496 m_value(value)
497 {}
498
499 template <typename T>
500 bool Constant<T>::operator==(const ValueRef<T>& rhs) const
501 {
502 if (&rhs == this)
503 return true;
504 if (typeid(rhs) != typeid(*this))
505 return false;
506 const Constant<T>& rhs_ = static_cast<const Constant<T>&>(rhs);
507
508 return m_value == rhs_.m_value && m_top_level_content == rhs_.m_top_level_content;
509 }
510
511 template <typename T>
Value()512 T Constant<T>::Value() const
513 { return m_value; }
514
515 template <typename T>
Eval(const ScriptingContext & context)516 T Constant<T>::Eval(const ScriptingContext& context) const
517 { return m_value; }
518
519 template <typename T>
Description()520 std::string Constant<T>::Description() const
521 { return UserString(boost::lexical_cast<std::string>(m_value)); }
522
523 template <typename T>
SetTopLevelContent(const std::string & content_name)524 void Constant<T>::SetTopLevelContent(const std::string& content_name)
525 { m_top_level_content = content_name; }
526
527 template <typename T>
GetCheckSum()528 unsigned int Constant<T>::GetCheckSum() const
529 {
530 unsigned int retval{0};
531
532 CheckSums::CheckSumCombine(retval, "ValueRef::Constant");
533 CheckSums::CheckSumCombine(retval, m_value);
534 TraceLogger() << "GetCheckSum(Constant<T>): " << typeid(*this).name() << " value: " << m_value << " retval: " << retval;
535 return retval;
536 }
537
538 template <>
539 FO_COMMON_API std::string Constant<int>::Description() const;
540
541 template <>
542 FO_COMMON_API std::string Constant<double>::Description() const;
543
544 template <>
545 FO_COMMON_API std::string Constant<std::string>::Description() const;
546
547 template <>
548 FO_COMMON_API std::string Constant<PlanetSize>::Dump(unsigned short ntabs) const;
549
550 template <>
551 FO_COMMON_API std::string Constant<PlanetType>::Dump(unsigned short ntabs) const;
552
553 template <>
554 FO_COMMON_API std::string Constant<PlanetEnvironment>::Dump(unsigned short ntabs) const;
555
556 template <>
557 FO_COMMON_API std::string Constant<UniverseObjectType>::Dump(unsigned short ntabs) const;
558
559 template <>
560 FO_COMMON_API std::string Constant<StarType>::Dump(unsigned short ntabs) const;
561
562 template <>
563 FO_COMMON_API std::string Constant<Visibility>::Dump(unsigned short ntabs) const;
564
565 template <>
566 FO_COMMON_API std::string Constant<double>::Dump(unsigned short ntabs) const;
567
568 template <>
569 FO_COMMON_API std::string Constant<int>::Dump(unsigned short ntabs) const;
570
571 template <>
572 FO_COMMON_API std::string Constant<std::string>::Dump(unsigned short ntabs) const;
573
574 template <>
575 FO_COMMON_API std::string Constant<std::string>::Eval(const ScriptingContext& context) const;
576
577 template <typename T>
578 template <typename Archive>
serialize(Archive & ar,const unsigned int version)579 void Constant<T>::serialize(Archive& ar, const unsigned int version)
580 {
581 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(ValueRef)
582 & BOOST_SERIALIZATION_NVP(m_value)
583 & BOOST_SERIALIZATION_NVP(m_top_level_content);
584 }
585
586 ///////////////////////////////////////////////////////////
587 // Variable //
588 ///////////////////////////////////////////////////////////
589 template <typename T>
Variable(ReferenceType ref_type,const std::vector<std::string> & property_name,bool return_immediate_value)590 Variable<T>::Variable(ReferenceType ref_type, const std::vector<std::string>& property_name,
591 bool return_immediate_value) :
592 m_ref_type(ref_type),
593 m_property_name(property_name.begin(), property_name.end()),
594 m_return_immediate_value(return_immediate_value)
595 {}
596
597 template <typename T>
Variable(ReferenceType ref_type,const std::string & property_name,bool return_immediate_value)598 Variable<T>::Variable(ReferenceType ref_type, const std::string& property_name,
599 bool return_immediate_value) :
600 m_ref_type(ref_type),
601 m_property_name(),
602 m_return_immediate_value(return_immediate_value)
603 {
604 m_property_name.push_back(property_name);
605 }
606
607 template <typename T>
Variable(ReferenceType ref_type,const boost::optional<std::string> & container_name,const std::string & property_name,bool return_immediate_value)608 Variable<T>::Variable(ReferenceType ref_type,
609 const boost::optional<std::string>& container_name,
610 const std::string& property_name,
611 bool return_immediate_value) :
612 m_ref_type(ref_type),
613 m_property_name(),
614 m_return_immediate_value(return_immediate_value)
615 {
616 if (container_name)
617 m_property_name.push_back(*container_name);
618
619 m_property_name.push_back(property_name);
620 }
621
622 template <typename T>
623 bool Variable<T>::operator==(const ValueRef<T>& rhs) const
624 {
625 if (&rhs == this)
626 return true;
627 if (typeid(rhs) != typeid(*this))
628 return false;
629 const Variable<T>& rhs_ = static_cast<const Variable<T>&>(rhs);
630 return (m_ref_type == rhs_.m_ref_type) &&
631 (m_property_name == rhs_.m_property_name) &&
632 (m_return_immediate_value == rhs_.m_return_immediate_value);
633 }
634
635 template <typename T>
GetReferenceType()636 ReferenceType Variable<T>::GetReferenceType() const
637 { return m_ref_type; }
638
639 template <typename T>
PropertyName()640 const std::vector<std::string>& Variable<T>::PropertyName() const
641 { return m_property_name; }
642
643 template <typename T>
ReturnImmediateValue()644 bool Variable<T>::ReturnImmediateValue() const
645 { return m_return_immediate_value; }
646
647 template <typename T>
RootCandidateInvariant()648 bool Variable<T>::RootCandidateInvariant() const
649 { return m_ref_type != CONDITION_ROOT_CANDIDATE_REFERENCE; }
650
651 template <typename T>
LocalCandidateInvariant()652 bool Variable<T>::LocalCandidateInvariant() const
653 { return m_ref_type != CONDITION_LOCAL_CANDIDATE_REFERENCE; }
654
655 template <typename T>
TargetInvariant()656 bool Variable<T>::TargetInvariant() const
657 { return m_ref_type != EFFECT_TARGET_REFERENCE && m_ref_type != EFFECT_TARGET_VALUE_REFERENCE; }
658
659 template <typename T>
SourceInvariant()660 bool Variable<T>::SourceInvariant() const
661 { return m_ref_type != SOURCE_REFERENCE; }
662
663 template <typename T>
Description()664 std::string Variable<T>::Description() const
665 { return FormatedDescriptionPropertyNames(m_ref_type, m_property_name, m_return_immediate_value); }
666
667 template <typename T>
Dump(unsigned short ntabs)668 std::string Variable<T>::Dump(unsigned short ntabs) const
669 { return ReconstructName(m_property_name, m_ref_type, m_return_immediate_value); }
670
671 template <typename T>
GetCheckSum()672 unsigned int Variable<T>::GetCheckSum() const
673 {
674 unsigned int retval{0};
675
676 CheckSums::CheckSumCombine(retval, "ValueRef::Variable");
677 CheckSums::CheckSumCombine(retval, m_property_name);
678 CheckSums::CheckSumCombine(retval, m_ref_type);
679 CheckSums::CheckSumCombine(retval, m_return_immediate_value);
680 TraceLogger() << "GetCheckSum(Variable<T>): " << typeid(*this).name() << " retval: " << retval;
681 return retval;
682 }
683
684 template <>
685 FO_COMMON_API PlanetSize Variable<PlanetSize>::Eval(const ScriptingContext& context) const;
686
687 template <>
688 FO_COMMON_API PlanetType Variable<PlanetType>::Eval(const ScriptingContext& context) const;
689
690 template <>
691 FO_COMMON_API PlanetEnvironment Variable<PlanetEnvironment>::Eval(const ScriptingContext& context) const;
692
693 template <>
694 FO_COMMON_API UniverseObjectType Variable<UniverseObjectType>::Eval(const ScriptingContext& context) const;
695
696 template <>
697 FO_COMMON_API StarType Variable<StarType>::Eval(const ScriptingContext& context) const;
698
699 template <>
700 FO_COMMON_API Visibility Variable<Visibility>::Eval(const ScriptingContext& context) const;
701
702 template <>
703 FO_COMMON_API double Variable<double>::Eval(const ScriptingContext& context) const;
704
705 template <>
706 FO_COMMON_API int Variable<int>::Eval(const ScriptingContext& context) const;
707
708 template <>
709 FO_COMMON_API std::string Variable<std::string>::Eval(const ScriptingContext& context) const;
710
711 template <>
712 FO_COMMON_API std::vector<std::string> Variable<std::vector<std::string>>::Eval(const ScriptingContext& context) const;
713
714 template <typename T>
715 template <typename Archive>
serialize(Archive & ar,const unsigned int version)716 void Variable<T>::serialize(Archive& ar, const unsigned int version)
717 {
718 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(ValueRef)
719 & BOOST_SERIALIZATION_NVP(m_ref_type)
720 & BOOST_SERIALIZATION_NVP(m_property_name)
721 & BOOST_SERIALIZATION_NVP(m_return_immediate_value);
722 }
723
724 ///////////////////////////////////////////////////////////
725 // Statistic //
726 ///////////////////////////////////////////////////////////
727 template <typename T>
Statistic(std::unique_ptr<ValueRef<T>> && value_ref,StatisticType stat_type,std::unique_ptr<Condition::Condition> && sampling_condition)728 Statistic<T>::Statistic(std::unique_ptr<ValueRef<T>>&& value_ref, StatisticType stat_type,
729 std::unique_ptr<Condition::Condition>&& sampling_condition) :
730 Variable<T>(NON_OBJECT_REFERENCE, ""),
731 m_stat_type(stat_type),
732 m_sampling_condition(std::move(sampling_condition)),
733 m_value_ref(std::move(value_ref))
734 {}
735
736 template <typename T>
737 bool Statistic<T>::operator==(const ValueRef<T>& rhs) const
738 {
739 if (&rhs == this)
740 return true;
741 if (typeid(rhs) != typeid(*this))
742 return false;
743 const Statistic<T>& rhs_ = static_cast<const Statistic<T>&>(rhs);
744
745 if (m_stat_type != rhs_.m_stat_type)
746 return false;
747 if (this->m_value_ref != rhs_.m_value_ref)
748 return false;
749
750 if (m_sampling_condition == rhs_.m_sampling_condition) {
751 // check next member
752 } else if (!m_sampling_condition || !rhs_.m_sampling_condition) {
753 return false;
754 } else {
755 if (*m_sampling_condition != *(rhs_.m_sampling_condition))
756 return false;
757 }
758
759 return true;
760 }
761
762 template <typename T>
GetConditionMatches(const ScriptingContext & context,Condition::ObjectSet & condition_targets,Condition::Condition * condition)763 void Statistic<T>::GetConditionMatches(const ScriptingContext& context,
764 Condition::ObjectSet& condition_targets,
765 Condition::Condition* condition) const
766 {
767 condition_targets.clear();
768 if (!condition)
769 return;
770 condition->Eval(context, condition_targets);
771 }
772
773 template <typename T>
GetObjectPropertyValues(const ScriptingContext & context,const Condition::ObjectSet & objects,std::map<std::shared_ptr<const UniverseObject>,T> & object_property_values)774 void Statistic<T>::GetObjectPropertyValues(const ScriptingContext& context,
775 const Condition::ObjectSet& objects,
776 std::map<std::shared_ptr<const UniverseObject>, T>& object_property_values) const
777 {
778 object_property_values.clear();
779
780 if (m_value_ref) {
781 // evaluate ValueRef with each condition match as the LocalCandidate
782 // TODO: Can / should this be paralleized?
783 for (auto& object : objects) {
784 T property_value = m_value_ref->Eval(ScriptingContext(context, object));
785 object_property_values[object] = property_value;
786 }
787 }
788 }
789
790 template <typename T>
RootCandidateInvariant()791 bool Statistic<T>::RootCandidateInvariant() const
792 {
793 return Variable<T>::RootCandidateInvariant() &&
794 m_sampling_condition->RootCandidateInvariant() &&
795 (!m_value_ref || m_value_ref->RootCandidateInvariant());
796 }
797
798 template <typename T>
LocalCandidateInvariant()799 bool Statistic<T>::LocalCandidateInvariant() const
800 {
801 // don't need to check if sampling condition is LocalCandidateInvariant, as
802 // all conditions aren't, but that refers to their own local candidate. no
803 // condition is explicitly dependent on the parent context's local candidate.
804 return Variable<T>::LocalCandidateInvariant() &&
805 (!m_value_ref || m_value_ref->LocalCandidateInvariant());
806 }
807
808 template <typename T>
TargetInvariant()809 bool Statistic<T>::TargetInvariant() const
810 {
811 return Variable<T>::TargetInvariant() &&
812 m_sampling_condition->TargetInvariant() &&
813 (!m_value_ref || m_value_ref->TargetInvariant());
814 }
815
816 template <typename T>
SourceInvariant()817 bool Statistic<T>::SourceInvariant() const
818 {
819 return Variable<T>::SourceInvariant() &&
820 m_sampling_condition->SourceInvariant() &&
821 (!m_value_ref || m_value_ref->SourceInvariant());
822 }
823
824 template <typename T>
Description()825 std::string Statistic<T>::Description() const
826 {
827 if (m_value_ref)
828 return StatisticDescription(m_stat_type, m_value_ref->Description(),
829 m_sampling_condition ? m_sampling_condition->Description() : "");
830
831 auto temp = Variable<T>::Description();
832 if (!temp.empty())
833 return StatisticDescription(m_stat_type, temp, m_sampling_condition ? m_sampling_condition->Description() : "");
834
835 return StatisticDescription(m_stat_type, "", m_sampling_condition ? m_sampling_condition->Description() : "");
836 }
837
838 template <typename T>
Dump(unsigned short ntabs)839 std::string Statistic<T>::Dump(unsigned short ntabs) const
840 {
841 std::string retval = "Statistic ";
842
843 switch (m_stat_type) {
844 case COUNT: retval += "Count"; break;
845 case UNIQUE_COUNT: retval += "CountUnique"; break;
846 case IF: retval += "If"; break;
847 case SUM: retval += "Sum"; break;
848 case MEAN: retval += "Mean"; break;
849 case RMS: retval += "RMS"; break;
850 case MODE: retval += "Mode"; break;
851 case MAX: retval += "Max"; break;
852 case MIN: retval += "Min"; break;
853 case SPREAD: retval += "Spread"; break;
854 case STDEV: retval += "StDev"; break;
855 case PRODUCT: retval += "Product"; break;
856 default: retval += "???"; break;
857 }
858 if (m_value_ref)
859 retval += " value = " + m_value_ref->Dump();
860 if (m_sampling_condition)
861 retval += " condition = " + m_sampling_condition->Dump();
862 return retval;
863 }
864
865 template <typename T>
SetTopLevelContent(const std::string & content_name)866 void Statistic<T>::SetTopLevelContent(const std::string& content_name)
867 {
868 if (m_sampling_condition)
869 m_sampling_condition->SetTopLevelContent(content_name);
870 if (m_value_ref)
871 m_value_ref->SetTopLevelContent(content_name);
872 }
873
874 template <typename T>
Eval(const ScriptingContext & context)875 T Statistic<T>::Eval(const ScriptingContext& context) const
876 {
877 Condition::ObjectSet condition_matches;
878 GetConditionMatches(context, condition_matches, m_sampling_condition.get());
879
880 // special case for IF statistic... return a T(1) for true.
881 if (m_stat_type == IF) {
882 if (condition_matches.empty())
883 return T(0);
884 else
885 return T(1);
886 }
887
888 // todo: consider allowing MAX and MIN using string sorting?
889
890 // the only other statistic that can be computed on non-number property
891 // types and that is itself of a non-number type is the most common value
892 if (m_stat_type != MODE) {
893 ErrorLogger() << "Statistic<std::string>::Eval has invalid statistic type: "
894 << m_stat_type;
895 return T(-1);
896 }
897
898 // evaluate property for each condition-matched object
899 std::map<std::shared_ptr<const UniverseObject>, T> object_property_values;
900 GetObjectPropertyValues(context, condition_matches, object_property_values);
901
902 // count number of each result, tracking which has the most occurances
903 std::map<T, unsigned int> histogram;
904 auto most_common_property_value_it = histogram.begin();
905 unsigned int max_seen(0);
906
907 for (const auto& entry : object_property_values) {
908 const T& property_value = entry.second;
909
910 auto hist_it = histogram.find(property_value);
911 if (hist_it == histogram.end())
912 hist_it = histogram.insert({property_value, 0}).first;
913 unsigned int& num_seen = hist_it->second;
914
915 num_seen++;
916
917 if (num_seen > max_seen) {
918 most_common_property_value_it = hist_it;
919 max_seen = num_seen;
920 }
921 }
922
923 // return result (property value) that occured most frequently
924 return most_common_property_value_it->first;
925 }
926
927 template <typename T>
GetCheckSum()928 unsigned int Statistic<T>::GetCheckSum() const
929 {
930 unsigned int retval{0};
931
932 CheckSums::CheckSumCombine(retval, "ValueRef::Statistic");
933 CheckSums::CheckSumCombine(retval, m_stat_type);
934 CheckSums::CheckSumCombine(retval, m_sampling_condition);
935 CheckSums::CheckSumCombine(retval, m_value_ref);
936 TraceLogger() << "GetCheckSum(Statisic<T>): " << typeid(*this).name() << " retval: " << retval;
937 return retval;
938 }
939
940 template <>
941 FO_COMMON_API double Statistic<double>::Eval(const ScriptingContext& context) const;
942
943 template <>
944 FO_COMMON_API int Statistic<int>::Eval(const ScriptingContext& context) const;
945
946 template <>
947 FO_COMMON_API std::string Statistic<std::string>::Eval(const ScriptingContext& context) const;
948
949 template <typename T>
ReduceData(const std::map<std::shared_ptr<const UniverseObject>,T> & object_property_values)950 T Statistic<T>::ReduceData(const std::map<std::shared_ptr<const UniverseObject>, T>& object_property_values) const
951 {
952 if (object_property_values.empty())
953 return T(0);
954
955 switch (m_stat_type) {
956 case COUNT: {
957 return T(object_property_values.size());
958 break;
959 }
960 case UNIQUE_COUNT: {
961 std::set<T> observed_values;
962 for (const auto& entry : object_property_values) {
963 observed_values.insert(entry.second);
964 }
965 return T(observed_values.size());
966 break;
967 }
968 case IF: {
969 if (object_property_values.empty())
970 return T(0);
971 return T(1);
972 break;
973 }
974 case SUM: {
975 T accumulator(0);
976 for (const auto& entry : object_property_values) {
977 accumulator += entry.second;
978 }
979 return accumulator;
980 break;
981 }
982
983 case MEAN: {
984 T accumulator(0);
985 for (const auto& entry : object_property_values) {
986 accumulator += entry.second;
987 }
988 return accumulator / static_cast<T>(object_property_values.size());
989 break;
990 }
991
992 case RMS: {
993 T accumulator(0);
994 for (const auto& entry : object_property_values) {
995 accumulator += (entry.second * entry.second);
996 }
997 accumulator /= static_cast<T>(object_property_values.size());
998
999 double retval = std::sqrt(static_cast<double>(accumulator));
1000 return static_cast<T>(retval);
1001 break;
1002 }
1003
1004 case MODE: {
1005 // count number of each result, tracking which has the most occurances
1006 std::map<T, unsigned int> histogram;
1007 auto most_common_property_value_it = histogram.begin();
1008 unsigned int max_seen(0);
1009
1010 for (const auto& entry : object_property_values) {
1011 const T& property_value = entry.second;
1012
1013 auto hist_it = histogram.find(property_value);
1014 if (hist_it == histogram.end())
1015 hist_it = histogram.insert({property_value, 0}).first;
1016 unsigned int& num_seen = hist_it->second;
1017
1018 num_seen++;
1019
1020 if (num_seen > max_seen) {
1021 most_common_property_value_it = hist_it;
1022 max_seen = num_seen;
1023 }
1024 }
1025
1026 // return result (property value) that occured most frequently
1027 return most_common_property_value_it->first;
1028 break;
1029 }
1030
1031 case MAX: {
1032 auto max_it = object_property_values.begin();
1033
1034 for (auto it = object_property_values.begin();
1035 it != object_property_values.end(); ++it)
1036 {
1037 const T& property_value = it->second;
1038 if (property_value > max_it->second)
1039 max_it = it;
1040 }
1041
1042 // return maximal observed propery value
1043 return max_it->second;
1044 break;
1045 }
1046
1047 case MIN: {
1048 auto min_it = object_property_values.begin();
1049
1050 for (auto it = object_property_values.begin();
1051 it != object_property_values.end(); ++it)
1052 {
1053 const T& property_value = it->second;
1054 if (property_value < min_it->second)
1055 min_it = it;
1056 }
1057
1058 // return minimal observed propery value
1059 return min_it->second;
1060 break;
1061 }
1062
1063 case SPREAD: {
1064 auto max_it = object_property_values.begin();
1065 auto min_it = object_property_values.begin();
1066
1067 for (auto it = object_property_values.begin();
1068 it != object_property_values.end(); ++it)
1069 {
1070 const T& property_value = it->second;
1071 if (property_value > max_it->second)
1072 max_it = it;
1073 if (property_value < min_it->second)
1074 min_it = it;
1075 }
1076
1077 // return difference between maximal and minimal observed propery values
1078 return max_it->second - min_it->second;
1079 break;
1080 }
1081
1082 case STDEV: {
1083 if (object_property_values.size() < 2)
1084 return T(0);
1085
1086 // find sample mean
1087 T accumulator(0);
1088 for (const auto& entry : object_property_values) {
1089 accumulator += entry.second;
1090 }
1091 const T MEAN(accumulator / static_cast<T>(object_property_values.size()));
1092
1093 // find average of squared deviations from sample mean
1094 accumulator = T(0);
1095 for (const auto& entry : object_property_values) {
1096 accumulator += (entry.second - MEAN) * (entry.second - MEAN);
1097 }
1098 const T MEAN_DEV2(accumulator / static_cast<T>(static_cast<int>(object_property_values.size()) - 1));
1099 double retval = std::sqrt(static_cast<double>(MEAN_DEV2));
1100 return static_cast<T>(retval);
1101 break;
1102 }
1103
1104 case PRODUCT: {
1105 T accumulator(1);
1106 for (const auto& entry : object_property_values) {
1107 accumulator *= entry.second;
1108 }
1109 return accumulator;
1110 break;
1111 }
1112
1113 default:
1114 throw std::runtime_error("ValueRef evaluated with an unknown or invalid StatisticType.");
1115 break;
1116 }
1117 }
1118
1119 template <typename T>
1120 template <typename Archive>
serialize(Archive & ar,const unsigned int version)1121 void Statistic<T>::serialize(Archive& ar, const unsigned int version)
1122 {
1123 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Variable)
1124 & BOOST_SERIALIZATION_NVP(m_stat_type)
1125 & BOOST_SERIALIZATION_NVP(m_sampling_condition)
1126 & BOOST_SERIALIZATION_NVP(m_value_ref);
1127 }
1128
1129 ///////////////////////////////////////////////////////////
1130 // ComplexVariable //
1131 ///////////////////////////////////////////////////////////
1132 template <typename T>
ComplexVariable(const std::string & variable_name,std::unique_ptr<ValueRef<int>> && int_ref1,std::unique_ptr<ValueRef<int>> && int_ref2,std::unique_ptr<ValueRef<int>> && int_ref3,std::unique_ptr<ValueRef<std::string>> && string_ref1,std::unique_ptr<ValueRef<std::string>> && string_ref2,bool return_immediate_value)1133 ComplexVariable<T>::ComplexVariable(const std::string& variable_name,
1134 std::unique_ptr<ValueRef<int>>&& int_ref1,
1135 std::unique_ptr<ValueRef<int>>&& int_ref2,
1136 std::unique_ptr<ValueRef<int>>&& int_ref3,
1137 std::unique_ptr<ValueRef<std::string>>&& string_ref1,
1138 std::unique_ptr<ValueRef<std::string>>&& string_ref2,
1139 bool return_immediate_value) :
1140 Variable<T>(NON_OBJECT_REFERENCE, std::vector<std::string>(1, variable_name), return_immediate_value),
1141 m_int_ref1(std::move(int_ref1)),
1142 m_int_ref2(std::move(int_ref2)),
1143 m_int_ref3(std::move(int_ref3)),
1144 m_string_ref1(std::move(string_ref1)),
1145 m_string_ref2(std::move(string_ref2))
1146 {}
1147
1148 template <typename T>
1149 bool ComplexVariable<T>::operator==(const ValueRef<T>& rhs) const
1150 {
1151 if (&rhs == this)
1152 return true;
1153 if (typeid(rhs) != typeid(*this))
1154 return false;
1155 const ComplexVariable<T>& rhs_ = static_cast<const ComplexVariable<T>&>(rhs);
1156
1157 if (this->m_property_name != rhs_.m_property_name)
1158 return false;
1159 if (this->m_return_immediate_value != rhs_.m_return_immediate_value)
1160 return false;
1161
1162 if (m_int_ref1 == rhs_.m_int_ref1) {
1163 // check next member
1164 } else if (!m_int_ref1 || !rhs_.m_int_ref1) {
1165 return false;
1166 } else {
1167 if (*m_int_ref1 != *(rhs_.m_int_ref1))
1168 return false;
1169 }
1170
1171 if (m_int_ref2 == rhs_.m_int_ref2) {
1172 // check next member
1173 } else if (!m_int_ref2 || !rhs_.m_int_ref2) {
1174 return false;
1175 } else {
1176 if (*m_int_ref2 != *(rhs_.m_int_ref2))
1177 return false;
1178 }
1179
1180 if (m_int_ref3 == rhs_.m_int_ref3) {
1181 // check next member
1182 } else if (!m_int_ref3 || !rhs_.m_int_ref3) {
1183 return false;
1184 } else {
1185 if (*m_int_ref3 != *(rhs_.m_int_ref3))
1186 return false;
1187 }
1188
1189 if (m_string_ref1 == rhs_.m_string_ref1) {
1190 // check next member
1191 } else if (!m_string_ref1 || !rhs_.m_string_ref1) {
1192 return false;
1193 } else {
1194 if (*m_string_ref1 != *(rhs_.m_string_ref1))
1195 return false;
1196 }
1197
1198 if (m_string_ref2 == rhs_.m_string_ref2) {
1199 // check next member
1200 } else if (!m_string_ref2 || !rhs_.m_string_ref2) {
1201 return false;
1202 } else {
1203 if (*m_string_ref2 != *(rhs_.m_string_ref2))
1204 return false;
1205 }
1206
1207 return true;
1208 }
1209
1210 template <typename T>
IntRef1()1211 const ValueRef<int>* ComplexVariable<T>::IntRef1() const
1212 { return m_int_ref1.get(); }
1213
1214 template <typename T>
IntRef2()1215 const ValueRef<int>* ComplexVariable<T>::IntRef2() const
1216 { return m_int_ref2.get(); }
1217
1218 template <typename T>
IntRef3()1219 const ValueRef<int>* ComplexVariable<T>::IntRef3() const
1220 { return m_int_ref3.get(); }
1221
1222 template <typename T>
StringRef1()1223 const ValueRef<std::string>* ComplexVariable<T>::StringRef1() const
1224 { return m_string_ref1.get(); }
1225
1226 template <typename T>
StringRef2()1227 const ValueRef<std::string>* ComplexVariable<T>::StringRef2() const
1228 { return m_string_ref2.get(); }
1229
1230 template <typename T>
RootCandidateInvariant()1231 bool ComplexVariable<T>::RootCandidateInvariant() const
1232 {
1233 return Variable<T>::RootCandidateInvariant()
1234 && (!m_int_ref1 || m_int_ref1->RootCandidateInvariant())
1235 && (!m_int_ref2 || m_int_ref2->RootCandidateInvariant())
1236 && (!m_int_ref3 || m_int_ref3->RootCandidateInvariant())
1237 && (!m_string_ref1 || m_string_ref1->RootCandidateInvariant())
1238 && (!m_string_ref2 || m_string_ref2->RootCandidateInvariant());
1239 }
1240
1241 template <typename T>
LocalCandidateInvariant()1242 bool ComplexVariable<T>::LocalCandidateInvariant() const
1243 {
1244 return (!m_int_ref1 || m_int_ref1->LocalCandidateInvariant())
1245 && (!m_int_ref2 || m_int_ref2->LocalCandidateInvariant())
1246 && (!m_int_ref3 || m_int_ref3->LocalCandidateInvariant())
1247 && (!m_string_ref1 || m_string_ref1->LocalCandidateInvariant())
1248 && (!m_string_ref2 || m_string_ref2->LocalCandidateInvariant());
1249 }
1250
1251 template <typename T>
TargetInvariant()1252 bool ComplexVariable<T>::TargetInvariant() const
1253 {
1254 return (!m_int_ref1 || m_int_ref1->TargetInvariant())
1255 && (!m_int_ref2 || m_int_ref2->TargetInvariant())
1256 && (!m_int_ref3 || m_int_ref3->TargetInvariant())
1257 && (!m_string_ref1 || m_string_ref1->TargetInvariant())
1258 && (!m_string_ref2 || m_string_ref2->TargetInvariant());
1259 }
1260
1261 template <typename T>
SourceInvariant()1262 bool ComplexVariable<T>::SourceInvariant() const
1263 {
1264 return (!m_int_ref1 || m_int_ref1->SourceInvariant())
1265 && (!m_int_ref2 || m_int_ref2->SourceInvariant())
1266 && (!m_int_ref3 || m_int_ref3->SourceInvariant())
1267 && (!m_string_ref1 || m_string_ref1->SourceInvariant())
1268 && (!m_string_ref2 || m_string_ref2->SourceInvariant());
1269 }
1270
1271 template <typename T>
Description()1272 std::string ComplexVariable<T>::Description() const
1273 {
1274 std::string retval = ComplexVariableDescription(
1275 this->m_property_name,
1276 m_int_ref1 ? m_int_ref1.get() : nullptr,
1277 m_int_ref2 ? m_int_ref2.get() : nullptr,
1278 m_int_ref3 ? m_int_ref3.get() : nullptr,
1279 m_string_ref1 ? m_string_ref1.get() : nullptr,
1280 m_string_ref2 ? m_string_ref2.get() : nullptr);
1281 if (retval.empty())
1282 return Dump();
1283 return retval;
1284 }
1285
1286 template <typename T>
Dump(unsigned short ntabs)1287 std::string ComplexVariable<T>::Dump(unsigned short ntabs) const
1288 {
1289 return ComplexVariableDump(this->m_property_name,
1290 m_int_ref1 ? m_int_ref1.get() : nullptr,
1291 m_int_ref2 ? m_int_ref2.get() : nullptr,
1292 m_int_ref3 ? m_int_ref3.get() : nullptr,
1293 m_string_ref1 ? m_string_ref1.get() : nullptr,
1294 m_string_ref2 ? m_string_ref2.get() : nullptr);
1295 }
1296
1297 template <typename T>
SetTopLevelContent(const std::string & content_name)1298 void ComplexVariable<T>::SetTopLevelContent(const std::string& content_name)
1299 {
1300 if (m_int_ref1)
1301 m_int_ref1->SetTopLevelContent(content_name);
1302 if (m_int_ref2)
1303 m_int_ref2->SetTopLevelContent(content_name);
1304 if (m_int_ref3)
1305 m_int_ref3->SetTopLevelContent(content_name);
1306 if (m_string_ref1)
1307 m_string_ref1->SetTopLevelContent(content_name);
1308 if (m_string_ref2)
1309 m_string_ref2->SetTopLevelContent(content_name);
1310 }
1311
1312 template <typename T>
GetCheckSum()1313 unsigned int ComplexVariable<T>::GetCheckSum() const
1314 {
1315 unsigned int retval{0};
1316
1317 CheckSums::CheckSumCombine(retval, "ValueRef::ComplexVariable");
1318 CheckSums::CheckSumCombine(retval, m_int_ref1);
1319 CheckSums::CheckSumCombine(retval, m_int_ref2);
1320 CheckSums::CheckSumCombine(retval, m_int_ref3);
1321 CheckSums::CheckSumCombine(retval, m_string_ref1);
1322 CheckSums::CheckSumCombine(retval, m_string_ref2);
1323 TraceLogger() << "GetCheckSum(ComplexVariable<T>): " << typeid(*this).name() << " retval: " << retval;
1324 return retval;
1325 }
1326
1327 template <>
1328 FO_COMMON_API PlanetSize ComplexVariable<PlanetSize>::Eval(const ScriptingContext& context) const;
1329
1330 template <>
1331 FO_COMMON_API PlanetType ComplexVariable<PlanetType>::Eval(const ScriptingContext& context) const;
1332
1333 template <>
1334 FO_COMMON_API PlanetEnvironment ComplexVariable<PlanetEnvironment>::Eval(const ScriptingContext& context) const;
1335
1336 template <>
1337 FO_COMMON_API UniverseObjectType ComplexVariable<UniverseObjectType>::Eval(const ScriptingContext& context) const;
1338
1339 template <>
1340 FO_COMMON_API StarType ComplexVariable<StarType>::Eval(const ScriptingContext& context) const;
1341
1342 template <>
1343 FO_COMMON_API Visibility ComplexVariable<Visibility>::Eval(const ScriptingContext& context) const;
1344
1345 template <>
1346 FO_COMMON_API double ComplexVariable<double>::Eval(const ScriptingContext& context) const;
1347
1348 template <>
1349 FO_COMMON_API int ComplexVariable<int>::Eval(const ScriptingContext& context) const;
1350
1351 template <>
1352 FO_COMMON_API std::string ComplexVariable<std::string>::Eval(const ScriptingContext& context) const;
1353
1354 template <>
1355 FO_COMMON_API std::string ComplexVariable<Visibility>::Dump(unsigned short ntabs) const;
1356
1357 template <>
1358 FO_COMMON_API std::string ComplexVariable<double>::Dump(unsigned short ntabs) const;
1359
1360 template <>
1361 FO_COMMON_API std::string ComplexVariable<int>::Dump(unsigned short ntabs) const;
1362
1363 template <>
1364 FO_COMMON_API std::string ComplexVariable<std::string>::Dump(unsigned short ntabs) const;
1365
1366 template <typename T>
1367 template <typename Archive>
serialize(Archive & ar,const unsigned int version)1368 void ComplexVariable<T>::serialize(Archive& ar, const unsigned int version)
1369 {
1370 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Variable)
1371 & BOOST_SERIALIZATION_NVP(m_int_ref1)
1372 & BOOST_SERIALIZATION_NVP(m_int_ref2)
1373 & BOOST_SERIALIZATION_NVP(m_int_ref3)
1374 & BOOST_SERIALIZATION_NVP(m_string_ref1)
1375 & BOOST_SERIALIZATION_NVP(m_string_ref2);
1376 }
1377
1378 ///////////////////////////////////////////////////////////
1379 // StaticCast //
1380 ///////////////////////////////////////////////////////////
1381 template <typename FromType, typename ToType>
1382 template <typename T>
StaticCast(T && value_ref,typename std::enable_if<std::is_convertible<T,std::unique_ptr<Variable<FromType>>>::value>::type *)1383 StaticCast<FromType, ToType>::StaticCast(
1384 T&& value_ref,
1385 typename std::enable_if<std::is_convertible<T, std::unique_ptr<Variable<FromType>>>::value>::type*) :
1386 Variable<ToType>(value_ref->GetReferenceType(), value_ref->PropertyName()),
1387 m_value_ref(std::move(value_ref))
1388 {}
1389
1390 template <typename FromType, typename ToType>
1391 template <typename T>
StaticCast(T && value_ref,typename std::enable_if<std::is_convertible<T,std::unique_ptr<ValueRef<FromType>>>::value &&!std::is_convertible<T,std::unique_ptr<Variable<FromType>>>::value>::type *)1392 StaticCast<FromType, ToType>::StaticCast(
1393 T&& value_ref,
1394 typename std::enable_if<
1395 std::is_convertible<T, std::unique_ptr<ValueRef<FromType>>>::value
1396 && !std::is_convertible<T, std::unique_ptr<Variable<FromType>>>::value>::type*) :
1397 Variable<ToType>(NON_OBJECT_REFERENCE),
1398 m_value_ref(std::move(value_ref))
1399 {}
1400
1401 template <typename FromType, typename ToType>
1402 bool StaticCast<FromType, ToType>::operator==(const ValueRef<ToType>& rhs) const
1403 {
1404 if (&rhs == this)
1405 return true;
1406 if (typeid(rhs) != typeid(*this))
1407 return false;
1408 const StaticCast<FromType, ToType>& rhs_ =
1409 static_cast<const StaticCast<FromType, ToType>&>(rhs);
1410
1411 if (m_value_ref == rhs_.m_value_ref) {
1412 // check next member
1413 } else if (!m_value_ref || !rhs_.m_value_ref) {
1414 return false;
1415 } else {
1416 if (*m_value_ref != *(rhs_.m_value_ref))
1417 return false;
1418 }
1419
1420 return true;
1421 }
1422
1423 template <typename FromType, typename ToType>
Eval(const ScriptingContext & context)1424 ToType StaticCast<FromType, ToType>::Eval(const ScriptingContext& context) const
1425 { return static_cast<ToType>(m_value_ref->Eval(context)); }
1426
1427 template <typename FromType, typename ToType>
RootCandidateInvariant()1428 bool StaticCast<FromType, ToType>::RootCandidateInvariant() const
1429 { return m_value_ref->RootCandidateInvariant(); }
1430
1431 template <typename FromType, typename ToType>
LocalCandidateInvariant()1432 bool StaticCast<FromType, ToType>::LocalCandidateInvariant() const
1433 { return m_value_ref->LocalCandidateInvariant(); }
1434
1435 template <typename FromType, typename ToType>
TargetInvariant()1436 bool StaticCast<FromType, ToType>::TargetInvariant() const
1437 { return m_value_ref->TargetInvariant(); }
1438
1439 template <typename FromType, typename ToType>
SourceInvariant()1440 bool StaticCast<FromType, ToType>::SourceInvariant() const
1441 { return m_value_ref->SourceInvariant(); }
1442
1443 template <typename FromType, typename ToType>
Description()1444 std::string StaticCast<FromType, ToType>::Description() const
1445 { return m_value_ref->Description(); }
1446
1447 template <typename FromType, typename ToType>
Dump(unsigned short ntabs)1448 std::string StaticCast<FromType, ToType>::Dump(unsigned short ntabs) const
1449 { return m_value_ref->Dump(ntabs); }
1450
1451 template <typename FromType, typename ToType>
SetTopLevelContent(const std::string & content_name)1452 void StaticCast<FromType, ToType>::SetTopLevelContent(const std::string& content_name)
1453 {
1454 if (m_value_ref)
1455 m_value_ref->SetTopLevelContent(content_name);
1456 }
1457
1458 template <typename FromType, typename ToType>
GetCheckSum()1459 unsigned int StaticCast<FromType, ToType>::GetCheckSum() const
1460 {
1461 unsigned int retval{0};
1462
1463 CheckSums::CheckSumCombine(retval, "ValueRef::StaticCast");
1464 CheckSums::CheckSumCombine(retval, m_value_ref);
1465 TraceLogger() << "GetCheckSum(StaticCast<FromType, ToType>): " << typeid(*this).name() << " retval: " << retval;
1466 return retval;
1467 }
1468
1469 template <typename FromType, typename ToType>
1470 template <typename Archive>
serialize(Archive & ar,const unsigned int version)1471 void StaticCast<FromType, ToType>::serialize(Archive& ar, const unsigned int version)
1472 {
1473 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(ValueRef)
1474 & BOOST_SERIALIZATION_NVP(m_value_ref);
1475 }
1476
1477 ///////////////////////////////////////////////////////////
1478 // StringCast //
1479 ///////////////////////////////////////////////////////////
1480 template <typename FromType>
StringCast(std::unique_ptr<ValueRef<FromType>> && value_ref)1481 StringCast<FromType>::StringCast(std::unique_ptr<ValueRef<FromType>>&& value_ref) :
1482 Variable<std::string>(NON_OBJECT_REFERENCE),
1483 m_value_ref(std::move(value_ref))
1484 {
1485 auto raw_ref_ptr = m_value_ref.get();
1486 // if looking up a the results of ValueRef::Variable::Eval, can copy that
1487 // ValueRef's internals to expose the reference type and property name from
1488 // this ValueRef
1489 if (auto var_ref = dynamic_cast<Variable<FromType>*>(raw_ref_ptr)) {
1490 this->m_ref_type = var_ref->GetReferenceType();
1491 this->m_property_name = var_ref->PropertyName();
1492 }
1493 }
1494
1495 template <typename FromType>
1496 bool StringCast<FromType>::operator==(const ValueRef<std::string>& rhs) const
1497 {
1498 if (&rhs == this)
1499 return true;
1500 if (typeid(rhs) != typeid(*this))
1501 return false;
1502 const StringCast<FromType>& rhs_ =
1503 static_cast<const StringCast<FromType>&>(rhs);
1504
1505 if (m_value_ref == rhs_.m_value_ref) {
1506 // check next member
1507 } else if (!m_value_ref || !rhs_.m_value_ref) {
1508 return false;
1509 } else {
1510 if (*m_value_ref != *(rhs_.m_value_ref))
1511 return false;
1512 }
1513
1514 return true;
1515 }
1516
1517 template <typename FromType>
Eval(const ScriptingContext & context)1518 std::string StringCast<FromType>::Eval(const ScriptingContext& context) const
1519 {
1520 if (!m_value_ref)
1521 return "";
1522 std::string retval;
1523 try {
1524 retval = boost::lexical_cast<std::string>(m_value_ref->Eval(context));
1525 } catch (...) {
1526 }
1527 return retval;
1528 }
1529
1530 template <typename FromType>
GetCheckSum()1531 unsigned int StringCast<FromType>::GetCheckSum() const
1532 {
1533 unsigned int retval{0};
1534
1535 CheckSums::CheckSumCombine(retval, "ValueRef::StringCast");
1536 CheckSums::CheckSumCombine(retval, m_value_ref);
1537 TraceLogger() << "GetCheckSum(StringCast<FromType>): " << typeid(*this).name() << " retval: " << retval;
1538 return retval;
1539 }
1540
1541 template <>
1542 FO_COMMON_API std::string StringCast<double>::Eval(const ScriptingContext& context) const;
1543
1544 template <>
1545 FO_COMMON_API std::string StringCast<int>::Eval(const ScriptingContext& context) const;
1546
1547 template <>
1548 FO_COMMON_API std::string StringCast<std::vector<std::string>>::Eval(const ScriptingContext& context) const;
1549
1550 template <typename FromType>
RootCandidateInvariant()1551 bool StringCast<FromType>::RootCandidateInvariant() const
1552 { return m_value_ref->RootCandidateInvariant(); }
1553
1554 template <typename FromType>
LocalCandidateInvariant()1555 bool StringCast<FromType>::LocalCandidateInvariant() const
1556 { return m_value_ref->LocalCandidateInvariant(); }
1557
1558 template <typename FromType>
TargetInvariant()1559 bool StringCast<FromType>::TargetInvariant() const
1560 { return m_value_ref->TargetInvariant(); }
1561
1562 template <typename FromType>
SourceInvariant()1563 bool StringCast<FromType>::SourceInvariant() const
1564 { return m_value_ref->SourceInvariant(); }
1565
1566 template <typename FromType>
Description()1567 std::string StringCast<FromType>::Description() const
1568 { return m_value_ref->Description(); }
1569
1570 template <typename FromType>
Dump(unsigned short ntabs)1571 std::string StringCast<FromType>::Dump(unsigned short ntabs) const
1572 { return m_value_ref->Dump(ntabs); }
1573
1574 template <typename FromType>
SetTopLevelContent(const std::string & content_name)1575 void StringCast<FromType>::SetTopLevelContent(const std::string& content_name) {
1576 if (m_value_ref)
1577 m_value_ref->SetTopLevelContent(content_name);
1578 }
1579
1580 template <typename FromType>
1581 template <typename Archive>
serialize(Archive & ar,const unsigned int version)1582 void StringCast<FromType>::serialize(Archive& ar, const unsigned int version)
1583 {
1584 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(ValueRef)
1585 & BOOST_SERIALIZATION_NVP(m_value_ref);
1586 }
1587
1588 ///////////////////////////////////////////////////////////
1589 // UserStringLookup //
1590 ///////////////////////////////////////////////////////////
1591 template <typename FromType>
UserStringLookup(std::unique_ptr<ValueRef<FromType>> && value_ref)1592 UserStringLookup<FromType>::UserStringLookup(std::unique_ptr<ValueRef<FromType>>&& value_ref) :
1593 Variable<std::string>(NON_OBJECT_REFERENCE),
1594 m_value_ref(std::move(value_ref))
1595 {
1596 auto raw_ref_ptr = m_value_ref.get();
1597 // if looking up a the results of ValueRef::Variable::Eval, can copy that
1598 // ValueRef's internals to expose the reference type and property name from
1599 // this ValueRef
1600 if (auto var_ref = dynamic_cast<Variable<FromType>*>(raw_ref_ptr)) {
1601 this->m_ref_type = var_ref->GetReferenceType();
1602 this->m_property_name = var_ref->PropertyName();
1603 }
1604 }
1605
1606 template <typename FromType>
1607 bool UserStringLookup<FromType>::operator==(const ValueRef<std::string>& rhs) const {
1608 if (&rhs == this)
1609 return true;
1610 if (typeid(rhs) != typeid(*this))
1611 return false;
1612 const UserStringLookup& rhs_ = static_cast<const UserStringLookup&>(rhs);
1613
1614 if (m_value_ref == rhs_.m_value_ref) {
1615 // check next member
1616 }
1617 else if (!m_value_ref || !rhs_.m_value_ref) {
1618 return false;
1619 }
1620 else {
1621 if (*m_value_ref != *(rhs_.m_value_ref))
1622 return false;
1623 }
1624
1625 return true;
1626 }
1627
1628 template <typename FromType>
Eval(const ScriptingContext & context)1629 std::string UserStringLookup<FromType>::Eval(const ScriptingContext& context) const {
1630 if (!m_value_ref)
1631 return "";
1632 std::string ref_val = boost::lexical_cast<std::string>(m_value_ref->Eval(context));
1633 if (ref_val.empty() || !UserStringExists(ref_val))
1634 return "";
1635 return UserString(ref_val);
1636 }
1637
1638 template <>
1639 FO_COMMON_API std::string UserStringLookup<std::string>::Eval(const ScriptingContext& context) const;
1640
1641 template <>
1642 FO_COMMON_API std::string UserStringLookup<std::vector<std::string>>::Eval(const ScriptingContext& context) const;
1643
1644 template <typename FromType>
RootCandidateInvariant()1645 bool UserStringLookup<FromType>::RootCandidateInvariant() const
1646 {
1647 return m_value_ref->RootCandidateInvariant();
1648 }
1649
1650 template <typename FromType>
LocalCandidateInvariant()1651 bool UserStringLookup<FromType>::LocalCandidateInvariant() const
1652 {
1653 return !m_value_ref || m_value_ref->LocalCandidateInvariant();
1654 }
1655
1656 template <typename FromType>
TargetInvariant()1657 bool UserStringLookup<FromType>::TargetInvariant() const
1658 {
1659 return !m_value_ref || m_value_ref->TargetInvariant();
1660 }
1661
1662 template <typename FromType>
SourceInvariant()1663 bool UserStringLookup<FromType>::SourceInvariant() const
1664 {
1665 return !m_value_ref || m_value_ref->SourceInvariant();
1666 }
1667
1668 template <typename FromType>
Description()1669 std::string UserStringLookup<FromType>::Description() const
1670 {
1671 return m_value_ref->Description();
1672 }
1673
1674 template <typename FromType>
Dump(unsigned short ntabs)1675 std::string UserStringLookup<FromType>::Dump(unsigned short ntabs) const
1676 {
1677 return m_value_ref->Dump(ntabs);
1678 }
1679
1680 template <typename FromType>
SetTopLevelContent(const std::string & content_name)1681 void UserStringLookup<FromType>::SetTopLevelContent(const std::string& content_name) {
1682 if (m_value_ref)
1683 m_value_ref->SetTopLevelContent(content_name);
1684 }
1685
1686 template <typename FromType>
GetCheckSum()1687 unsigned int UserStringLookup<FromType>::GetCheckSum() const
1688 {
1689 unsigned int retval{0};
1690
1691 CheckSums::CheckSumCombine(retval, "ValueRef::UserStringLookup");
1692 CheckSums::CheckSumCombine(retval, m_value_ref);
1693 TraceLogger() << "GetCheckSum(UserStringLookup<FromType>): " << typeid(*this).name() << " retval: " << retval;
1694 return retval;
1695 }
1696
1697 template <typename FromType>
1698 template <typename Archive>
serialize(Archive & ar,const unsigned int version)1699 void UserStringLookup<FromType>::serialize(Archive& ar, const unsigned int version)
1700 {
1701 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(ValueRef<std::string>)
1702 & BOOST_SERIALIZATION_NVP(m_value_ref);
1703 }
1704
1705 ///////////////////////////////////////////////////////////
1706 // NameLookup //
1707 ///////////////////////////////////////////////////////////
1708 template <typename Archive>
serialize(Archive & ar,const unsigned int version)1709 void NameLookup::serialize(Archive& ar, const unsigned int version)
1710 {
1711 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(ValueRef<std::string>)
1712 & BOOST_SERIALIZATION_NVP(m_value_ref)
1713 & BOOST_SERIALIZATION_NVP(m_lookup_type);
1714 }
1715
1716 ///////////////////////////////////////////////////////////
1717 // Operation //
1718 ///////////////////////////////////////////////////////////
1719 template <typename T>
Operation(OpType op_type,std::unique_ptr<ValueRef<T>> && operand1,std::unique_ptr<ValueRef<T>> && operand2)1720 Operation<T>::Operation(OpType op_type,
1721 std::unique_ptr<ValueRef<T>>&& operand1,
1722 std::unique_ptr<ValueRef<T>>&& operand2) :
1723 m_op_type(op_type)
1724 {
1725 if (operand1)
1726 m_operands.push_back(std::move(operand1));
1727 if (operand2)
1728 m_operands.push_back(std::move(operand2));
1729 DetermineIfConstantExpr();
1730 CacheConstValue();
1731 }
1732
1733 template <typename T>
Operation(OpType op_type,std::unique_ptr<ValueRef<T>> && operand)1734 Operation<T>::Operation(OpType op_type, std::unique_ptr<ValueRef<T>>&& operand) :
1735 m_op_type(op_type)
1736 {
1737 if (operand)
1738 m_operands.push_back(std::move(operand));
1739 DetermineIfConstantExpr();
1740 CacheConstValue();
1741 }
1742
1743 template <typename T>
Operation(OpType op_type,std::vector<std::unique_ptr<ValueRef<T>>> && operands)1744 Operation<T>::Operation(OpType op_type, std::vector<std::unique_ptr<ValueRef<T>>>&& operands) :
1745 m_op_type(op_type),
1746 m_operands(std::move(operands))
1747 {
1748 DetermineIfConstantExpr();
1749 CacheConstValue();
1750 }
1751
1752 template <typename T>
DetermineIfConstantExpr()1753 void Operation<T>::DetermineIfConstantExpr()
1754 {
1755 if (m_op_type == RANDOM_UNIFORM || m_op_type == RANDOM_PICK) {
1756 m_constant_expr = false;
1757 return;
1758 }
1759
1760 m_constant_expr = true; // may be overridden...
1761
1762 for (auto& operand : m_operands) {
1763 if (operand && !operand->ConstantExpr()) {
1764 m_constant_expr = false;
1765 return;
1766 }
1767 }
1768 }
1769
1770 template <typename T>
CacheConstValue()1771 void Operation<T>::CacheConstValue()
1772 {
1773 if (!m_constant_expr)
1774 return;
1775
1776 m_cached_const_value = this->EvalImpl(ScriptingContext());
1777 }
1778
1779 template <typename T>
1780 bool Operation<T>::operator==(const ValueRef<T>& rhs) const
1781 {
1782 if (&rhs == this)
1783 return true;
1784 if (typeid(rhs) != typeid(*this))
1785 return false;
1786 const Operation<T>& rhs_ = static_cast<const Operation<T>&>(rhs);
1787
1788 if (m_operands == rhs_.m_operands)
1789 return true;
1790
1791 if (m_operands.size() != rhs_.m_operands.size())
1792 return false;
1793
1794 for (unsigned int i = 0; i < m_operands.size(); ++i) {
1795 if (m_operands[i] != rhs_.m_operands[i])
1796 return false;
1797 if (m_operands[i] && *(m_operands[i]) != *(rhs_.m_operands[i]))
1798 return false;
1799 }
1800
1801 // should be redundant...
1802 if (m_constant_expr != rhs_.m_constant_expr)
1803 return false;
1804
1805 return true;
1806 }
1807
1808 template <typename T>
GetOpType()1809 OpType Operation<T>::GetOpType() const
1810 { return m_op_type; }
1811
1812 template <typename T>
LHS()1813 const ValueRef<T>* Operation<T>::LHS() const
1814 {
1815 if (m_operands.empty())
1816 return nullptr;
1817 return m_operands[0].get();
1818 }
1819
1820 template <typename T>
RHS()1821 const ValueRef<T>* Operation<T>::RHS() const
1822 {
1823 if (m_operands.size() < 2)
1824 return nullptr;
1825 return m_operands[1].get();
1826 }
1827
1828 template <typename T>
Operands()1829 const std::vector<ValueRef<T>*> Operation<T>::Operands() const
1830 {
1831 std::vector<ValueRef<T>*> retval(m_operands.size());
1832 std::transform(m_operands.begin(), m_operands.end(), retval.begin(),
1833 [](const auto& xx){ return xx.get(); });
1834 return retval;
1835 }
1836
1837 template <typename T>
Eval(const ScriptingContext & context)1838 T Operation<T>::Eval(const ScriptingContext& context) const
1839 {
1840 if (m_constant_expr)
1841 return m_cached_const_value;
1842 return this->EvalImpl(context);
1843 }
1844
1845 template <typename T>
EvalImpl(const ScriptingContext & context)1846 T Operation<T>::EvalImpl(const ScriptingContext& context) const
1847 {
1848 switch (m_op_type) {
1849 case TIMES: {
1850 // useful for writing a "Statistic If" expression with arbitrary types.
1851 // If returns T(0) or T(1) for nothing or something matching the
1852 // sampling condition. This can be checked here by returning T(0) if
1853 // the LHS operand is T(0) and just returning RHS() otherwise.
1854 if (!LHS()->Eval(context))
1855 return T(0);
1856 return RHS()->Eval(context);
1857 break;
1858 }
1859
1860 case MAXIMUM:
1861 case MINIMUM: {
1862 // evaluate all operands, return smallest or biggest
1863 std::set<T> vals;
1864 for (auto& vr : m_operands) {
1865 if (vr)
1866 vals.insert(vr->Eval(context));
1867 }
1868 if (m_op_type == MINIMUM)
1869 return vals.empty() ? T(-1) : *vals.begin();
1870 else
1871 return vals.empty() ? T(-1) : *vals.rbegin();
1872 break;
1873 }
1874
1875 case RANDOM_PICK: {
1876 // select one operand, evaluate it, return result
1877 if (m_operands.empty())
1878 return T(-1); // should be INVALID_T of enum types
1879 unsigned int idx = RandSmallInt(0, m_operands.size() - 1);
1880 auto& vr = *std::next(m_operands.begin(), idx);
1881 if (!vr)
1882 return T(-1); // should be INVALID_T of enum types
1883 return vr->Eval(context);
1884 break;
1885 }
1886
1887 case COMPARE_EQUAL:
1888 case COMPARE_GREATER_THAN:
1889 case COMPARE_GREATER_THAN_OR_EQUAL:
1890 case COMPARE_LESS_THAN:
1891 case COMPARE_LESS_THAN_OR_EQUAL:
1892 case COMPARE_NOT_EQUAL: {
1893 const T&& lhs_val = LHS()->Eval(context);
1894 const T&& rhs_val = RHS()->Eval(context);
1895 bool test_result = false;
1896 switch (m_op_type) {
1897 case COMPARE_EQUAL: test_result = lhs_val == rhs_val; break;
1898 case COMPARE_GREATER_THAN: test_result = lhs_val > rhs_val; break;
1899 case COMPARE_GREATER_THAN_OR_EQUAL: test_result = lhs_val >= rhs_val; break;
1900 case COMPARE_LESS_THAN: test_result = lhs_val < rhs_val; break;
1901 case COMPARE_LESS_THAN_OR_EQUAL: test_result = lhs_val <= rhs_val; break;
1902 case COMPARE_NOT_EQUAL: test_result = lhs_val != rhs_val; break;
1903 default: break; // ??? do nothing, default to false
1904 }
1905 if (m_operands.size() < 3) {
1906 return T(1);
1907 } else if (m_operands.size() < 4) {
1908 if (test_result)
1909 return m_operands[2]->Eval(context);
1910 else
1911 return T(0);
1912 } else {
1913 if (test_result)
1914 return m_operands[2]->Eval(context);
1915 else
1916 return m_operands[3]->Eval(context);
1917 }
1918 break;
1919 }
1920
1921 default:
1922 break;
1923 }
1924
1925 throw std::runtime_error("ValueRef::Operation<T>::EvalImpl evaluated with an unknown or invalid OpType.");
1926 }
1927
1928 template <typename T>
GetCheckSum()1929 unsigned int Operation<T>::GetCheckSum() const
1930 {
1931 unsigned int retval{0};
1932
1933 CheckSums::CheckSumCombine(retval, "ValueRef::Operation");
1934 CheckSums::CheckSumCombine(retval, m_op_type);
1935 CheckSums::CheckSumCombine(retval, m_operands);
1936 CheckSums::CheckSumCombine(retval, m_constant_expr);
1937 CheckSums::CheckSumCombine(retval, m_cached_const_value);
1938 TraceLogger() << "GetCheckSum(Operation<T>): " << typeid(*this).name() << " retval: " << retval;
1939 return retval;
1940 }
1941
1942 template <>
1943 FO_COMMON_API std::string Operation<std::string>::EvalImpl(const ScriptingContext& context) const;
1944
1945 template <>
1946 FO_COMMON_API double Operation<double>::EvalImpl(const ScriptingContext& context) const;
1947
1948 template <>
1949 FO_COMMON_API int Operation<int>::EvalImpl(const ScriptingContext& context) const;
1950
1951 template <typename T>
RootCandidateInvariant()1952 bool Operation<T>::RootCandidateInvariant() const
1953 {
1954 if (m_op_type == RANDOM_UNIFORM || m_op_type == RANDOM_PICK)
1955 return false;
1956 for (auto& operand : m_operands) {
1957 if (operand && !operand->RootCandidateInvariant())
1958 return false;
1959 }
1960 return true;
1961 }
1962
1963 template <typename T>
LocalCandidateInvariant()1964 bool Operation<T>::LocalCandidateInvariant() const
1965 {
1966 if (m_op_type == RANDOM_UNIFORM || m_op_type == RANDOM_PICK)
1967 return false;
1968 for (auto& operand : m_operands) {
1969 if (operand && !operand->LocalCandidateInvariant())
1970 return false;
1971 }
1972 return true;
1973 }
1974
1975 template <typename T>
TargetInvariant()1976 bool Operation<T>::TargetInvariant() const
1977 {
1978 if (m_op_type == RANDOM_UNIFORM || m_op_type == RANDOM_PICK)
1979 return false;
1980 for (auto& operand : m_operands) {
1981 if (operand && !operand->TargetInvariant())
1982 return false;
1983 }
1984 return true;
1985 }
1986
1987 template <typename T>
SourceInvariant()1988 bool Operation<T>::SourceInvariant() const
1989 {
1990 if (m_op_type == RANDOM_UNIFORM || m_op_type == RANDOM_PICK)
1991 return false;
1992 for (auto& operand : m_operands) {
1993 if (operand && !operand->SourceInvariant())
1994 return false;
1995 }
1996 return true;
1997 }
1998
1999 template <typename T>
SimpleIncrement()2000 bool Operation<T>::SimpleIncrement() const
2001 {
2002 if (m_op_type != PLUS && m_op_type != MINUS)
2003 return false;
2004 if (m_operands.size() < 2 || !m_operands[0] || !m_operands[1])
2005 return false;
2006 // RHS must be the same value for all targets
2007 if (!(m_operands[1]->TargetInvariant()))
2008 return false;
2009 // LHS must be just the immediate value of what's being incremented
2010 const auto lhs = dynamic_cast<const Variable<T>*>(m_operands[0].get());
2011 if (!lhs)
2012 return false;
2013 return lhs->GetReferenceType() == EFFECT_TARGET_VALUE_REFERENCE;
2014 }
2015
2016 template <typename T>
Description()2017 std::string Operation<T>::Description() const
2018 {
2019 if (m_op_type == NEGATE) {
2020 if (auto rhs = dynamic_cast<const Operation<T>*>(LHS())) {
2021 OpType op_type = rhs->GetOpType();
2022 if (op_type == PLUS || op_type == MINUS ||
2023 op_type == TIMES || op_type == DIVIDE ||
2024 op_type == NEGATE || op_type == EXPONENTIATE)
2025 return "-(" + LHS()->Description() + ")";
2026 } else {
2027 return "-" + LHS()->Description();
2028 }
2029 }
2030
2031 if (m_op_type == ABS)
2032 return "abs(" + LHS()->Description() + ")";
2033 if (m_op_type == LOGARITHM)
2034 return "log(" + LHS()->Description() + ")";
2035 if (m_op_type == SINE)
2036 return "sin(" + LHS()->Description() + ")";
2037 if (m_op_type == COSINE)
2038 return "cos(" + LHS()->Description() + ")";
2039
2040 if (m_op_type == MINIMUM) {
2041 std::string retval = "min(";
2042 for (auto it = m_operands.begin(); it != m_operands.end(); ++it) {
2043 if (it != m_operands.begin())
2044 retval += ", ";
2045 retval += (*it)->Description();
2046 }
2047 retval += ")";
2048 return retval;
2049 }
2050 if (m_op_type == MAXIMUM) {
2051 std::string retval = "max(";
2052 for (auto it = m_operands.begin(); it != m_operands.end(); ++it) {
2053 if (it != m_operands.begin())
2054 retval += ", ";
2055 retval += (*it)->Description();
2056 }
2057 retval += ")";
2058 return retval;
2059 }
2060
2061 if (m_op_type == RANDOM_UNIFORM)
2062 return "RandomNumber(" + LHS()->Description() + ", " + RHS()->Description() + ")";
2063
2064 if (m_op_type == RANDOM_PICK) {
2065 std::string retval = "OneOf(";
2066 for (auto it = m_operands.begin(); it != m_operands.end(); ++it) {
2067 if (it != m_operands.begin())
2068 retval += ", ";
2069 retval += (*it)->Description();
2070 }
2071 retval += ")";
2072 return retval;
2073 }
2074
2075 if (m_op_type == ROUND_NEAREST)
2076 return "round(" + LHS()->Description() + ")";
2077 if (m_op_type == ROUND_UP)
2078 return "ceil(" + LHS()->Description() + ")";
2079 if (m_op_type == ROUND_DOWN)
2080 return "floor(" + LHS()->Description() + ")";
2081
2082 bool parenthesize_lhs = false;
2083 bool parenthesize_rhs = false;
2084 if (auto lhs = dynamic_cast<const Operation<T>*>(LHS())) {
2085 OpType op_type = lhs->GetOpType();
2086 if (
2087 (m_op_type == EXPONENTIATE &&
2088 (op_type == EXPONENTIATE || op_type == TIMES || op_type == DIVIDE ||
2089 op_type == PLUS || op_type == MINUS || op_type == NEGATE)
2090 ) ||
2091 (((m_op_type == TIMES || m_op_type == DIVIDE) &&
2092 (op_type == PLUS || op_type == MINUS)) || op_type == NEGATE)
2093 )
2094 parenthesize_lhs = true;
2095 }
2096 if (auto rhs = dynamic_cast<const Operation<T>*>(RHS())) {
2097 OpType op_type = rhs->GetOpType();
2098 if (
2099 (m_op_type == EXPONENTIATE &&
2100 (op_type == EXPONENTIATE || op_type == TIMES || op_type == DIVIDE ||
2101 op_type == PLUS || op_type == MINUS || op_type == NEGATE)
2102 ) ||
2103 (((m_op_type == TIMES || m_op_type == DIVIDE) &&
2104 (op_type == PLUS || op_type == MINUS)) || op_type == NEGATE)
2105 )
2106 parenthesize_rhs = true;
2107 }
2108
2109 std::string retval;
2110 if (parenthesize_lhs)
2111 retval += '(' + LHS()->Description() + ')';
2112 else
2113 retval += LHS()->Description();
2114
2115 switch (m_op_type) {
2116 case PLUS: retval += " + "; break;
2117 case MINUS: retval += " - "; break;
2118 case TIMES: retval += " * "; break;
2119 case DIVIDE: retval += " / "; break;
2120 case EXPONENTIATE: retval += " ^ "; break;
2121 default: retval += " ? "; break;
2122 }
2123
2124 if (parenthesize_rhs)
2125 retval += '(' + RHS()->Description() + ')';
2126 else
2127 retval += RHS()->Description();
2128
2129 return retval;
2130 }
2131
2132 template <typename T>
Dump(unsigned short ntabs)2133 std::string Operation<T>::Dump(unsigned short ntabs) const
2134 {
2135 if (m_op_type == NEGATE) {
2136 if (auto rhs = dynamic_cast<const Operation<T>*>(LHS())) {
2137 OpType op_type = rhs->GetOpType();
2138 if (op_type == PLUS || op_type == MINUS ||
2139 op_type == TIMES || op_type == DIVIDE ||
2140 op_type == NEGATE || op_type == EXPONENTIATE)
2141 return "-(" + LHS()->Dump(ntabs) + ")";
2142 } else {
2143 return "-" + LHS()->Dump(ntabs);
2144 }
2145 }
2146
2147 if (m_op_type == ABS)
2148 return "abs(" + LHS()->Dump(ntabs) + ")";
2149 if (m_op_type == LOGARITHM)
2150 return "log(" + LHS()->Dump(ntabs) + ")";
2151 if (m_op_type == SINE)
2152 return "sin(" + LHS()->Dump(ntabs) + ")";
2153 if (m_op_type == COSINE)
2154 return "cos(" + LHS()->Dump(ntabs) + ")";
2155
2156 if (m_op_type == MINIMUM) {
2157 std::string retval = "min(";
2158 for (auto it = m_operands.begin(); it != m_operands.end(); ++it) {
2159 if (it != m_operands.begin())
2160 retval += ", ";
2161 retval += (*it)->Dump(ntabs);
2162 }
2163 retval += ")";
2164 return retval;
2165 }
2166 if (m_op_type == MAXIMUM) {
2167 std::string retval = "max(";
2168 for (auto it = m_operands.begin(); it != m_operands.end(); ++it) {
2169 if (it != m_operands.begin())
2170 retval += ", ";
2171 retval += (*it)->Dump(ntabs);
2172 }
2173 retval += ")";
2174 return retval;
2175 }
2176
2177 if (m_op_type == RANDOM_UNIFORM)
2178 return "random(" + LHS()->Dump(ntabs) + ", " + LHS()->Dump(ntabs) + ")";
2179
2180 if (m_op_type == RANDOM_PICK) {
2181 std::string retval = "randompick(";
2182 for (auto it = m_operands.begin(); it != m_operands.end(); ++it) {
2183 if (it != m_operands.begin())
2184 retval += ", ";
2185 retval += (*it)->Dump(ntabs);
2186 }
2187 retval += ")";
2188 return retval;
2189 }
2190
2191 if (m_op_type == ROUND_NEAREST)
2192 return "round(" + LHS()->Dump(ntabs) + ")";
2193 if (m_op_type == ROUND_UP)
2194 return "ceil(" + LHS()->Dump(ntabs) + ")";
2195 if (m_op_type == ROUND_DOWN)
2196 return "floor(" + LHS()->Dump(ntabs) + ")";
2197
2198 bool parenthesize_lhs = false;
2199 bool parenthesize_rhs = false;
2200 if (auto lhs = dynamic_cast<const Operation<T>*>(LHS())) {
2201 OpType op_type = lhs->GetOpType();
2202 if (
2203 (m_op_type == EXPONENTIATE &&
2204 (op_type == EXPONENTIATE || op_type == TIMES || op_type == DIVIDE ||
2205 op_type == PLUS || op_type == MINUS || op_type == NEGATE)
2206 ) ||
2207 (((m_op_type == TIMES || m_op_type == DIVIDE) &&
2208 (op_type == PLUS || op_type == MINUS)) || op_type == NEGATE)
2209 )
2210 parenthesize_lhs = true;
2211 }
2212 if (auto rhs = dynamic_cast<const Operation<T>*>(RHS())) {
2213 OpType op_type = rhs->GetOpType();
2214 if (
2215 (m_op_type == EXPONENTIATE &&
2216 (op_type == EXPONENTIATE || op_type == TIMES || op_type == DIVIDE ||
2217 op_type == PLUS || op_type == MINUS || op_type == NEGATE)
2218 ) ||
2219 (((m_op_type == TIMES || m_op_type == DIVIDE) &&
2220 (op_type == PLUS || op_type == MINUS)) || op_type == NEGATE)
2221 )
2222 parenthesize_rhs = true;
2223 }
2224
2225 std::string retval;
2226 if (parenthesize_lhs)
2227 retval += '(' + LHS()->Dump(ntabs) + ')';
2228 else
2229 retval += LHS()->Dump(ntabs);
2230
2231 switch (m_op_type) {
2232 case PLUS: retval += " + "; break;
2233 case MINUS: retval += " - "; break;
2234 case TIMES: retval += " * "; break;
2235 case DIVIDE: retval += " / "; break;
2236 case EXPONENTIATE: retval += " ^ "; break;
2237 default: retval += " ? "; break;
2238 }
2239
2240 if (parenthesize_rhs)
2241 retval += '(' + RHS()->Dump(ntabs) + ')';
2242 else
2243 retval += RHS()->Dump(ntabs);
2244
2245 return retval;
2246 }
2247
2248 template <typename T>
SetTopLevelContent(const std::string & content_name)2249 void Operation<T>::SetTopLevelContent(const std::string& content_name) {
2250 for (auto& operand : m_operands) {
2251 if (operand)
2252 operand->SetTopLevelContent(content_name);
2253 }
2254 }
2255
2256 template <typename T>
2257 template <typename Archive>
serialize(Archive & ar,const unsigned int version)2258 void Operation<T>::serialize(Archive& ar, const unsigned int version)
2259 {
2260 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(ValueRef)
2261 & BOOST_SERIALIZATION_NVP(m_op_type)
2262 & BOOST_SERIALIZATION_NVP(m_operands)
2263 & BOOST_SERIALIZATION_NVP(m_constant_expr)
2264 & BOOST_SERIALIZATION_NVP(m_cached_const_value);
2265 }
2266
2267 } // namespace ValueRef
2268
2269 #endif // _ValueRefs_h_
2270