Skip to main content
Skip table of contents

Sequences

Sequence Syntax

Sequences are variable-length collections of elements:

SLICE
module M
{
    sequence<Fruit> FruitPlatter;
}

A sequence can be empty — that is, it can contain no elements, or it can hold any number of elements up to the memory limits of your platform.

Sequences can contain elements that are themselves sequences. This arrangement allows you to create lists of lists:

SLICE
module M
{
    sequence<FruitPlatter> FruitBanquet;
}

Sequences are used to model a variety of collections, such as vectors, lists, queues, sets, bags, or trees. (It is up to the application to decide whether or not order is important; by discarding order, a sequence serves as a set or bag.)

Language Mapping

Default Mapping

Here is the definition of our FruitPlatter sequence once more:

Slice
SLICE
sequence<Fruit> FruitPlatter;

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

CPP
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:

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

Customizing the Sequence Mapping with cpp:type 

The cpp:type:c++-type metadata directive allows you to map a given Slice type, field or parameter to the C++ type of your choice. 

For example, you can override the default mapping of a Slice sequence type:

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 Slice sequence now maps to a C++ std::list instead of the default std::vector:

CPP
#include <list>

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

    // ...
}

The Slice to C++ compiler takes the string following the cpp:type: prefix as the name of the mapped C++ type. For example, we could use ["cpp:type:::std::list<::Food::Fruit>"]. In that case, the compiler would use a fully-qualified name to define the type:

CPP
using FruitPlatter = ::std::list<::Food::Fruit>;

Note that the code generator inserts whatever string you specify following the cpp:type: prefix literally into the generated code. We recommend you use fully qualified names to avoid C++ compilation failures due to unknown symbols.

Also note that, to avoid compilation errors in the generated code, you must instruct the compiler to generate an appropriate include directive with the cpp:include file metadata directive. This causes the compiler to add the line

CPP
#include <list>

to the generated header file.

In addition to modifying the type of a sequence itself, you can also modify the mapping for particular return values or parameters. For example:

SLICE
[["cpp:include:list"]]
[["cpp:include:deque"]]

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

    sequence<Fruit> FruitPlatter;

    interface Market
    {
        ["cpp:type:list<::Food::Fruit>"]
        FruitPlatter barter(["cpp:type:deque<::Food::Fruit>"] FruitPlatter offer);
    }
}

With this definition, the default mapping of FruitPlatter to a C++ vector still applies but the return value of barter is mapped as a list, and the offer parameter is mapped as a deque.

Instead of std::list or std::deque, you can specify a type of your own as the sequence type, for example:

SLICE
[["cpp:include:FruitBowl.h"]]

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

    ["cpp:type:FruitBowl"]
    sequence<Fruit> FruitPlatter;
}

With these metadata directives, the compiler will use a C++ type FruitBowl as the sequence type, and add an include directive for the header file FruitBowl.h to the generated code.

The class or template class you provide must meet the following requirements:

  • The class must have a default constructor.

  • The class must have a copy constructor.

If you use a class that also meets the following requirements

  • The class has a single-argument constructor that takes the size of the sequence as an argument of unsigned integral type.

  • The class has a member function size that returns the number of elements in the sequence as an unsigned integral type.

  • The class provides a member function swap that swaps the contents of the sequence with another sequence of the same type.

  • The class defines iterator and const_iterator types and provides begin and end member functions with the usual semantics; its iterators are comparable for equality and inequality.

then you do not need to provide code to marshal and unmarshal your custom sequence – Ice will do it automatically.

Less formally, this means that if the provided class looks like a vectorlist, or deque with respect to these points, you can use it as a custom sequence implementation without any additional coding.

Span Mapping for Sequence Parameters

When you give a sequence parameter to Ice for marshaling, this parameter is passed by const reference. Take for example:

NONE
sequence<int> IntSeq;

interface Collector
{
    void reportValues(IntSeq values);
}

With the default mapping, the proxy functions look like:

CPP
using IntSeq = std::vector<std::int32_t>;

class CollectorPrx : ...
{
public:
    void reportValues(const IntSeq& values, ...);
};

You can change this default mapping for “outgoing” parameters to a std::span with the metadata directive ["cpp:view-type:std::span<const T>”] (or ["cpp:view-type:std::span<T>”]) where T is the mapped element type.

With our example above:

CODE
void reportValues(["cpp:view-type:std::span<const std::int32_t>"] IntSeq values);

changes the mapping to:

CPP
void reportValues(std::span<const std::int32_t> values, ...);

This span mapping can help reduce copies in the caller.

std::span requires C++20.

Array Mapping for Sequence Parameters

In addition to the default and custom mappings of sequence types as a whole, you can use metadata ["cpp:array"] to map a single operation parameter of type sequence to a pair of pointers.

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 runtime to AMI callbacks

  • Out and return parameters provided to marshaled results or AMD callbacks

The ["cpp:array"] metadata affects many more parameters than the span mapping described earlier.

 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:

CPP
void write(
    const std::pair<const std::byte*, const std::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:

CPP
virtual void write(
    std::pair<const std::byte*, const std::byte*> contents, 
    const Ice::Current& 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 when receiving a request; this allows the runtime 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 when you enable unaligned reads by defining ICE_UNALIGNED.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.