The Support Kit consist of a suite of useful utilities and common operations. These classes were designed and written to assist in developing the Binder and systems built on top of it, however they can be used in a wide variety of situations.
Be sure to also see the API Conventions page for a higher-level description of the coding conventions used by the Binder and its related APIs.
Note that error codes are negative constants. A common pattern is to use ssize_t to return a result that can be either a (negative) error code or a (positive) index. Thus, for example, you will often write code like:
void myFunc(const SSortedVector<SString>& stringSet) { ssize_t index = stringSet.IndexOf(SString("some string")); if (index >= 0) { // ... do something ... } else { // couldn't find "some string" } }
See general_error_codes_enum for the standard C++ error code constant and Error Codes for more details on error codes.
All of the classes described here use copy-on-write semantics for their data, so you can cheaply copy them from one place to another. Note that thread safety is supplied for the underlying data (if more than one object is referencing the same copy-on-write buffer), but the public APIs described here are not thread safe. If multiple threads may be accessing a particular instance of one of these objects, you will need to protect it appropriately.
Usually you will pass these objects by constant reference in to a function, so that the copy-on-write mechanism can be used to avoid copying the object's data:
void MyClass::StoreSomething(const SString& inputString) { m_someString = inputString; }
The copy-on-write mechanism is also taken advantage of to efficiently return these objects by value from functions, which is very useful when writing thread safe code:
SString MyClass::RetrieveSomething() const { return m_someString; }
An unusual feature of SValue is that it can hold complex data structures in addition to simple typed data. These are constructed as sets of mappings, where the key and value of each mapping is itself an SValue object (which may contain further mappings). These kinds of data structures are usually written in this way:
{ "Key1" -> 0, "Key2" -> "string" }
Indeed, the Binder Shell provides a mechanism to build SValue structures using just this syntax:
$ echo @{ Key1 -> 0, Key2 -> string }
The macros B_STATIC_STRING_VALUE_LARGE() and B_STATIC_STRING_VALUE_SMALL() are provided to efficiently create static string constants. Note that a constant like the following requires, at load time, for the SValue object to be constructed and memory allocated for "some string":
static SValue myValue("some string");
Not only does this take time to do, but it means that the SValue object itself can't be placed in the constant section of your code, and the data from the string must be copied out of your constant sections and on to the heap. As an alternative, this code will produce a "myValue" holding the exact same string constant as shown above:
B_STATIC_STRING_VALUE_LARGE(myValue, "some string", );
The data for this object is created entirely through static data structures that can be placed in the executable's text section. The myValue constant can be used as either an SValue or SString object, depending on what you need.
The B_STATIC_STRING_VALUE_SMALL() macro is used to create SValue constants that are four bytes (including a string NUL terminator) or less. Thus the correct uses of these macros:
B_STATIC_STRING_VALUE_SMALL(mySmallValue, "123", ); B_STATIC_STRING_VALUE_LARGE(myLargeValue, "1234", );
For the very performance conscious, the SSimpleValue template class is a very efficient way to create SValue constants at runtime like B_STATIC_STRING_VALUE_SMALL but for different types that are created on the stack. The SSimpleStatusValue is the same kind of thing as SSimpleValue, but specifically for an SValue holding a status code.
These classes avoid templatizing their implementation by spliting the class into two parts. A base class (such as SAbstractVector) provides a type-independent implementation of its algorithms, with a set of pure virtual functions (such as SAbstractVector::PerformCopy()) that represent the type-dependent operations it will need to do.
The template class you use in your code, such as SVector, derives from its corresponding generic base class, and provides the type specific parts of the implementation. These are very minimal, consisting mostly of type casts along with an implementation of the pure virtuals needed by the base class.
Like the Basic Types, none of the APIs described here are thread safe. You must supply your own thread protection if multiple threads will be accessing the same class instance.
Two-dimensional arrays are created by nesting SVector objects:
SVector<SVector<int32_t> > array_2d;
Though this kind of structure can lead to significant inefficiency due to a lot of copying of inner objects when the outer container is change, the SVector class provides an optimization so that in most cases the inner SVector instances will simply be moved in memory when rows are added or removed from the outer SVector.
These kinds of optimizations are supported by a lot of the standard Binder type classes through specialization of the type-specific functions in support/TypeFuncs.h. In particular, SVector implements BMoveBefore and BMoveAfter to provide an efficient mechanism for moving a vector in memory without having to completely copy and destroy the object.
The SAtom Debugging page describes a rich set of reference count debugging and leak tracking features that are available for SAtom and SLightAtom objects.
The SLocker::Autolock class is a convenient way to manage the locking in a function. By placing it on the stack, it will automatically release your lock when execution exits its containing code block either by naturally leaving the block, a return, or an exception.
class MyClass { public: void SafeFunc(const SString& string); { SLocker::Autolock _l(m_lock); if (m_string != "") return; m_string = string; } private: SLocker m_lock; SString m_string; };
void MyClass::MyFunc(sptr<Something>* inout1, sptr<Something>* inout2) { SLocker::Autolock _l(m_lock); // This code can call into the Something destructor with m_lock // held. *inout1 = NULL; // This code can -still- call into the Something destructor with // m_lock held, because holdRef will be destroyed before _l! sptr<Something> holdRef(*inout2); *inout2 = NULL; }
In addition, setting LOCK_DEBUG_STACK_CRAWLS to a non-zero integer will include stack crawl information in the debugging instrumentation, telling you where the problematic locks were acquired.
The SHandler Patterns is a recipe book for some common threading techniques using SHandler.
SValue myval(SValue::String("str1"), SValue::String("str2")); myval.JoinItem(SValue::String("str3"), SValue::String("str4")); bout << myval << endl;
Also included are some convenience classes for printing data using special formats.