# Using Sequences in C++

As explained in the User's Guide page, a sequence is an unbounded array of eXtremeDB-supported scalar data elements. The C++ Sequence class is used together with the generated C API `classname_fieldname_*()` functions in C++ applications to manage database fields of type sequence. As sequences are effectively vectors of values, they are accessed through iterators. Whereas the C type `mco_seq_iterator_h` is used in C applications, the C++ class Sequence serves the equivalent role in C++ applications. The Sequence class provides a powerful set of Analytics Methods for performing mathematical and statistical operations on sequences.

## Inserting and Updating Sequences

> Normally sequence data is inserted using the generated C API `classname_fieldname_append()`. For example consider the following schema definition:

>         #define uint4 unsigned<4>

>         class Quote {
>             char<16>            symbol;
>             sequence<uint4 asc> day;
>             sequence<float>     price;

>             tree<symbol> by_symbol;
>         };

> With this class definition, the Quote sequence fields `day` and `price` can be populated with code like the following:

>         #define  N_ITEMS                4
>         uint4 days[N_ITEMS] = { 1, 2, 4, 5 };
>         float prices[N_ITEMS] = { 10, 20, 40 ,50 };
>         ...
>         Quote q;
>         q.create(t);
>         q.symbol_put("IBM", (uint2)(strlen("IBM")));
>         q.day_append(days, N_ITEMS);
>         ...
>         q.price_append(prices, N_ITEMS);

> It may sometimes be necessary to insert values into an ordered time series. Values can be inserted into an existing sequence using the generated C API <classname>_<fieldname>_insert(). For example, the following code snippet searches for the Quote object with symbol "`IBM`", then inserts `day` and `price` values:

>         #define  DAY_THREE              3
>         #define  DAY_THREE_PRICE        30
>         uint4 day_to_insert[1] = { DAY_THREE };
>         float price_to_insert[1] = { DAY_THREE_PRICE };
>         ...
>         mco_trans_h     t;
>         mco_cursor_t    cur;
>         ...
>         mco_trans_start(db, MCO_READ_WRITE, MCO_TRANS_FOREGROUND, &t);
>         mco_cursor_first(t, &cur);
>         rc = Quote::by_symbol::cursor(t, &cur);
>         if (MCO_S_OK == rc)
>         {
>             rc = Quote::by_symbol::search(t, &cur, MCO_GE, "IBM",
>                             (uint2)(sizeof("IBM")));
>             if (MCO_S_OK == rc)
>             {
>                 //insert here
>                 Quote q;
>                 q.create(t);

>                 rc = q.from_cursor(t, &cur);
>                 Sequence<uint4> seq = q.day_iterator();
>                 if (MCO_S_OK == rc)
>                 {
>                     rc = q.day_search(seq,
>                                 DAY_THREE, MCO_SEQ_BOUNDARY_EXCLUSIVE,
>                                 0, MCO_SEQ_BOUNDARY_OPEN);
>                     mco_seq_no_t pos = seq.iter->first_seq_no;
>                     rc = q.day_insert(pos, day_to_insert, 1);
>                     ...
>                     rc = q.price_insert(pos, price_to_insert, 1);
>                     rc = mco_trans_commit(t);
>                 }
>             }
>         }

> ## Iterating Sequences

> Normally sequence data is iterated using the Sequence method `next()`. For example, the Quote sequence fields `day` and `price` can be iterated with code like the following:

>         mco_trans_h trans;
>         MCO_RET rc;
>         ...
>         mco_trans_start(db, MCO_READ_ONLY, MCO_TRANS_FOREGROUND, &trans);
>         if ( MCO_S_OK == rc )
>         {
>             Sequence<uint4> day_iterator;
>             ...
>             quote.day_search(day_iterator, DMY(1,1,2013), MCO_SEQ_BOUNDARY_INCLUSIVE, DMY(1,4,2013), MCO_SEQ_BOUNDARY_INCLUSIVE));
>             Sequence<float> price_iterator = quote.price_project(day_iterator);

>             /* Iterate day and price sequences */
>             while (day_iterator.next(day))
>             {
>                 printf("%u: %f\n", day, ++price_iterator);
>             }
>             mco_trans_rollback(trans);
>         }

> Note how the `next()` method is used to iterate through the `day` sequence and the convenient ++ operator is used to iterate the `price` sequence.

> ## Using Analytics Methods

> As mentione above, the Sequence class provides a number of Analytics Methods to efficiently manipulate sequence data and perform a variety of statistical operations. For example, the following code snippet demonstrates how to iterate a Grid Aggregate Maximum sequence of Quote `price` values using a generic sequence output function `print_sequence()` (as demonstrated in SDK sample ``samples/native/sequences/api/cpp``):

>         mco_trans_h trans;
>         MCO_RET rc;
>         ...
>         mco_trans_start(db, MCO_READ_ONLY, MCO_TRANS_FOREGROUND, &trans);
>         if ( MCO_S_OK == rc )
>         {
>             /* Iterate through all Quote objects */
>             Quote::by_sym::cursor(trans, &quote_cursor);
>             for (rc = mco_cursor_first(trans, &quote_cursor);
>                 rc != MCO_S_CURSOR_END;
>                 rc = mco_cursor_next(trans, &quote_cursor))
>             {
>                 /* Get current Quote object */
>                 quote.from_cursor(trans, &quote_cursor);

>                 /* Print the Grid Aggregate sequence for price */
>                 print_sequence(quote, quote.price_iterator().gridAggMax(7));
>             }
>             mco_trans_rollback(trans);
>         }

> Note that the C type ``sequence_iterator`` returned by generated function `quote.price_iterator()` is converted to a C++ Sequence and its method `gridAggMax()` is invoked in the call to function `print_sequence()`. This Sequence is then iterated and printed out in `print_sequence()`.