#include <TCLObject.h> ... class CTCLObject : public CTCLInterpreterObject { public: CTCLObject (); CTCLObject (Tcl_Obj* am_pObject); CTCLObject (const CTCLObject& aCTCLObject ); virtual ~CTCLObject ( ); CTCLObject& operator= (const CTCLObject& aCTCLObject); int operator== (const CTCLObject& aCTCLObject) const; Tcl_Obj* getObject(); const Tcl_Obj* getObject() const; CTCLObject& operator= (const std::string& rSource) ; CTCLObject& operator= (const char* pSource) ; CTCLObject& operator= (int nSource) ; CTCLObject& operator= (const CTCLList& rList) ; CTCLObject& operator= (double dSource) ; CTCLObject& operator=(Tcl_Obj* rhs); operator std::string () ; operator int () ; operator CTCLList () ; operator double () ; CTCLObject& operator+= (const CTCLObject& rObject) ; CTCLObject& operator+= (int nItem) ; CTCLObject& operator+= (const std::string& rItem) ; CTCLObject& operator+= (const char* pItem) ; CTCLObject& operator+= (double Item) ; CTCLObject clone () ; CTCLObject operator() () ; CTCLObject getRange(int first, int last); CTCLObject& concat(CTCLObject& rhs); // Concat lists. std::vector<CTCLObject> getListElements(); CTCLObject& setList(std::vector<CTCLObject> elements); int llength(); CTCLObject lindex(int index); CTCLObject& lreplace(int first, int count, std::vector<CTCLObject> newElements); };
Tcl as a scripting language carries a deeply embedded philosophy that everything can be treated as a string. Nonetheless, in many cases, entities manipulated by the interpreter are more efficiently manipulated when they have other types of internal representations. For example strings which represent floating point numbers in extended computations are more efficiently represented directly as float or double variables.
Tcl uses dual ported objects to capture this efficiently. A Tcl object is a thing that has a string representation and at most one other typed representation (e.g. list, integer, floating point). Conversions from string to this representation are done once and cached as long as possible, so that when an object has been used as a particular type there is essentially no additional conversion cost to use it as that type again.
While a Tcl_Obj and therefore a CTCLObject
can exist independent of an interpreter, many member functions require the
object be bound to an interpreter, or they will fail with an assertion failure
causing the program to abort. Use the base class Bind
(CTCLInterpreterObject
::Bind
)
member to bind the object to an existing interpreter, usually as soon as
possible.
Tcl objects also can be shared with a lazy copy on write scheme so that overhead associated with duplicating objects (e.g. when using them as parameters to Tcl commands) is minimized.
CTCLObject
exposes an object oriented interface to the
Tcl dual ported object.
CTCLObject
();CTCLObject
(Tcl_Obj*pObject
);CTCLObject
(const CTCLObject&rhs
);
Constructs a Tcl object wrapped in a CTCLObject
.
pObject
is an existing Tcl_Obj pointer that will be wrapped.
rhs
is an existing CTCLObject
that will be used to create another reference to the same underlying
object. Note that in the last two of these forms, a new Tcl_Obj
is not created. Instead, Tcl_IncrRefCount
is used
on the previously existing object to mark it as shared.
All member functions which modify the underlying object will create a new
object (copy on write semantics), and decrement the reference count of the
original object. Destroying a CTCLObject
invokes
Tcl_DecrRefCount
on the underlying Tcl_Obj
object. This may or may not result in destruction of that underlying object
depending on the resulting reference count.
CTCLObject&operator
= (const CTCLObject&rhs
); intoperator==
(const CTCLObject&rhs
) const;
These two members provide assignment and equality comparison for CTCLObject
instances with another object rhs
. Assignment operates
efficiently by decrementing the reference count on the prior object,
incrementing the reference count for rhs
, and
copying its Tcl_Obj* only.
Equality comparision is true if the underlying objects have the same string
representation.
Tcl_Obj*getObject
(); const Tcl_Obj*getObject
() const;
Retrieves a mutable or immutable pointer to the underlying object.
If you intend to retain this pointer for longer than the lifetime of the
CTCLObject
object from which it comes or longer
than the lifetime of the execution of the calling function you should
invoke Tcl_IncrRefCount
to mark the object shared
and prevent its destruction until you no longer need it, at which point
you should invoke Tcl_DecrRefCount
.
You should not modify the underlying object as that violates the
copy on write semantics expected of Tcl_Obj objects.
Instead, use Tcl_DuplicateObj
to create a new
object (decrementing the reference count of the previous object), and
modify that one instead. The following code snippet shows this:
int len; Tcl_Obj* pObject = someObject.getObject(); string value = string(Tcl_GetStringFromObj(pObject, &len)); value += "new text"; pObject = Tcl_DuplicateObj(pObject); // Split off a new object. Tcl_SetStringObj(pObject, (char*)value.c_str(), -1);
CTCLObject&operator=
(const std::string&rSource
) ; CTCLObject&operator=
(const char*pSource
) ; CTCLObject&operator=
(intnSource
) ; CTCLObject&operator=
(const CTCLList&rList
) ; CTCLObject&operator=
(doubledSource
) ; CTCLObject&operator=
(Tcl_Obj*rhs
);
Assigns a new value to the object. The reference count of the previously
encapsulated object is decremented and a new object is created into
which the right hand side value is loaded. This preserves copy on write
semantics. rSource
and pSource
load
the new object with a string valued entity. No attempt is made to create another
representation for the object (yet).
nSource
loads the object with an integer value and its
string representation.
rList
loads the object with a list representation and
its string representation.
dSource
loads the object with a double precision floating
point value and its string representation. rhs
simply
copies in the new object pointer and increments its reference count.
operator std::string
() ;operator int
() ;operator CTCLList
() ;operator double
() ;
These function provide implicit and explicit type conversions between
a CTCLObject
instance and other types.
The type conversions attempt to extract the appropriately typed value
from the underlying object. If successful, the value is returned.
On failure, a CTCLException
is thrown.
For example:
CTCLObject object = "3.14159"; // String rep. object.Bind(pInterp); // Some of these need an interp. double pi = object // (operator double()). object = "george"; // string rep. try { int trash = object; // fails. } catch (CTCLException& e) { // this catch block will execute. }
CTCLObject&operator+=
(const CTCLObject&rObject
) ; CTCLObject&operator+=
(intnItem
) ; CTCLObject&operator+=
(const std::string&rItem
) ; CTCLObject&operator+=
(const char*pItem
) ; CTCLObject&operator+=
(doubleItem
) ;
Creates the list representation of the underlying object, converts either
rObject
,
nItem
,
rItem
,
pItem
,
Item
to its string representation and appends
it as a list entry to the object.
CTCLObject clone
() ;
A wrapper for Tcl_DuplicateObj
. The object is
duplicated and its duplicate is returned wrapped by a
CTCLOjbect
.
CTCLObject operator()
() ;
The object's string representation is compiled by its bound
interpreter to Tcl byte code and executed as a script by that
bound interpreter. Note that the byte code compilation is cached
so that subsequent invocations of the script will not require
recompilation unless other references force a different second
representation on the object (e.g. fetching it as a list).
The result of the script execution is returned as a new CTCLObject
If script compilation failed, or script execution resulted in an error,
a CTCLException
will be thrown describing this.
CTCLObjectgetRange
(intfirst
, intlast
);
Returns a new object that consists of a subrange of the string representation of
the original object. first
is the index of the first
character of the substring returned. last
is the
index of the last character of the substring. See Tcl_GetRange
for more information, note however that some values of first
or last
will be treated specially, and that the
underlying string representation operated on is a Unicode string
for which some characters in some languages may require more than one byte.
CTCLObject&concat
(CTCLObject&rhs
); // Concat lists.
Concatenates the rhs
as a list element to the object.
A refrence to the new object is returned. Copy on write semantics are maintained.
std::vector<CTCLObject> getListElements
();
Converts the object into its underlying list representation. The
elements of the list are loaded into a vector of CTCLObject
objects and returned. If the underlying string representation does not have
a valid list representation, (e.g. "{this cannot be converted") a
CTCLException
is thrown.
CTCLObject& setList(std::vector<CTCLObject> elements);
Loads the object with a string and list representation whose words are
the appropriately quoted string representation of elements
.
A reference to the new object is returned. Copy on write semantics are
maintained.
int llength()
;
If necessary, converts the object to its list representation and returns the
number of elements in that list. If it is not possible to convert the
string represenation of the object into a valid list, a CTCLException
is thrown.
CTCLObjectlindex
(intindex
);
If necessary, creates the list representation of the object and returns a
new object that is element number index
of that list.
If the object cannot be converted into a list, a CTCLException
is thrown.
CTCLObject&lreplace
(intfirst
, intcount
, std::vector<CTCLObject>newElements
);
If necessary, converts the object to its list representation. If that conversion
fails a CTCLException
is thrown. The set of elements
specified by first
and count
,
are replaced by the words held in the vector newElements
.
newElements
can, of course, be an empty vector in order
to remove count
elements starting at first
from the list. A reference to the resulting object is returned.
Copy on write semantics are enforced.