openMSX
TclObject.hh
Go to the documentation of this file.
1 #ifndef TCLOBJECT_HH
2 #define TCLOBJECT_HH
3 
4 #include "string_ref.hh"
5 #include "openmsx.hh"
6 #include "xxhash.hh"
7 #include <tcl.h>
8 #include <iterator>
9 #include <cassert>
10 
11 struct Tcl_Obj;
12 
13 namespace openmsx {
14 
15 class Interpreter;
16 
17 class TclObject
18 {
19  // For STL interface, see below
20  struct iterator {
21  iterator(const TclObject& obj_, unsigned i_)
22  : obj(&obj_), i(i_) {}
23 
24  bool operator==(const iterator& other) const {
25  assert(obj == other.obj);
26  return i == other.i;
27  }
28  bool operator!=(const iterator& other) const {
29  return !(*this == other);
30  }
31 
32  string_ref operator*() const {
33  return obj->getListIndexUnchecked(i).getString();
34  }
35 
36  iterator& operator++() {
37  ++i;
38  return *this;
39  }
40  iterator operator++(int) {
41  iterator result = *this;
42  ++result;
43  return result;
44  }
45  iterator& operator--() {
46  --i;
47  return *this;
48  }
49  iterator operator--(int) {
50  iterator result = *this;
51  --result;
52  return result;
53  }
54  private:
55  const TclObject* obj;
56  unsigned i;
57  };
58 
59 public:
60  TclObject() { init(Tcl_NewObj()); }
61  explicit TclObject(Tcl_Obj* o) { init(o); }
62  explicit TclObject(string_ref v) { init(Tcl_NewStringObj(v.data(), int(v.size()))); }
63  explicit TclObject(int v) { init(Tcl_NewIntObj(v)); }
64  explicit TclObject(double v) { init(Tcl_NewDoubleObj(v)); }
65  TclObject(const TclObject& o) { init(o.obj); }
66  TclObject( TclObject&& o) noexcept { init(o.obj); }
67  ~TclObject() { Tcl_DecrRefCount(obj); }
68 
69  // assignment operator so we can use vector<TclObject>
70  TclObject& operator=(const TclObject& other) {
71  if (&other != this) {
72  Tcl_DecrRefCount(obj);
73  init(other.obj);
74  }
75  return *this;
76  }
77  TclObject& operator=(TclObject&& other) noexcept {
78  std::swap(obj, other.obj);
79  return *this;
80  }
81 
82  // get underlying Tcl_Obj
83  Tcl_Obj* getTclObject() { return obj; }
84  Tcl_Obj* getTclObjectNonConst() const { return const_cast<Tcl_Obj*>(obj); }
85 
86  // value setters
87  void setString(string_ref value);
88  void setInt(int value);
89  void setBoolean(bool value);
90  void setDouble(double value);
91  void setBinary(byte* buf, unsigned length);
92  void addListElement(string_ref element);
93  void addListElement(int value);
94  void addListElement(double value);
95  void addListElement(const TclObject& element);
96  template <typename ITER> void addListElements(ITER begin, ITER end);
97  template <typename CONT> void addListElements(const CONT& container);
98 
99  // value getters
100  string_ref getString() const;
101  int getInt (Interpreter& interp) const;
102  bool getBoolean (Interpreter& interp) const;
103  double getDouble(Interpreter& interp) const;
104  const byte* getBinary(unsigned& length) const;
105  unsigned getListLength(Interpreter& interp) const;
106  TclObject getListIndex(Interpreter& interp, unsigned index) const;
107  TclObject getDictValue(Interpreter& interp, const TclObject& key) const;
108 
109  // STL-like interface when interpreting this TclObject as a list of
110  // strings. Invalid Tcl lists are silently interpreted as empty lists.
111  unsigned size() const { return getListLengthUnchecked(); }
112  bool empty() const { return size() == 0; }
113  iterator begin() const { return iterator(*this, 0); }
114  iterator end() const { return iterator(*this, size()); }
115 
116  // expressions
117  bool evalBool(Interpreter& interp) const;
118 
126  TclObject executeCommand(Interpreter& interp, bool compile = false);
127 
128  friend bool operator==(const TclObject& x, const TclObject& y) {
129  return x.getString() == y.getString();
130  }
131  friend bool operator==(const TclObject& x, string_ref y) {
132  return x.getString() == y;
133  }
134  friend bool operator==(string_ref x, const TclObject& y) {
135  return x == y.getString();
136  }
137 
138  friend bool operator!=(const TclObject& x, const TclObject& y) { return !(x == y); }
139  friend bool operator!=(const TclObject& x, string_ref y) { return !(x == y); }
140  friend bool operator!=(string_ref x, const TclObject& y) { return !(x == y); }
141 
142 private:
143  void init(Tcl_Obj* obj_) noexcept {
144  obj = obj_;
145  Tcl_IncrRefCount(obj);
146  }
147 
148  void addListElement(Tcl_Obj* element);
149  unsigned getListLengthUnchecked() const;
150  TclObject getListIndexUnchecked(unsigned index) const;
151 
152  Tcl_Obj* obj;
153 };
154 
155 template <typename ITER>
156 void TclObject::addListElements(ITER first, ITER last)
157 {
158  for (ITER it = first; it != last; ++it) {
159  addListElement(*it);
160  }
161 }
162 
163 template <typename CONT>
164 void TclObject::addListElements(const CONT& container)
165 {
166  addListElements(std::begin(container), std::end(container));
167 }
168 
169 // We want to be able to reinterpret_cast a Tcl_Obj* as a TclObject.
170 static_assert(sizeof(TclObject) == sizeof(Tcl_Obj*), "");
171 
172 
173 struct XXTclHasher {
174  uint32_t operator()(string_ref str) const {
175  return xxhash(str);
176  }
177  uint32_t operator()(const TclObject& obj) const {
178  return xxhash(obj.getString());
179  }
180 };
181 
182 } // namespace openmsx
183 
184 #endif
void setBinary(byte *buf, unsigned length)
Definition: TclObject.cc:58
void setDouble(double value)
Definition: TclObject.cc:47
TclObject(string_ref v)
Definition: TclObject.hh:62
T length(const vecN< N, T > &x)
Definition: gl_vec.hh:333
TclObject & operator=(const TclObject &other)
Definition: TclObject.hh:70
TclObject(Tcl_Obj *o)
Definition: TclObject.hh:61
string_ref::const_iterator end(const string_ref &x)
Definition: string_ref.hh:167
iterator begin() const
Definition: TclObject.hh:113
const byte * getBinary(unsigned &length) const
Definition: TclObject.cc:146
friend bool operator==(const TclObject &x, const TclObject &y)
Definition: TclObject.hh:128
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
TclObject(double v)
Definition: TclObject.hh:64
unsigned getListLength(Interpreter &interp) const
Definition: TclObject.cc:152
This class implements a subset of the proposal for std::string_ref (proposed for the next c++ standar...
Definition: string_ref.hh:18
void setBoolean(bool value)
Definition: TclObject.cc:36
bool evalBool(Interpreter &interp) const
Definition: TclObject.cc:198
bool empty() const
Definition: TclObject.hh:112
Tcl_Obj * getTclObject()
Definition: TclObject.hh:83
friend bool operator!=(const TclObject &x, string_ref y)
Definition: TclObject.hh:139
friend bool operator!=(const TclObject &x, const TclObject &y)
Definition: TclObject.hh:138
friend bool operator==(string_ref x, const TclObject &y)
Definition: TclObject.hh:134
Tcl_Obj * getTclObjectNonConst() const
Definition: TclObject.hh:84
uint32_t operator()(const TclObject &obj) const
Definition: TclObject.hh:177
const char * data() const
Definition: string_ref.hh:68
unsigned size() const
Definition: TclObject.hh:111
uint32_t operator()(string_ref str) const
Definition: TclObject.hh:174
uint128 operator*(const uint128 &a, const uint128 &b)
Definition: uint128.hh:164
friend bool operator==(const TclObject &x, string_ref y)
Definition: TclObject.hh:131
iterator end() const
Definition: TclObject.hh:114
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
TclObject getListIndex(Interpreter &interp, unsigned index) const
Definition: TclObject.cc:170
TclObject getDictValue(Interpreter &interp, const TclObject &key) const
Definition: TclObject.cc:188
string_ref getString() const
Definition: TclObject.cc:139
friend bool operator!=(string_ref x, const TclObject &y)
Definition: TclObject.hh:140
TclObject & operator=(TclObject &&other) noexcept
Definition: TclObject.hh:77
bool getBoolean(Interpreter &interp) const
Definition: TclObject.cc:119
TclObject(const TclObject &o)
Definition: TclObject.hh:65
uint32_t xxhash(string_ref key)
Definition: xxhash.hh:143
double getDouble(Interpreter &interp) const
Definition: TclObject.cc:129
void addListElement(string_ref element)
Definition: TclObject.cc:69
int getInt(Interpreter &interp) const
Definition: TclObject.cc:109
void setString(string_ref value)
Definition: TclObject.cc:14
size_type size() const
Definition: string_ref.hh:55
void setInt(int value)
Definition: TclObject.cc:25
string_ref::const_iterator begin(const string_ref &x)
Definition: string_ref.hh:166
TclObject(TclObject &&o) noexcept
Definition: TclObject.hh:66
TclObject executeCommand(Interpreter &interp, bool compile=false)
Interpret this TclObject as a command and execute it.
Definition: TclObject.cc:208
void addListElements(ITER begin, ITER end)
Definition: TclObject.hh:156