Skip to content

Commit 1cec573

Browse files
committed
libtclcpp: Added TclDynList
Signed-off-by: Krzysztof Boronski <[email protected]>
1 parent 4738670 commit 1cec573

File tree

2 files changed

+154
-6
lines changed

2 files changed

+154
-6
lines changed

libs/libtclcpp/src/tclcpp.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,33 @@ int TclCtx::_tcl_do_method(
127127
}
128128
return TCL_OK;
129129
}
130+
131+
TclDynList::TclDynList(Tcl_Interp* interp, Tcl_Obj* obj)
132+
: _interp(interp) {
133+
const Tcl_ObjType* obj_type = obj->typePtr;
134+
if (obj_type == nullptr)
135+
return;
136+
137+
if (obj_type == nullptr || std::strcmp(obj_type->name, "list")) {
138+
Tcl_Obj* item;
139+
this->_obj = Tcl_NewListObj(1, &obj);
140+
} else {
141+
this->_obj = obj;
142+
}
143+
}
144+
145+
TclDynList tcl_obj_getdynlist (TclClient* client, Tcl_Obj* obj) {
146+
return TclDynList(client->_interp, obj);
147+
}
148+
149+
Tcl_Obj* TclDynList::operator[](size_t idx) {
150+
int count;
151+
Tcl_Obj* objp;
152+
153+
Tcl_ListObjLength(this->_interp, this->_obj, &count);
154+
if (idx >= count)
155+
return nullptr;
156+
Tcl_ListObjIndex(this->_interp, this->_obj, idx, &objp);
157+
158+
return objp;
159+
}

libs/libtclcpp/src/tclcpp.h

Lines changed: 124 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,18 @@ class TclList {
194194
return this->_obj;
195195
}
196196

