19 SWIG and Reposit

19.1 Overview

The reposit project implements an object repository in which objects may be instantiated, queried, updated, and destroyed, facilitating deployment of object oriented functionality to procedural platforms such as spreadsheets.

The reposit SWIG module parses the header files of your C++ library and autogenerates an Excel addin which links your library to the object repository, making it possible to call your library from a spreadsheet. Reposit also generates a C++ addin with the same interface as the Excel addin. Reposit wraps the objects from your C++ library in a layer that supports additional features such as serialization, allowing data to be transferred between Excel and C++ processes. Other supported platforms include C# and =countify.

The home page for the reposit project is http://www.quantlib.org/reposit/index.html

19.2 Differences Between the reposit SWIG Module and Other SWIG Modules

The reposit SWIG module differs from other SWIG modules in a couple of respects. Reposit parses C++ code in the usual way but does its own thing for autogenerating source code.

In order to parse the C++ code of the library you are trying to wrap, you impement a class inherited from Language and override selected member functions to intercept events of interest. The design of the reposit module is perfectly standard in this respect:

class REPOSIT : public Language {
    int functionHandler(Node *n);
    int classDeclaration(Node *n);
    int namespaceDeclaration(Node *n);
    // etc etc etc
};

To generate the source code of the addin, SWIG provides a set of buffers (begin, runtime, header, etc...). The basic structure of these buffers is usually similar from one SWIG module to another. Reposit does not use these buffers. Reposit allows SWIG to generate some of the default content of these buffers. Reposit also dumps some debug info into those buffers. Reposit then appends all of SWIG's buffers one after the other into an output file called ./test.cpp. The file is not part of the build and does not contain valid C++, but looking at the contents of the file can sometimes be helpful when debugging the behavior of the reposit module.

Reposit instead generates its own set of output buffers and writes these to disk. When generating the output, reposit uses a lot of standard SWIG utilities - typemaps, output functions, etc. But the list of output files is completely specific to reposit. The output files are explained in detail later in this document.

19.3 Installation

A basic howto for installing and running the reposit SWIG module and object repository is provided at the following link: http://www.quantlib.org/reposit/installation.html. The document you are reading now provides more in depth information on the reposit SWIG module.

19.4 Running SWIG

If you build SWIG with "make install", then the resulting binary can be found at xxx/bin/swig, where xxx is the installation directory.

If you just do "make" then you get a binary at swig/preinst-swig. The reposit examples within the SWIG source tree run off this local binary, so that during development you can just do "make" rather than "make install".

After you have compiled SWIG with the reposit module, you run it like this:

swig -c++ -reposit -gencpp -genxll -prefix xx xxx.i

Here is a description of the arguments:

ArgumentMeaning
-c++This tells SWIG that the library you are going to wrap is written in C++.
-repositThis means that you want to run the reposit module.
-legacySupply this optional flag to generate backward compatible function signatures (see below).
-gencppUse this argument to generate a C++ addin.
-genxllUse this argument to generate an Excel addin.
-prefix xxThis indicates the prefix to be prepended to the names of the functions in your addin. For example, if prefix is xx, and if you are wrapping member function Bar in class Foo, then the resulting addin function will be called xxFooBar().
xxx.iThis is the name of your SWIG interface file.

The SWIG interface file that you provide for the reposit module needs to contain a section like this:

%module(
    rp_obj_dir="dir1",
    rp_add_dir="dir2",
    rp_xll_dir="dir3",
    rp_obj_inc="dir4",
    rp_add_inc="dir4",
    rp_xll_inc="dir6"
) MyAddin

The paths indicate the relative paths to the directories where the addin code is generated. The last argument is the name of the addin. See the examples.

19.5 Function Signatures

When autogenerating addin source code, reposit inserts additional arguments into each function:

ArgumentFunctionMemberConstructor
Trigger - Force a dependency on another function
ObjectId - ID of object to be created/invoked 
Overwrite - Flag to indicate whether new object should replace an old one with the same ID  
Permanent - Flag to indicate whether object should persist after a call to function rpRepositoryDeleteAllObjects()  

When autogenerating addin source code, there are two possibilities regarding the sequence in which autogenerated arguments appear in function signatures:

This is how the function signatures appear under the old and new configurations for functions, members, and constructors:

