The Battle for Wesnoth  1.19.0-dev
persist_context.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2024
3  by Jody Northup
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #pragma once
17 
18 #include "config.hpp"
19 #include "log.hpp"
20 static lg::log_domain log_persist("engine/persistence");
21 
22 #define LOG_PERSIST LOG_STREAM(info, log_persist)
23 #define ERR_PERSist LOG_STREAM(err, log_persist)
24 config pack_scalar(const std::string &,const t_string &);
26 public:
27 
28  virtual ~persist_context() {}
29 
30  struct name_space {
31  std::string namespace_;
32  std::string root_;
33  std::string node_;
34  std::string lineage_;
35  std::string descendants_;
36  bool valid_;
37 
38  bool valid() const {
39  return valid_;
40  }
41  void parse() {
42  while (namespace_.find_first_of("^") < namespace_.size()) {
43  if (namespace_[0] == '^') {
44  //TODO: Throw a WML error
45  namespace_ = "";
46  break;
47  }
48  std::string infix = namespace_.substr(namespace_.find_first_of("^"));
49  std::size_t end = infix.find_first_not_of("^");
50  if (!((end >= infix.length()) || (infix[end] == '.'))) {
51  //TODO: Throw a WML error
52  namespace_ = "";
53  break;
54  }
55  infix = infix.substr(0,end);
56  std::string suffix = namespace_.substr(namespace_.find_first_of("^") + infix.length());
57  while (!infix.empty())
58  {
59  std::string body = namespace_.substr(0,namespace_.find_first_of("^"));
60  body = body.substr(0,body.find_last_of("."));
61  infix = infix.substr(1);
62  namespace_ = body + infix + suffix;
63  }
64  }
65  }
66  name_space next() const {
67  return name_space(descendants_);
68  }
69  name_space prev() const {
70  return name_space(lineage_);
71  }
72  operator bool () const { return valid_; }
74  : namespace_()
75  , root_()
76  , node_()
77  , lineage_()
78  , descendants_()
79  , valid_(false)
80  {
81  }
82 
83  name_space(const std::string &ns, bool doParse = false)
84  : namespace_(ns)
85  , root_()
86  , node_()
87  , lineage_()
88  , descendants_()
89  , valid_(false)
90  {
91  if (doParse)
92  parse();
93  valid_ = ((namespace_.find_first_not_of("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_.") > namespace_.length()) && !namespace_.empty());
94  root_ = namespace_.substr(0,namespace_.find_first_of("."));
95  node_ = namespace_.substr(namespace_.find_last_of(".") + 1);
96  if (namespace_.find_last_of(".") <= namespace_.length())
97  lineage_ = namespace_.substr(0,namespace_.find_last_of("."));
98  if (namespace_.find_first_of(".") <= namespace_.length())
99  descendants_ = namespace_.substr(namespace_.find_first_of(".") + 1);
100  }
101  };
102 protected:
105  bool valid_;
107 
109  : cfg_()
110  , namespace_()
111  , valid_(false)
112  , in_transaction_(false)
113  {}
114 
115  persist_context(const std::string &name_space)
116  : cfg_()
117  , namespace_(name_space,true)
118  , valid_(namespace_.valid())
119  , in_transaction_(false)
120  {}
121 
122  config *get_node(config &cfg, name_space &ns, bool force = false) {
123  name_space next = ns.next();
124  if (next) {
125  if (force)
126  return get_node(cfg.child_or_add(next.root_), next, true);
127  else if (cfg.has_child(next.root_))
128  return get_node(cfg.mandatory_child(next.root_), next);
129  else
130  return nullptr;
131  }
132  else
133  return &cfg;
134  }
135 
136  const config *get_node(const config &cfg, const name_space &ns) const {
137  name_space next = ns.next();
138  if (next) {
139  if (cfg.has_child(next.root_))
140  return get_node(cfg.mandatory_child(next.root_), next);
141  else
142  return nullptr;
143  }
144  else
145  return &cfg;
146  }
147 
148 public:
149  virtual bool clear_var(const std::string &, bool immediate = false) = 0;
150  virtual config get_var(const std::string &) const = 0;
151  virtual bool set_var(const std::string &, const config &, bool immediate = false) = 0;
152  virtual bool start_transaction () = 0;
153  virtual bool end_transaction () = 0;
154  virtual bool cancel_transaction () = 0;
155  std::string get_node() const;
156  void set_node(const std::string &);
157  bool valid() const { return valid_; }
158  bool dirty() const {
159  return true;
160  }
161  operator bool() const { return valid_; }
162 };
163 
165 private:
166  void load();
167  void init();
168  bool save_context();
169 
170 public:
171  persist_file_context(const std::string &name_space);
172  bool clear_var(const std::string &, bool immediate = false);
173  config get_var(const std::string &) const;
174  bool set_var(const std::string &, const config &, bool immediate = false);
175 
177  if (in_transaction_)
178  return false;
179  in_transaction_ = true;
180  return true;
181  }
182  bool end_transaction () {
183  if (!in_transaction_)
184  return false;
185  in_transaction_ = false;
186  save_context();
187  return true;
188  }
190  if (!in_transaction_)
191  return false;
192  load();
193  in_transaction_ = false;
194  return true;
195  }
196 };
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
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:317
config & child_or_add(config_key_type key)
Returns a reference to the first child with the given key.
Definition: config.cpp:406
virtual config get_var(const std::string &) const =0
const config * get_node(const config &cfg, const name_space &ns) const
persist_context(const std::string &name_space)
virtual bool end_transaction()=0
std::string get_node() const
config * get_node(config &cfg, name_space &ns, bool force=false)
bool valid() const
virtual bool set_var(const std::string &, const config &, bool immediate=false)=0
bool dirty() const
virtual ~persist_context()
virtual bool start_transaction()=0
void set_node(const std::string &)
virtual bool cancel_transaction()=0
virtual bool clear_var(const std::string &, bool immediate=false)=0
config get_var(const std::string &) const
bool set_var(const std::string &, const config &, bool immediate=false)
persist_file_context(const std::string &name_space)
bool clear_var(const std::string &, bool immediate=false)
Standard logging facilities (interface).
static lg::log_domain log_persist("engine/persistence")
config pack_scalar(const std::string &, const t_string &)
name_space(const std::string &ns, bool doParse=false)