C++11 Mapping for Sequences

On this page:

Default Sequence Mapping in C++

Here is the definition of our FruitPlatter sequence once more:

Slice
sequence<Fruit> FruitPlatter;

The Slice compiler generates the following definition for the FruitPlatter sequence:

C++
using FruitPlatter = std::vector<Fruit>;

As you can see, the sequence simply maps to a standard std::vector, so you can use the sequence like any other vector. For example:

C++
// Make a small platter with one Apple and one Orange
//
FruitPlatter p;
p.push_back(Fruit::Apple);
p.push_back(Fruit::Orange);

Custom Sequence Mapping in C++

You can override the default mapping of Slice sequences to C++ vectors with the cpp:type and cpp:view-type metadata directives

For example:

Slice
[["cpp:include:list"]]

module Food
{
    enum Fruit { Apple, Pear, Orange }

    ["cpp:type:std::list<Food::Fruit>"]
    sequence<Fruit> FruitPlatter;
}

With this metadata directive, the sequence now maps to a C++ std::list:

C++
#include <list>

namespace Food 
{
    using FruitPlatter = std::list<Food::Fruit>;

    // ...
}

Custom Mapping for Sequence Parameters

In addition to the default and custom mappings of sequence types as a whole, you can use metadata to customize the mapping of a single operation parameter of type sequence.

The C++ mapping provides a metadata directive for this purpose, ["cpp:array"].

Array Mapping for Sequence Parameters in C++

The array mapping for sequence parameters applies only to: 

  • In parameters, on the client-side and on the server-side
  • Out and return parameters provided by the Ice run-time to AMI callbacks
  • Out and return parameters provided to marshaled results or AMD callbacks

 For example:

Slice
interface File
{
    void write(["cpp:array"] Ice::ByteSeq contents);
}

The cpp:array metadata directive instructs the compiler to map the contents parameter to a pair of pointers. With this directive, the write function on the proxy has the following signature:

C++
void write(const std::pair<const Ice::Byte*, const Ice::Byte*>& contents, const Ice::Context& = Ice::noExplicitContext);

To pass a byte sequence to the server, you pass a pair of pointers; the first pointer points at the beginning of the sequence, and the second pointer points one element past the end of the sequence.

Similarly, for the server side, the write method on the skeleton has the following signature:

C++
virtual void write(std::pair<const Ice::Byte*, const Ice::Byte*>, const Ice::Current&) = 0;

The passed pointers denote the beginning and end of the sequence as a range [first, last) (that is, they use the usual semantics for iterators).

The array mapping is useful to achieve zero-copy passing of sequences. The pointers point directly into the server-side transport buffer; this allows the server-side run time to avoid creating a vector to pass to the operation implementation, thereby avoiding both allocating memory for the sequence and copying its contents into that memory.

You can use the array mapping for any sequence type. However, it provides a performance advantage only for byte sequences (on all platforms) and for sequences of integral or floating point types (on some platforms).

See Also