Function TypeOld Build (-legacy)New Build (default)
Function..., TriggerTrigger, ...
MemberObjectId, ..., TriggerTrigger, ObjectId, ...
ConstructorObjectId, ..., Permanent, Trigger, OverwriteTrigger, ObjectId, Overwrite, Permanent, ...

19.6 Components of the reposit SWIG module

If you want to make any changes to the reposit SWIG module then the files and directories of most interest are:

swig/Source/Modules/reposit.cxx
swig/Lib/reposit/reposit.swg
swig/Examples/reposit/
swig/Doc/Manual/Reposit.html

19.7 Examples

Two example applications are provided.

19.7.1 SimpleLib

The SimpleLib example is provided in directory swig/Examples/reposit/simple. This is nearly the smallest reposit project that it is possible to have.

The code in directory simple/Library represents the C++ library that you want to wrap. File simple/Library/adder.hpp implements a function and a class:

    std::string func();

    class Adder {
    private:
        long x_;
    public:
        Adder(long x);
        long add(long y);
    };

File simple/swig/simple.i is the SWIG interface file that the reposit SWIG module uses to generate the addins for the above library:

// This typemap tells the reposit SWIG module that type SimpleLib::Adder *
// should be treated like a char* as far as Excel is concerned.
%typemap(rp_tm_xll_cod) SimpleLib::Adder * "C";

// This directive specifies the directories to which the autogenerated output
// files should be written, and the name of the addin.
%module(
    rp_obj_dir="../AddinObjects",
    rp_add_dir="../AddinCpp",
    rp_xll_dir="../AddinXl",
    rp_obj_inc="AddinObjects",
    rp_add_inc="AddinCpp",
    rp_xll_inc="AddinXl"
) SimpleLibAddin

// This directive says that we want to group some functions under the label
// "adder"
%feature("rp:group", "adder");

// This directive specifies the #include statement that must be inserted into
// the source code for autogenerated objects.
%feature("rp:obj_include") %{
#include "Library/adder.hpp"
%}

// This code indicates which functionality from the SimpleLib library should be
// included in the addin.
namespace SimpleLib {
    std::string func();
    class Adder {
    public:
        Adder(long x);
        long add(long y);
    };
}

The source code for addin wrapper classes is autogenerated to files in directory simple/AddinObjects.

The functions for the C++ addin are autogenerated to files in directory simple/AddinCpp.

File simple/Main/mainSimpleLibAddin.cpp shows how an end user calls the C++ addin. It is pretty easy:

// Call function SimpleLib::func()
std::cout << SimpleLibAddinCpp::slFunc() << std::endl;
// Construct an instance of class SimpleLib::Adder
SimpleLibAddinCpp::slAdder("adder", 1);
// Call member function SimpleLib::Adder::add()
std::cout << "1 + 2 = " << SimpleLibAddinCpp::slAdderAdd("adder", 2) << std::endl;

These are the paths to the Excel addin and sample workbook:

simple\Release\AddinXl.xll
simple\AddinXl\AddinXl.xlsx

The functionality of the example workbook is the same as that of the example C++ program:

=slFunc()
=slAdder("adder", 1)
=slAdderAdd("adder", 2)

19.7.2 ComplexLib

The ComplexLib example is provided in directory swig/Examples/reposit/complex. This project is a bucket of every single feature supported by reposit. The ComplexLib example project is referred to throughout the rest of this document.

Here is an overview of the components of the ComplexLib example:

PathComponent
ComplexLibThe example C++ library that we want to wrap
ComplexLibAddin/swigThe configuration files for the reposit SWIG module
ComplexLibAddin/cloAutogenerated wrapper classes
ComplexLibAddin/AddinCppAutogenerated C++ addin
ComplexLibAddin/MainSample C++ client program
ComplexLibXLAutogenerated Excel addin
Release\AddinXl.xllThe Excel addin binary
ComplexLibXL\Workbooks\AddinXl.xlsxExample spreadsheet

19.8 Buffers

This chapter summarizes the output files that are generated by the reposit SWIG module. The exact locations of the files depends on the configuration described above. For purposes of this example we use the paths that are configured in the example project, swig/Examples/reposit/complex.

When you run the SWIG reposit module, the following global files are generated:

