• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Open-Sn / opensn / 18300593117

06 Oct 2025 10:47PM UTC coverage: 74.862% (-0.2%) from 75.031%
18300593117

push

github

web-flow
Merge pull request #759 from wdhawkins/performance

Sweep performance optimizations

294 of 302 new or added lines in 15 files covered. (97.35%)

334 existing lines in 80 files now uncovered.

17788 of 23761 relevant lines covered (74.86%)

61852783.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.48
/framework/parameters/parameter_block.h
1
// SPDX-FileCopyrightText: 2024 The OpenSn Authors <https://open-sn.github.io/opensn/>
2
// SPDX-License-Identifier: MIT
3

4
#pragma once
5

6
#include "framework/data_types/varying.h"
7
#include <memory>
8
#include <stdexcept>
9
#include <vector>
10
#include <string>
11
#include <map>
12

13
namespace opensn
14
{
15

16
enum class ParameterBlockType
17
{
18
  INVALID_VALUE = 0,
19
  BOOLEAN = 1,
20
  FLOAT = 3,
21
  STRING = 4,
22
  INTEGER = 5,
23
  USER_DATA = 6,
24
  ARRAY = 98,
25
  BLOCK = 99
26
};
27

28
std::string ParameterBlockTypeName(ParameterBlockType type);
29

30
class ParameterBlock;
31

32
/**
33
 * A ParameterBlock is a conceptually simple data structure that supports a hierarchy of primitive
34
 * parameters. There really are just 4 member variables on a ParameterBlock object, they are 1) the
35
 * type (as an enum), 2) the name of the block, 3) a pointer to a value (which can only be a
36
 * primitive type), and 4) a vector of child parameters.
37
 *
38
 * If a ParameterBlock has a primitive type, i.e., BOOLEAN, FLOAT, STRING, or INTEGER, then the
39
 * value_ptr will contain a pointer to the value of a primitive type. Otherwise, for types ARRAY and
40
 * BLOCK, the ParameterBlock will not have a value_ptr and instead the vector member will contain
41
 * sub-parameters.
42
 */
43
class ParameterBlock
44
{
45
private:
46
  ParameterBlockType type_ = ParameterBlockType::BLOCK;
47
  std::string name_;
48
  std::shared_ptr<Varying> value_ptr_ = nullptr;
49
  std::vector<ParameterBlock> parameters_;
50
  std::string error_origin_scope_ = "Unknown Scope";
51

52
public:
53
  /// Sets the name of the block.
54
  void SetBlockName(const std::string& name);
55

56
  // Helpers
57
  template <typename T>
58
  struct IsBool
59
  {
60
    static constexpr bool value = std::is_same_v<T, bool>;
61
  };
62
  template <typename T>
63
  struct IsFloat
64
  {
65
    static constexpr bool value = std::is_floating_point_v<T>;
66
  };
67
  template <typename T>
68
  struct IsString
69
  {
70
    static constexpr bool value = std::is_same_v<T, std::string> or std::is_same_v<T, const char*>;
71
  };
72
  template <typename T>
73
  struct IsInteger
74
  {
75
    static constexpr bool value = std::is_integral_v<T> and not std::is_same_v<T, bool>;
76
  };
77
  template <typename T>
78
  struct IsUserData
79
  {
80
    static constexpr bool value = (std::is_pointer_v<T> or is_shared_ptr_v<T> or
81
                                   (std::is_class_v<T> and not std::is_same_v<T, std::string>)) and
82
                                  (not std::is_same_v<T, const char*>);
83
  };
84

85
  // Constructors
86
  /// Constructs an empty parameter block with the given name and type BLOCK.
87
  explicit ParameterBlock(const std::string& name = "");
88

89
  /// Derived type constructor
90
  template <typename T>
91
  ParameterBlock(const std::string& name, const std::vector<T>& array)
2,989✔
92
    : type_(ParameterBlockType::ARRAY), name_(name)
5,978✔
93
  {
94
    size_t k = 0;
2,989✔
95
    for (const T& value : array)
3,109✔
96
      AddParameter(std::to_string(k++), value);
120✔
97
  }
2,989✔
98

99
  /// Constructs one of the fundamental types.
100
  template <typename T>
101
  explicit ParameterBlock(const std::string& name, T value) : name_(name)
200,612✔
102
  {
103
    constexpr bool is_supported = IsBool<T>::value or IsFloat<T>::value or IsString<T>::value or
100,306✔
104
                                  IsInteger<T>::value or IsUserData<T>::value;
105

106
    static_assert(is_supported, "Value type not supported for parameter block");
107

108
    if (IsBool<T>::value)
109
      type_ = ParameterBlockType::BOOLEAN;
110
    if (IsFloat<T>::value)
111
      type_ = ParameterBlockType::FLOAT;
67,682✔
112
    if (IsString<T>::value)
113
      type_ = ParameterBlockType::STRING;
114
    if (IsInteger<T>::value)
115
      type_ = ParameterBlockType::INTEGER;
116
    if (IsUserData<T>::value)
117
      type_ = ParameterBlockType::USER_DATA;
118

119
    value_ptr_ = std::make_shared<Varying>(value);
100,306✔
120
  }
100,306✔
121

7,773✔
122
  /// Copy constructor
123
  ParameterBlock(const ParameterBlock& other);
124

125
  /// Copy assignment operator
126
  ParameterBlock& operator=(const ParameterBlock& other);
127

128
  /// Move constructor
129
  ParameterBlock(ParameterBlock&& other) noexcept = default;
130

131
  /// Move assignment operator
132
  ParameterBlock& operator=(ParameterBlock&& other) noexcept;
133

134
  // Accessors
135
  ParameterBlockType GetType() const;
136

137
  /**
138
   * Returns true if the parameter block comprises a single value of any of the types BOOLEAN,
139
   * FLOAT, STRING, INTEGER.
140
   */
141
  bool IsScalar() const;
142

143
  /// Returns a string version of the type.
144
  std::string GetTypeName() const;
145
  std::string GetName() const;
146
  const Varying& GetValue() const;
147

148
  /// Returns the number of parameters in a block. This is normally only useful for the ARRAY type.
149
  size_t GetNumParameters() const;
150

151
  /// Returns the sub-parameters of this block.
152
  const std::vector<ParameterBlock>& GetParameters() const;
153

154
  /**
155
   * Returns whether or not the block has a value. If this block has sub-parameters it should not
156
   * have a value. This is a good way to check if the block is actually a single value because some
157
   * Parameter blocks can be passed as empty.
158
   */
159
  bool HasValue() const;
160

161
  // Mutators
162

163
  /// Changes the block type to array, making it accessible via integer keys.
164
  void ChangeToArray();
165

166
  /// Sets a string to be displayed alongside exceptions that give some notion of the origin of the
167
  /// error.
168
  void SetErrorOriginScope(const std::string& scope);
169

170
  /// Gets a string that allows error messages to print the scope of an error.
171
  std::string GetErrorOriginScope() const { return error_origin_scope_; }
172

173
  // Requirements
174

175
  /**
176
   * Checks that the block is of the given type. If it is not it will throw an exception
177
   * `std::logic_error`.
178
   */
179
  void RequireBlockTypeIs(ParameterBlockType type) const;
180
  void RequireParameterBlockTypeIs(const std::string& param_name, ParameterBlockType type) const
181
  {
182
    GetParam(param_name).RequireBlockTypeIs(type);
183
  }
184

185
  /// Check that the parameter with the given name exists otherwise throws a `std::logic_error`.
186
  void RequireParameter(const std::string& param_name) const;
187

188
  // utilities
189

190
  /// Adds a parameter to the sub-parameter list.
191
  void AddParameter(ParameterBlock block);
192

193
  /// Makes a ParameterBlock and adds it to the sub-parameters list.
194
  template <typename T>
195
  void AddParameter(const std::string& name, const T& value)
32,161✔
196
  {
197
    AddParameter(ParameterBlock(name, value));
32,161✔
198
  }
32,161✔
199

200
  /// Sorts the sub-parameter list according to name. This is useful for regression testing.
201
  void SortParameters();
202

203
  /// Returns true if a parameter with the specified name is in the list of sub-parameters.
204
  /// Otherwise, false.
205
  bool Has(const std::string& param_name) const;
206

207
  /// Gets a parameter by name.
208
  ParameterBlock& GetParam(const std::string& param_name);
209

210
  /// Gets a parameter by index.
211
  ParameterBlock& GetParam(size_t index);
212

213
  /// Gets a parameter by name.
214
  const ParameterBlock& GetParam(const std::string& param_name) const;
215

216
  /// Gets a parameter by index.
217
  const ParameterBlock& GetParam(size_t index) const;
218

219
  /// Returns the value of the parameter.
220
  template <typename T>
221
  T GetValue() const
85,284✔
222
  {
223
    if (value_ptr_ == nullptr)
85,284✔
224
      throw std::logic_error(error_origin_scope_ + std::string(__PRETTY_FUNCTION__) +
×
225
                             ": Value not available for block type " +
×
226
                             ParameterBlockTypeName(GetType()));
×
227
    try
228
    {
229
      return GetValue().GetValue<T>();
85,284✔
230
    }
231
    catch (const std::exception& exc)
×
232
    {
233
      throw std::logic_error(error_origin_scope_ + ":" + GetName() + " " + exc.what());
×
234
    }
235
  }
236

237
  /// Fetches the parameter with the given name and returns it value.
238
  template <typename T>
239
  T GetParamValue(const std::string& param_name) const
19,224✔
240
  {
241
    try
242
    {
243
      const auto& param = GetParam(param_name);
19,224✔
244
      return param.GetValue<T>();
26,677✔
245
    }
246
    catch (const std::out_of_range& oor)
×
247
    {
248
      throw std::out_of_range(error_origin_scope_ + std::string(__PRETTY_FUNCTION__) +
×
249
                              ": Parameter \"" + param_name + "\" not present in block");
×
250
    }
251
  }
252

253
  /**
254
   * Fetches the parameter of type std::shared_ptr<T> with the given name and returns its value.
255
   *
256
   * Will perform checking on whether or not the pointed-to-object is null (if \p check = true)
257
   *
258
   * The optional second template argument can be used to attempt to cast the object
259
   * to the derived type and will throw an exception if the cast fails.
260
   */
261
  template <typename T, typename Derived = T>
262
  std::shared_ptr<Derived> GetSharedPtrParam(const std::string& param_name,
263
                                             const bool check = true) const
264
  {
265
    static_assert(std::is_base_of_v<T, Derived>, "T is not a base of derived");
266

267
    auto value = this->GetParamValue<std::shared_ptr<T>>(param_name);
268
    if (!value)
269
    {
270
      if (check)
271
        throw std::logic_error(error_origin_scope_ + std::string(__PRETTY_FUNCTION__) +
272
                               ": shared_ptr param is null");
273
      return nullptr;
274
    }
275
    if constexpr (!std::is_same_v<T, Derived>)
276
    {
277
      if (auto derived_value = std::dynamic_pointer_cast<Derived>(value))
278
        return derived_value;
279

280
      throw std::logic_error(error_origin_scope_ + std::string(__PRETTY_FUNCTION__) +
281
                             ": Supplied object is not derived from " + typeid(T).name());
282
    }
283
    else
284
    {
285
      return value;
286
    }
287
  }
288

289
  /**
290
   * Converts the parameters of an array-type parameter block to a vector of primitive types and
291
   * returns it.
292
   */
293
  template <typename T>
294
  std::vector<T> GetVectorValue() const
3,182✔
295
  {
296
    if (GetType() != ParameterBlockType::ARRAY)
3,182✔
297
      throw std::logic_error(error_origin_scope_ + std::string(__PRETTY_FUNCTION__) +
×
298
                             ": Invalid type requested for parameter of type " +
×
299
                             ParameterBlockTypeName(GetType()));
×
300

301
    std::vector<T> vec;
3,182✔
302
    if (parameters_.empty())
3,182✔
303
      return vec;
826✔
304

305
    // Check the first sub-param is of the right type
306
    const auto& front_param = parameters_.front();
2,356✔
307

308
    // Check that all other parameters are of the required type
309
    for (const auto& param : parameters_)
64,102✔
310
      if (param.GetType() != front_param.GetType())
61,746✔
311
        throw std::logic_error(error_origin_scope_ + " " + std::string(__PRETTY_FUNCTION__) +
×
312
                               ": Parameter \"" + name_ +
×
313
                               "\", cannot construct vector from block because "
314
                               "the sub_parameters do not all have the correct type. param->" +
×
315
                               ParameterBlockTypeName(param.GetType()) + " vs param0->" +
×
316
                               ParameterBlockTypeName(front_param.GetType()));
×
317

318
    const size_t num_params = parameters_.size();
2,356✔
319
    for (size_t k = 0; k < num_params; ++k)
64,102✔
320
    {
321
      const auto& param = GetParam(k);
61,746✔
322
      vec.push_back(param.GetValue<T>());
61,746✔
323
    }
324

325
    return vec;
2,356✔
326
  }
×
327

328
  /// Gets a vector of primitive types from an array-type parameter block specified as a parameter
329
  /// of the current block.
330
  template <typename T>
331
  std::vector<T> GetParamVectorValue(const std::string& param_name) const
2,118✔
332
  {
333
    const auto& param = GetParam(param_name);
2,118✔
334
    return param.GetVectorValue<T>();
2,118✔
335
  }
11,049✔
336

2,312✔
337
  // Iterator
2,312✔
338
  class Iterator
2,312✔
339
  {
629✔
340
  public:
×
341
    ParameterBlock& ref_block;
629✔
342
    size_t ref_id;
1,350✔
343

2,312✔
344
    Iterator(ParameterBlock& block, size_t i) : ref_block(block), ref_id(i) {}
4,777✔
345

9,025✔
346
    Iterator operator++()
347
    {
348
      Iterator i = *this;
349
      ref_id++;
350
      return i;
351
    }
352
    Iterator operator++(int)
353
    {
354
      ref_id++;
355
      return *this;
356
    }
357

358
    ParameterBlock& operator*() { return ref_block.parameters_[ref_id]; }
359
    bool operator==(const Iterator& rhs) const { return ref_id == rhs.ref_id; }
360
    bool operator!=(const Iterator& rhs) const { return ref_id != rhs.ref_id; }
361
  };
362

363
  class ConstIterator
364
  {
365
  public:
366
    const ParameterBlock& ref_block;
367
    size_t ref_id;
368

369
    ConstIterator(const ParameterBlock& block, size_t i) : ref_block(block), ref_id(i) {}
1,782✔
370

371
    ConstIterator operator++()
1,016✔
372
    {
373
      ConstIterator i = *this;
1,016✔
374
      ref_id++;
1,016✔
375
      return i;
1,016✔
376
    }
377
    ConstIterator operator++(int)
378
    {
379
      ref_id++;
380
      return *this;
381
    }
382

383
    const ParameterBlock& operator*() { return ref_block.parameters_[ref_id]; }
1,016✔
384
    bool operator==(const ConstIterator& rhs) const { return ref_id == rhs.ref_id; }
385
    bool operator!=(const ConstIterator& rhs) const { return ref_id != rhs.ref_id; }
1,907✔
386
  };
387

388
  Iterator begin() { return {*this, 0}; }
389
  Iterator end() { return {*this, parameters_.size()}; }
390

391
  ConstIterator begin() const { return {*this, 0}; }
891✔
392
  ConstIterator end() const { return {*this, parameters_.size()}; }
891✔
393

4✔
394
  /**
×
395
   * Given a reference to a string, recursively travels the parameter tree and print values into
×
396
   * the reference string.
×
397
   */
×
398
  void RecursiveDumpToString(std::string& outstr, const std::string& offset = "") const;
×
399

×
400
  /// Print the block tree structure into a designated string.
×
401
  void RecursiveDumpToJSON(std::string& outstr) const;
×
UNCOV
402
};
×
403

12,201,616✔
404
} // namespace opensn
666✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc