Chapter 2. Data Containers¶
In this chapter, I will finish explaining about Container class and
its subclasses.
You need to open the source code committed with message
002. Data Containers before read the extra chapter.
Superclass Container¶
The Container class is a superclass for 4 data container implementations,
Single, List, Set, and Map. List, set, and map are well known, and
you may not heard about something like single container but still you can
guess what it is: it’s container for only one instance.
Container provides common pure virtual functions which can be applied to
all of 4 containers, or more if you add some new container types later.
They are size() and datas(). They are pretty straight-forward, but
I still need to explain: size() returns the number of items in the
container. For SingleContainer, it returns 1 if the container has valid
object, unless returns 0.
data() returns ordered list of all Data instances the container has.
SetContainer and MapContainer returns child instances in sorted order.
Key is not included for MapContainer. For SingleContainer, if it has
valid object, the function returns list of one item, otherwise return null
list.
All the Container subclasses provides 2 version of container: they are
ownership container and reference container. Ownership container takes
its owner’s children, while reference container takes reference of other
Data instances which have separate parent.
Container’s subclasses are class templates, which usually take T
and Ptr as its parameters. For MapContainer, it takes one more
parameter, Key. T is a subtype of Data to be stored, and
Ptr is a smart pointer type which is intended to be used. get() and
operator * should be implemented: std::shared_ptr satisfies the
condition. Ptr can be TypeEnum::Ref, which may invoke reference
version container instead of ownership version.
SingleContainer¶
In single_container.h, SingleContainer is defined. It provides
two setters and two events, setValid(), setNul(), sig_validSet(),
and sig_beforeNullSet().
setValid() is a setter which can be used for null container to set
valid, new data instance. Only valid object is allowed, and calling this with
nullptr with expecting same result with calling setNull() will show
undefined behavior instead. Nor this should not be called when a valid instance
is already set: setNull() must be called first then this function is
followed.
setNull() is in opposite side of setValid(). It should be called
only when the container is holding a valid instance, to set it null.
sig_validSet() will be called after setValid() does its job.
sig_beforeNullSet() will be called before setValid() does its
job. Attention at the word “before”.
SetContainer¶
This container introduces add(), remove(), clear() setters,
has(), list() getters, and sig_added(), sig_beforeRemoved(),
and sig_beforeCleared().
add(), remove(), and clear() work just as what general programmers
expect for a general set container, except for that add() and remove()
will show undefined behavior if existing instance is added again or
non-existing instance is removed.
has() returns true if the instance exists, otherwise returns false.
list() is same with datas(), but it returns in type of template, not
Data superclass.
sig_added() and sig_beforeRemoved() work as expected, similar with
SingleContainer’s one.
sig_beforeCleared() is introduced to provide better performance to
signal accepters. When clear() is called, instead of sig_beforeRemoved()
is called for every instances, sig_beforeCleared() will be called once.
ListContainer¶
single() returns an instance placed at passed index.
list() is same with datas(), but returns in type of template,
not Data.
index() is opposite of single(), it takes an instance and returns
position of it. isValid out parameter is set false if there’s no matching
instance, otherwise it will be set true. If no output isValid parameter is
given, the function may show undefined behavior if there’s no matching instance.
However, that undefined behavior will be assertion.
append(), insert(), remove(), move(), and clear() work
as just expected for general list container. One uncommon method is move(),
it is not common move operation in C/C++, but takes 2 indexes and swap
the instances’ position.
sig_added(), sig_beforeRemoved(), and sig_beforeCleared()
are called in same manner with
SetContainer and SingleContainer. sig_moved() is called after
move() finishes its job.
MapContainer¶
keyList(), valueList() and list() returns list of key, value, or
both.
value() returns an instance which is corresponding to the parameter key.
Undefined behavior will occur if the parameter key does not exist.
key() is opposite of value(): it returns a key matching with an
parameter instance. The implementation may need to iterate through all
instances, so it can be expensive, depended on the number of instances.
Undefined behavior will occur if the parameter instance does not exist.
hasKey() and hasValue() can be used to check existence of specific
key or instance. Returns true if the parameter exists, otherwise returns false.
hasValue() may be expensive, because the implementation may require
iteration through all instances.
sig_added(), sig_beforeRemoved(), and sig_beforeCleared() follows
exactly same manner with SetContainer.
SinglePrimContainer¶
Well, this is not a Data instance container, but it’s for general value
types such as int, float, std::string, image, vector, animation,
geometry, and similar ones.
It follows general getter-setter pattern, except modification event is
provided as well. (sig_updated())
Its setter is not separated into valid setter and null setter, since there’s no null value for value types: null is a concept for object types.