PathComponent
ComplexLibAddin/clo/obj_all.hpp#include directives
ComplexLibAddin/clo/serialization/create/create_all.hpp#includes relating to creation of serializtion objects
ComplexLibAddin/clo/serialization/register_creators.cppregister addin classes with the serialization layer
ComplexLibAddin/clo/serialization/register/serialization_register.hpp#includes relating to registration for serialization
ComplexLibAddin/clo/serialization/register/serialization_all.hpp#includes relating to registration for serialization
ComplexLibAddin/AddinCpp/add_all.hpp#includes for the C++ addin
ComplexLibXL/clxl/register/register_all.cppregister addin functions with Excel

In addition, for each function group xxx, defined in file ComplexLibAddin/swig/functions/xxx.i, you will get the following collection of files:

PathComponent
ComplexLibAddin/clo/obj_xx.hppaddin objects that wrap classes in the library
ComplexLibAddin/clo/valueobjects/vo_xx.?ppimplementation of value objects in support of serialization
ComplexLibAddin/clo/serialization/create/create_xx.?ppfunctions to create objects as they are deserialized
ComplexLibAddin/clo/serialization/register/serialization_xx.?ppregister addin classes with the serialization layer
ComplexLibAddin/AddinCpp/add_xx.?ppthe functions in the C++ addin
ComplexLibXL/clxl/functions/function_xxx.cppthe functions in the Excel addin
ComplexLibXL/clxl/register/register_xxx.cppregister addin functions with Excel

The obj_xxx.?pp files are the addin objects that wrap the library objects - this is explained in more detail later in this document. The directories valueobjects and serialization contain code to support serialization of objects in the repository. The add_xxx.?pp files are the C++ addin functions. The files in the XL directory are the Excel addin functions.

19.9 Features

This section documents all of the features supported by reposit. The relevant code in ComplexLib is referenced throughout.

19.9.1 Functions

This example demonstrates how a simple function in the C++ library is exported to the Excel and C++ addins.

File ComplexLib/cl/functions.hpp defines a function:

std::string func1();

File ComplexLibAddin/swig/functions/functions.i defines the wrapper for the above function.

The implementation of the function in the C++ addin appears in files ComplexLibAddin/AddinCpp/add_functions.?pp.

Usage of the C++ addin function is demonstrated in file ComplexLibAddin/Main/test_functions.cpp:

    std::cout << ComplexLibAddinCpp::clFunc1() << std::endl;

The implementation of the function in the Excel addin appears in file ComplexLibXL/clxl/functions/function_functions.cpp.

19.9.2 Typedefs

File ComplexLib/cl/typedefs.hpp implements a couple of typedefs:

    typedef double Double;
    typedef long double LongDouble;

The above file also implements a couple of test functions that receive as inputs variables of the above typedefs.

Reposit has native support for bool, long, double, and string. The first typedef above is mapped automatically by SWIG to a double and no extra work is required. The second typedef, LongDouble, maps to long double which is a type not recognized by reposit.

In file ComplexLibAddin/swig/typemaps/all.i, a definition is provided for LongDouble:

%apply rp_tp_double { LongDouble };
%apply const rp_tp_double & { const LongDouble & };

This maps LongDouble to rp_tp_double. rp_tp_double is an identifier that reposit recognizes and treats as a double. This is explained in more detail later.

19.9.3 Objects

File ComplexLib/cl/objects.hpp declares a class:

namespace ComplexLib {
    class Test {
        long input_;
    public:
        Test(long input);
        long getInput() const;
    };
};

How will reposit process this class? The object repository looks something like this:

    map<string, ObjectHandler::Object *> repository;

We want to store class ComplexLib::Test in the repository, but the repository only accepts objects of type ObjectHandler::Object, and ComplexLib::Test is not an ObjectHandler::Object.

We autogenerate a class ComplexLibAddin::Test which inherits from ObjectHandler::Object and holds a reference to ComplexLib::Test:

        ______________________________
       |                              |
       |     ObjectHandler::Object    |
       |______________________________|
                       ^
                       |
        _______________|______________     _______________________
       |                              |   |                      |
       |     ComplexLibAddin::Test    |-->|   ComplexLib::Test   |
       |______________________________|   |______________________|

In fact, 99% percent of the time, ComplexLibAddin::Test requires a few standard facilities (such as the reference to ComplexLib::Test). These facilities are implemented in class ObjectHandler::LibraryObject, which is usually inserted between ObjectHandler::Object and ComplexLibAddin::Test:

        ______________________________
       |                              |
       |     ObjectHandler::Object    |
       |______________________________|
                       ^
                       |
        _______________|______________
       |                              |
       | ObjectHandler::LibraryObject |
       |______________________________|
                       ^
                       |
        _______________|______________     _______________________
       |                              |   |                      |
       |     ComplexLibAddin::Test    |-->|   ComplexLib::Test   |
       |______________________________|   |______________________|

The definition of ComplexLibAddin::Test is autogenerated to files ComplexLibAddin/clo/obj_objects.?pp.

Addin wrapper functions relating to class ComplexLibAddin::Test are written to files ComplexLibAddin/AddinCpp/add_objects.?pp.

Usage of the wrapper is demonstrated in file ComplexLibAddin/Main/test_objects.cpp:

    ComplexLibAddinCpp::clTest("my_test", 42);
    std::cout << ComplexLibAddinCpp::clTestGetInput("my_test") << std::endl;

Equivalent Excel functionality is also generated. Usage in the Excel spreadsheet is exactly the same as that of the example C++ program:

    =clTest("my_test", 42)
    =clTestGetInput("my_test")

19.9.4 Inheritance

Reposit supports inheritance. A couple of example class hierarchies are implemented in file ComplexLib/cl/inheritance.hpp:

    // One base class, one derived.

    class Base {
    public:
        virtual std::string f() { return "ComplexLib::Base::f()"; }
        virtual ~Base() {}
    };

    class Derived : public Base {
    public:
        virtual std::string f() { return "ComplexLib::Derived::f()"; }
    };

    // Hierarchy of 3 classes.

    class A {
    public:
        virtual std::string f0()=0;
        virtual ~A() {}
    };

    class B : public A {
    public:
        virtual std::string f1()=0;
    };

    class C : public B {
    public:
        virtual std::string f0() { return "ComplexLib::C::f0()"; }
        virtual std::string f1() { return "ComplexLib::C::f1()"; }
    };

For each class above in the ComplexLib namespace, a corresponding wrapper class is autogenerated in the ComplexLibAddin namespace. The logic is a little complicated, though all of it is handled automatically by reposit, no configuration is required.

Generation of wrapper classes depends upon whether the class being wrapped is a base class or a derived class, and whether it has a constructor. For classes with no constructors, reposit still generates wrappers for the member functions, allowing the interface of the class to be exported to the addin.

You might see four different kinds of constructors being autogenerated to ComplexLibAddin/clo/obj_xxx.hpp:

Parent?Constructor?CodeDescription
NoYesfull class inheriting LibraryObjectIf the library class is a base class, and if it has a constructor, then reposit autogenerates a complete implementation of the wrapper class. For base class ComplexLib::Foo, you get a wrapper class ComplexLibAddin::Foo which inherits from helper class ObjectHandler::LibraryObject.
NoNoOH_LIB_CLASSIf the library class is a base class, and if it has no constructor, reposit still generates a wrapper class. But the wrapper is a skeleton and the entire implementation is provided by macro OH_LIB_CLASS.
YesYesfull class inheriting ObjectIf the library class is a derived class, and if it has a constructor, then reposit autogenerates a complete implementation of the wrapper class. For base class ComplexLib::Bar deriving from ComplexLib::Foo, you get a wrapper class ComplexLibAddin::Bar deriving from ComplexLibAddin::Foo.
YesNoOH_OBJ_CLASSIf the library class is a derived class, and if it has no constructor, reposit still generates a wrapper class. But the wrapper is a skeleton and the entire implementation is provided by macro OH_OBJ_CLASS.

Note that in this context when we talk about whether or not a class has a constructor, we mean simply whether or not a constructor is exported to the addin. In other words, is the constructor defined in our xxx.i file? We don't care how many constructors are actually implemented in the library class, or whether they are default or explicit. For purposes of the four rules listed above, if a class's constructor appears in the xxx.i file, then the class has a constructor, if not then it doesn't.

Examples of all of the output described above may be found in file ComplexLibAddin/clo/obj_inheritance.hpp.

You can see inheritance at work in file ComplexLibAddin/Main/test_inheritance.cpp. For example, the code below constructs an object of type Derived, then invokes member function Base::f():

    ComplexLibAddinCpp::clDerived("derived");
    std::cout << ComplexLibAddinCpp::clBaseF("derived") << std::endl;

19.9.5 Conversions

For the arguments and return values of addin functions, the only data types that reposit allows are: bool, long, double, string, and any. On C++, any is ObjectHandler::property_t, which is a boost::variant. On Excel, any is OPER.

Any time a library function requires an input of a type not listed above, a conversion must be performed.

File ComplexLib/cl/conversions.hpp declares a type Grade, and a function expecting an input of that type:

    struct Grade {
        Grade(double);
        operator char();
    private:
        double score_;
    };

    std::string showGrade(Grade);

File ComplexLibAddin/swig/typemaps/all.i applies the identifier rp_tp_cnv to Grade:

%apply rp_tp_cnv { Grade };

This tells reposit that a conversion must be performed on inputs or outputs of this type.

The necessary functions to convert an input argument into a value of type Grade are implemented by hand in files ComplexLibAddin/clo/conversions/*.?pp.

Reposit takes care of the rest automatically. In file ComplexLibAddin/clo/obj_conversions.hpp, the wrapper function is already expecting an input of type Grade:

    std::string showGrade(
        Grade score
    );

The code to perform the conversion is autogenerated in the wrapper function in file ComplexLibAddin/AddinCpp/add_conversions.cpp. This C++ addin function accepts an argument of type ObjectHandler::property_t, and converts it to Grade by calling the handwritten conversion function mentioned previously:

std::string ComplexLibAddinCpp::clShowGrade(
    const ObjectHandler::property_t& score
) {
    Grade score_cnv =
        ObjectHandler::convert2<Grade, ObjectHandler::property_t>score);

    return ComplexLibAddin::showGrade(score_cnv);
}

Sample usage of the function appears in file ComplexLibAddin/Main/test_conversions.cpp:

std::cout << ComplexLibAddinCpp::clShowGrade(75.) >> std::endl;

Note that the type Grade is not wrapped by our addin. The end user supplies a double which reposit stores in a ObjectHandler::property_t before converting to a Grade. If we wanted to we could wrap Grade as a class available to the addin.

The conversion functionality in the Excel addin is analogous to that described above for the C++ addin.

19.9.6 Coercions

A coercion is a list of conversions. We receive an argument from the caller - usually of type any or string - and attempt a series of conversions on it. The first successful conversion is used.

File ComplexLib/cl/coercions.hpp implements type Grade2 that can be used to illustrate coercion, and a function taking arguments of that type:

    struct Grade2 {
        Grade2(double=0);
        operator char();
    private:
        double score_;
    };

    std::string showGrade2(Grade2);

Simlar to the preceding conversion example, file ComplexLibAddin/swig/typemaps/all.i applies the identifier rp_tp_crc to Grade2:

%apply rp_tp_crc { Grade2 };

The necessary functions to coerce an input argument into a value of type Grade2 are implemented by hand in file ComplexLibAddin/clo/coercions/coerce_grade.hpp.

As in the conversion example given before, file ComplexLibAddin/clo/obj_coercions.hpp implements a wrapper function which already expects an argument that has been coerced to type Grade2.

In file ComplexLibAddin/AddinCpp/add_coercions.cpp, the wrapper function accepts an argument of type ObjectHandler::property_t, and invokes the relevant code to coerce the value into type Grade2.

19.9.7 Enumerations

Reposit implements a number of registries which allow C++ eunmerations to be represented by strings. This facilitiates support of C++ enumerations on platforms where they are not recognized, such as Excel.

19.9.7.1 Enumerated Types

Reposit's enumerated type registry maps C++ enums to strings.

File ComplexLib/cl/enumerated_types.hpp defines a couple of enumerated types, and some functions to process them:

    enum AccountType { Current, Savings };
    long getInterestRate(AccountType accountType);

    struct Account2 {
        enum Type2 { Current2=0, Savings2=1 };
    };
    long getInterestRate2(Account2::Type2 accountType2);

In file ComplexLibAddin/swig/typemaps/all.i, we tell reposit that AccountType and Account2::Type2 are C++ enums:

%apply rp_tp_enm { AccountType };
%apply rp_tp_enm { Account2::Type2 };

The code to add the above values into the enumeration registry is handwritten in file ComplexLibAddin/clo/enumerations/register/register_types.cpp.

Similar to previous examples, the autogenerated wrapper code in ComplexLibAddin/clo/obj_enumerated_types.hpp expects that inputs have already been converted into enumerations.

The conversion takes place in file ComplexLibAddin/AddinCpp/add_enumerated_types.cpp. The addin function accepts an argument of type string and converts it to an enum, by calling in to the enumerated type registry:

long ComplexLibAddinCpp::clGetInterestRate(
    const std::string& accountType
) {
    AccountType accountType_enm =
        ObjectHandler::Create<AccountType>()(accountType);

    return ComplexLibAddin::getInterestRate(accountType_enm);
}

File ComplexLibAddin/Main/test_enumerated_types.cpp shows that the end user can supply a string in place of the enumeration:

std::cout  <<"Interest rate current = " << ComplexLibAddinCpp::clGetInterestRate("Current")  << std::endl;

19.9.7.2 Enumerated Classes

The enumerated class registry allows a string to be associated to an instance of a class. Classes enumerated in this way ought to be stateless, though reposit does not enforce that rule. Enumerating stateful classes can yield strange behavior. Every occurence of a given string (identifier) maps to the same single instance of the enumerated class.

File ComplexLib/cl/enumerated_classes.hpp implements a family of stateless classes, and a function to process them:

    class TimeZone { /* ... */ };
    class TimeZoneEst : public TimeZone { /* ... */ };
    class TimeZoneUtc : public TimeZone { /* ... */ };
    class TimeZoneCst : public TimeZone { /* ... */ };
    std::string timeString(boost::shared_ptr<TimeZone> timeZone);

In file ComplexLibAddin/swig/typemaps/all.i, we tell reposit that we want to enumerate the TimeZone class:

%apply rp_tp_enm_cls { boost::shared_ptr<TimeZone> };

The code to register the TimeZone types with reposit's enumerated class registry is handwritten in file ComplexLibAddin/clo/enumerations/register/register_classes.cpp:

        create.registerType("EST", reinterpret_cast<void*>(TimeZone_EST));
        create.registerType("UTC", reinterpret_cast<void*>(TimeZone_UTC));
        create.registerType("CST", reinterpret_cast<void*>(TimeZone_CST));

The conversion from string to class is autogenerated in file ComplexLibAddin/AddinCpp/add_enumerated_classes.cpp.

File ComplexLibAddin/Main/test_enumerated_classes.cpp demonstrates that the end user can refer to an enumerated class by it corresponding string:

std::cout << "The current time in New York is "  << ComplexLibAddinCpp::clTimeString("EST")  << std::endl;

19.9.7.3 Enumerated Pairs

This feature is not yet supported. The functionality is supported in the object repository but the reposit SWIG module does not yet autogenerate the corresponding addin code.

Enumerated pairs are used to provide support for template classes. Suppose you have a C++ class that looks like this:

template<type A, type B>
class Foo { ... };

Reposit's enumerated pair registry allows an instance of the above class to be created from Excel using something like:

=xxFoo("my_foo", "A", "B")

19.9.7.4 Custom Enumerations

This feature is not yet supported. The functionality is supported in the object repository but the reposit SWIG module does not yet autogenerate the corresponding addin code.

Custom enumerations allow a string to be associated to a functor of any kind. This facilitates a wide range of custom functionality.

19.9.8 Serialization

reposit generates all of the code necessary to serialize the objects in the addin. This feature is not yet documented.

19.9.9 Looping Functions

Excel supports functions which loop on one of their inputs and return a list of values, each value in the return list relating to the corresponding value in the input list. Reposit supports autogeneration of functions which implement the same support for looping but this feature is not yet documented.

19.9.10 Handwritten Implementations

Sometimes you want to override the behavior in the autogenerated code.

File ComplexLib/cl/overrides.hpp implements some simple behavior:

    class Test2 {
    public:
        std::string f() { return "ComplexLib::Test2::f()"; }
    };

Suppose we want to take the addin function that wraps the above, and implement additional behavior there.

Our SWIG wrapper for the above code is configured in file ComplexLibAddin/swig/functions/overrides.i. We use the %override directive to suppress autogeneration of the object wrapper code:

%group(overrides);
%override

%insert(overrides_library_hpp) %{
#include <cl/overrides.hpp>
%}

namespace ComplexLib {
    class Test2 {
    public:
        Test2();
        std::string f();
    };
}

When we run SWIG, note that the autogenerated file is named with the suffix .template:

../clo/objmanual_overrides.hpp.template................................Unchanged

The file above is created for convenience only and is not included in the build. We must manually copy it, removing the .template extension:

ComplexLibAddin/clo/objmanual_overrides.hpp

Now we edit the file as desired, adding the corresponding cpp file if necessary. The default behavior as shown above is to print out the string "ComplexLib::Test2::f()". Let us also print out the string "ComplexLibAddin::Test2::f()". In file ComplexLibAddin/clo/objmanual_overrides.cpp we write:

