KeyValue is a cross-platform library for making C++ objects accessible through OpenOffice Calc, Excel and other front-ends. Experience of spreadsheet users is enhanced by an object model and a handy key-value based interface.
KeyValue does more than just help creating spreadsheet functions. The object model allows end-users to build C++ objects through the front-ends. These objects are stored in a repository for latter use at user's request. Additionally, KeyValue provides a set of services to an effective use of these objects.
The library is named ater one of its main features: The key-value based interface. Parameters are passed to functions through key-value pairs in contrast to the standard positional interfaces of OpenOffice Calc, Excel, C/C++, etc.
For instance, consider a function which requires stock prices at different dates. Two vectors have to be passed: A vector of dates and a vector of prices. In a positional interface these two vectors would be rovided in a specific order, say, first the vector of dates followed by the vector of prices. In contrast, KeyValue allows a label (or key) to be attached to each vector (the value associated to the key) in order to distinguish their meanings. In the example, the keys could be Dates and Prices while the values would be the vectors of dates and prices themselves.
To give a taste of KeyValue, let us develop this example a bit further. Suppose we want to write a C++ function that, given a set of dates and corresponding stock prices, returns to the spreadsheet the earliest date where the stock has reached its lowest level. In the termsheet we would see something like in Figure 1.
The C++ code (see
keyvalue/bridge-example/bridge-example/processor/LowTime.cpp
)
could be:
template <>value::Value
Calculator
<LowTime>::getValue
(constDataSet
& data) const { // A constkey::MonotoneBoundedVector
<ptime
,key::StrictlyIncreasing
> keyDates("Dates"); // B const std::vector<ptime>& dates(*data.getValue
(keyDates)); // C constkey::MonotoneBoundedVector
<double,key::NonMonotone
,key::Geq
> keyPrices("Prices", 0.0, dates.size()); // D const std::vector<double>& prices(*data.getValue
(keyPrices)); // E double lowPrice = prices[0]; // F ptime lowDate = dates[0]; for (size_t i=1; i<prices.size(); ++i) if (prices[i] < lowPrice) { lowPrice = prices[i]; lowDate = dates[i]; } // G return lowDate; // H }
Without getting too deep in the details, we shall comment some important points of this example:
Functions returning values to the spreadsheet are
specializations of template class Calculator
of which
getValue()
is the main method.
The template type parameter LowTime
is
just a tag identifier to distinguish between different
functions.
Object keyDates
holds information about
key Dates including the label
"Dates
" seen on the spreadsheet. Its type is an
instantiation of key::MonotoneBoundedVector
for
type parameters ptime
and
key::StrictlyIncreasing
.
This means that the expected type of value is a
std::vector<ptime>
[1] object whose elements are in increasing
order.
Many other generic keys like key::MonotoneBoundedVector
are
implemented. We can implement application specific keys when no
generic key fits our needs or when this proves to be convenient.
For instance, implementing a class named
Dates
can be useful if key
Dates is used very often. In such case,
Dates
would hold all the above
information and line B would be replaced
by
const Dates keyDates;
The method DataSet
::
getValue()
retrieves the
std::vector<ptime>
object
containing the dates. At this time, all the information
contained in keyDates
is used. In particular,
the constraints on the input are verified and an exception is
thrown if the check fails. Therefore, if execution gets to next
line, we can safely assume that dates are in increasing
order.
Object keyPrices
carries information
about key Prices: the label
"Prices
" and its expected type of value,
that is, a std::vector<double>
object of size dates.size()
and positive
elements.
Retrieves the
std::vector<double>
object and, if
execution gets to next line, we can be sure that
prices
and dates
have the same size and all price
elements are
positive. Otherwise an exception will be thrown.
This bit of code could be part of the library which KeyValue helps to make accessible through OpenOffice Calc or Excel instead of being here.
While the type returned by Calculator
<LowTime>::
getValue()
is value::Value
the code above
returns a ptime
. For convenience,
KeyValue implements a collection of implicit conversions to
value::Value
from several types
including bool, double,
string
, ptime
,
std::vector<double>
, etc.
More than just a nice interface, KeyValue provides memory management, dependency control, exception handling, caching (memoization) and other services.
The two main examples of front-ends (both provided with KeyValue) are OpenOffice Calc and Excel. A third example is an XML parser. Other front-ends may be easily implemented thanks to KeyValue's modular design represented in Figure 2.
There are four layers. The main layer is occupied by KeyValue
alone and is independent, that is, does not #include
any
header file from other layers.
The top layer is populated by front-ends. Components of this layer
only #include
header files from KeyValue. (Fact indicated
by the down arrow.)
The bottom layer hosts the core library, that is, the C++ library which we want to use through front-ends with KeyValue's help. This layer is also independent. As mentioned, in the example above the code between lines F and G woulb be better placed in the core library.
The bridge layer connects
KeyValue and core library. Bridge #include
s files from both
layers it is connected to. The code given in the example above would be
part of this layer.
Additionally to KeyValue layer, the distibuted code contains the front-ends (excluding the XLM parser which will be available in a future release). KeyValue users have to implement the bridge and core library. If they wish, they can also easily implement other front-ends.