The Battle for Wesnoth  1.19.0-dev
variable_info_detail.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2005 - 2024
3  by Philippe Plantier <ayin@anathas.org>
4  Copyright (C) 2003 by David White <dave@whitevine.net>
5  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY.
13 
14  See the COPYING file for more details.
15 */
16 
17 #pragma once
18 
19 #include "config.hpp"
20 #include "utils/const_clone.hpp"
21 
22 #include <string>
23 #include <type_traits>
24 
26 {
27 /**
28  * The variable_info policy classes.
29  *
30  * Each of these classes describes a different behavior for reading data from a variable
31  * and should implement two functions:
32  *
33  * - get_child_at Describes the desired behavior when reading variable info.
34  * - error_message Error message regarding policy behavior.
35  */
36 
37 /** Takes a const reference and is guaranteed to not change the config. */
39 {
40 public:
41  static const config& get_child_at(const config& cfg, const std::string& key, int index)
42  {
43  assert(index >= 0);
44  // cfg.child_or_empty does not support index parameter
45  if(auto child = cfg.optional_child(key, index)) {
46  return *child;
47  }
48 
49  static const config empty_const_cfg;
50  return empty_const_cfg;
51  }
52 
53  static std::string error_message(const std::string& name)
54  {
55  return "Cannot resolve variable '" + name + "' for reading.";
56  }
57 };
58 
59 /** Creates a child table when resolving name if it doesn't exist yet. */
61 {
62 public:
63  static config& get_child_at(config& cfg, const std::string& key, int index)
64  {
65  assert(index >= 0);
66  // the 'create_if_not_existent' logic.
67  while(static_cast<int>(cfg.child_count(key)) <= index) {
68  cfg.add_child(key);
69  }
70 
71  return cfg.mandatory_child(key, index);
72  }
73 
74  static std::string error_message(const std::string& name)
75  {
76  return "Cannot resolve variable '" + name + "' for writing.";
77  }
78 };
79 
80 /**
81  * Will throw an exception when trying to access a nonexistent table.
82  * Note that the other types can throw too if name is invlid, such as '..[[[a'.
83  */
85 {
86 public:
87  static config& get_child_at(config& cfg, const std::string& key, int index)
88  {
89  assert(index >= 0);
90  if(auto child = cfg.optional_child(key, index)) {
91  return *child;
92  }
93 
95  }
96 
97  static std::string error_message(const std::string& name)
98  {
99  return "Cannot resolve variable '" + name + "' for writing without creating new children.";
100  }
101 };
102 
103 // ==================================================================
104 // Other implementation details.
105 // ==================================================================
106 
107 template<typename T, typename V>
108 struct maybe_const : public utils::const_clone<T, V>
109 {
110  // Meta type aliases provided by const_clone
111 };
112 
113 template<>
114 struct maybe_const<config::child_itors, const vi_policy_const>
115 {
117 };
118 
120  state_start = 0, /**< Represents the initial variable state before processing. */
121  state_named, /**< The result of .someval. This can either mean an attribute value or a child range. */
122  state_indexed, /**< The result of .someval[index]. This is never an attribute value and is always a single config. */
123  state_temporary, /**< The result of .length. This value can never be written, it can only be read. */
124 };
125 
126 template<typename V>
128 {
130 
132  : child_(&vars)
133  , key_()
134  , index_(0)
135  , temp_val_()
136  , type_(state_start)
137  {
138  child_ = &vars;
139  }
140 
141  // The meaning of the following 3 depends on 'type_', but the current config is usually
142  // child_->child_at(key_, index_).
144  std::string key_;
145  int index_;
146 
147  // If we have a temporary value like .length we store the result here.
149 
150  // See @ref variable_info_state_type
152 };
153 } // end namespace variable_info_implementation
154 
155 /** Helper template alias for maybe_const, defined at global scope for convenience. */
156 template<typename T, typename V>
Variant for storing WML attributes.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
config & mandatory_child(config_key_type key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
Definition: config.cpp:367
std::size_t child_count(config_key_type key) const
Definition: config.cpp:297
boost::iterator_range< const_child_iterator > const_child_itors
Definition: config.hpp:283
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Euivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition: config.cpp:385
config & add_child(config_key_type key)
Definition: config.cpp:441
static const config & get_child_at(const config &cfg, const std::string &key, int index)
static std::string error_message(const std::string &name)
Creates a child table when resolving name if it doesn't exist yet.
static std::string error_message(const std::string &name)
static config & get_child_at(config &cfg, const std::string &key, int index)
Will throw an exception when trying to access a nonexistent table.
static config & get_child_at(config &cfg, const std::string &key, int index)
static std::string error_message(const std::string &name)
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
@ state_named
The result of .someval.
@ state_start
Represents the initial variable state before processing.
@ state_indexed
The result of .someval[index].
@ state_temporary
The result of .length.
Helper struct to clone the constness of one type to another.
Definition: const_clone.hpp:38
std::conditional_t< is_source_const, const T, T > type
The destination type, possibly const qualified.
Definition: const_clone.hpp:48
typename maybe_const< config, V >::type child_t
typename variable_info_implementation::maybe_const< T, V >::type maybe_const_t
Helper template alias for maybe_const, defined at global scope for convenience.