std::string ComplexLibAddin::Test2::f() {
    return "ComplexLibAddin::Test2::f() " + libraryObject_->f();
}

The call to this function appears in file ComplexLibAddin/Main/test_overrides.cpp:

ComplexLibAddinCpp::clTest2(trigger, "my_test2", overwrite, permanent);
std::cout << ComplexLibAddinCpp::clTest2F(trigger, "my_test2") << std::endl;

If you run it you will see that you get the overridden behavior.

19.9.11 Handwritten Implementations - Advanced

TODO - Provide another example which mixes and matches (1) handwritten and autogenerated code and (2) ComplexLib and ComplexLibAddin namespaces.

19.10 Typemaps

BUFFERS

AddinScopeClassBuffer
Library ObjectsAddinAddinLibraryObjectsb_lib_add_hpp
Library ObjectsGroupGroupLibraryObjectsb_lib_grp_cpp
Library ObjectsGroupGroupLibraryObjectsb_lib_grp_hpp
Value ObjectsGroupGroupValueObjectsb_vob_grp_cpp
Value ObjectsGroupGroupValueObjectsb_vob_grp_hpp
Serialization - CreateAddinAddinSerializationCreateb_scr_add_hpp
Serialization - CreateGroupGroupSerializationCreateb_scr_grp_cpp
Serialization - CreateGroupGroupSerializationCreateb_scr_grp_hpp
Serialization - RegisterAddinAddinSerializationRegisterb_sra_add_hpp
Serialization - RegisterAddinAddinSerializationRegisterb_srg_add_cpp
Serialization - RegisterAddinAddinSerializationRegisterb_srg_add_hpp
Serialization - RegisterGroupGroupSerializationRegisterb_srg_grp_cpp
Serialization - RegisterGroupGroupSerializationRegisterb_srg_grp_hpp
C++ AddinAddinAddinCppb_cpp_add_all_hpp
C++ AddinGroupGroupCppb_cpp_grp_cpp
C++ AddinGroupGroupCppb_cpp_grp_hpp
Excel Addin - FunctionsGroupGroupExcelFunctionsb_xlf_grp_cpp
Excel Addin - RegisterAddinAddinExcelRegisterb_xlr_add_all_cpp
=countify AddinAddinAddinCountifyb_cfy_add_mng_txt
=countify AddinGroupGroupCountifyb_cfy_grp_cpp

TYPEMAPS

rp_tm_default - defined in code

There are 18 buffers and 21 typemaps.

A typemap always relates to a data type, either of a parameter or of a return value, for a function, constructor, or member.

Three of the 18 buffers do not use any typemaps. The output of those buffers relates not to functions but to groups - either a list of #includes, or a list of group-level functions such as initializers.

The 21 typemaps are distributed among the remaining 15 buffers.

Two typemaps, rp_type and rp_name, are shared among multiple buffers. Each of the remaining 19 typemaps is specific to a particular buffer.

The typemaps are defined in file swig/Lib/reposit/reposit.swg. Here is an overview of them.

BufferTypemapPurpose
rp_val_*rp_tm_val_prmxxx
rp_val_*rp_tm_val_dclxxx
rp_val_*rp_tm_val_serxxx
rp_val_*rp_tm_val_namxxx
rp_val_*rp_tm_val_inixxx
rp_val_*rp_tm_val_cnvxxx
rp_ser_*rp_tm_cre_cnvxxx
rp_obj_*rp_tm_obj_retxxx
rp_obj_*rp_tm_obj_rdcxxx
rp_add_*rp_tm_add_retxxx
rp_add_*rp_tm_add_prmxxx
rp_add_*rp_tm_add_cnvxxx
rp_add_*rp_tm_add_cllxxx
rp_add_*rp_add_retxxx
rp_add_*rp_tm_add_oh_getxxx
rp_xll_*rp_tm_xll_codxxx
rp_xll_*rp_tm_xll_prmxxx
rp_xll_*rp_tm_xll_cnvxxx
rp_xll_*rp_tm_xll_cll_objxxx
rp_xll_*rp_tm_xll_cll_valxxx
rp_xll_*rp_tm_xll_retxxx
rp_xll_*rp_xll_getxxx
rp_xll_*rp_tm_xll_rdcxxx

hello hello hello

shell here

hello hello hello

code here

hello hello hello

targetlang here

hello hello hello

diagram here