197+
Tcl_Obj* operator*(size_t idx) {
198+
int count;
199+
Tcl_Obj* objp;
200+
201+
Tcl_ListObjLength(this->_interp, this->_obj, &count);
202+
if (idx >= count)
203+
return nullptr;
204+
Tcl_ListObjIndex(this->_interp, this->_obj, idx, &objp);
205+
206+
return tcl_obj_getptr<T>(objp);
207+
}
208+
197209
/**
198210
* @brief Iterator
199211
* Dereferencing it yields a pointer to a C++ object
@@ -203,11 +215,10 @@ class TclList {
203215
* return `TclList<T>` for `TclList<TclList<T>>::Iterator::operaotr*()`.
204216
* Primitive TCL types might also need a specialized handling.
205217
*/
206-
template<class dummy>
207218
class Iterator {
208219
public:
209220
Iterator& operator=(const Iterator& other) {
210-
this->_idx = other->_idx;
221+
this->_idx = other._idx;
211222
return *this;
212223
}
213224

@@ -237,14 +248,14 @@ class TclList {
237248
Tcl_Obj* _obj; /* Underlying Tcl_Obj representing the list */
238249
};
239250

240-
Iterator<void> begin() {
241-
return Iterator<void>(this->_interp, this->_obj, 0);
251+
Iterator begin() {
252+
return Iterator(this->_interp, this->_obj, 0);
242253
}
243254

244-
Iterator<void> end() {
255+
Iterator end() {
245256
int count;
246257
Tcl_ListObjLength(this->_interp, this->_obj, &count);
247-
return Iterator<void>(this->_interp, this->_obj, count);
258+
return Iterator(this->_interp, this->_obj, count);
248259
}
249260

250261
/**
@@ -261,7 +272,113 @@ class TclList {
261272
Tcl_Obj* _obj; /* Underlying Tcl_Obj representing the list */
262273
};
263274

275+
class TclDynList {
276+
public:
277+
/**
278+
* @brief Create empty TCL list
279+
*/
280+
inline TclDynList(Tcl_Interp* interp)
281+
: _interp(interp)
282+
, _obj(Tcl_NewListObj(0, nullptr)) {}
283+
284+
/**
285+
* @brief Import a TCL list from Tcl_Obj of list type, or create one-element list from
286+
* object of any other type.
287+
*/
288+
TclDynList(Tcl_Interp* interp, Tcl_Obj* obj);
289+
290+
/**
291+
* @brief Get the raw TCL_Obj representing the list.
292+
*/
293+
inline Tcl_Obj* tcl_obj() {
294+
return this->_obj;
295+
}
296+
297+
Tcl_Obj* operator[](size_t idx);
298+
299+
template <typename T>
300+
Tcl_Obj* at(size_t idx) {
301+
Tcl_Obj* obj = (*this)[idx];
302+
if (obj == nullptr)
303+
return nullptr;
304+
return tcl_obj_getptr<T>(obj);
305+
}
306+
307+
/**
308+
* @brief Iterator
309+
* Dereferencing it yields a pointer to a C++ object
310+
*
311+
* TODO: If we ever need to handle a TCL list of TCL lists this won't work. It might be possible to use
312+
* template spcializations to derive a class with alternative implementation of `operator*()` that would
313+
* return `TclList<T>` for `TclList<TclList<T>>::Iterator::operaotr*()`.
314+
* Primitive TCL types might also need a specialized handling.
315+
*/
316+
class Iterator {
317+
public:
318+
inline Iterator& operator=(const Iterator& other) {
319+
this->_idx = other._idx;
320+
return *this;
321+
}
322+
323+
inline Iterator& operator++() {
324+
this->_idx++;
325+
return *this;
326+
}
327+
328+
inline bool operator!=(const Iterator& other) {
329+
return (this->_interp != other._interp) || (this->_obj != other._obj) || (this->_idx != other._idx);
330+
}
331+
332+
inline Tcl_Obj* operator*() const {
333+
Tcl_Obj* objp;
334+
Tcl_ListObjIndex(this->_interp, this->_obj, this->_idx, &objp);
335+
return objp;
336+
}
337+
338+
template <typename T>
339+
inline T* at() const {
340+
return tcl_obj_getptr<T>(**this);
341+
}
342+
343+
inline Iterator(Tcl_Interp* interp, Tcl_Obj* obj, int idx)
344+
: _interp(interp)
345+
, _obj(obj)
346+
, _idx(idx) {}
347+
348+
protected:
349+
Tcl_Interp* _interp;
350+
int _idx; /* Currently visited index on the list */
351+
Tcl_Obj* _obj; /* Underlying Tcl_Obj representing the list */
352+
};
353+
354+
inline Iterator begin() {
355+
return Iterator(this->_interp, this->_obj, 0);
356+
}
357+
358+
inline Iterator end() {
359+
int count;
360+
Tcl_ListObjLength(this->_interp, this->_obj, &count);
361+
return Iterator(this->_interp, this->_obj, count);
362+
}
363+
364+
/**
365+
* @brief Get number of elements on the list.
366+
*/
367+
inline size_t size() const {
368+
int len;
369+
Tcl_ListObjLength(this->_interp, this->_obj, &len);
370+
return size_t(len);
371+
}
372+
373+
protected:
374+
Tcl_Interp* _interp;
375+
Tcl_Obj* _obj; /* Underlying Tcl_Obj representing the list */
376+
};
377+
264378
class TclCtx;
379+
class TclClient;
380+
381+
TclDynList tcl_obj_getdynlist(TclClient* client, Tcl_Obj* obj);
265382

266383
/**
267384
* @brief Provide a C++ state with TCL interface.
@@ -380,6 +497,7 @@ class TclClient {
380497
friend class TclCtx;
381498
template<typename T>
382499
friend TclList<T> tcl_obj_getlist(TclClient* client, Tcl_Obj* obj);
500+
friend TclDynList tcl_obj_getdynlist(TclClient* client, Tcl_Obj* obj);
383501

384502
Tcl_Interp* _interp;
385503
};

0 commit comments

Comments
 (0)