Multi Type Vector

Code Example

Simple use case

The following code demonstrates a simple use case of storing values of double and std::string types in a single container using multi_type_vector.

#include <mdds/multi_type_vector.hpp>
#include <mdds/multi_type_vector_trait.hpp>
#include <iostream>
#include <vector>
#include <string>

using std::cout;
using std::endl;

typedef mdds::multi_type_vector<mdds::mtv::element_block_func> mtv_type;

template<typename _Blk>
void print_block(const mtv_type::value_type& v)
{
    // Each element block has static begin() and end() methods that return
    // begin and end iterators, respectively, from the passed element block
    // instance.
    auto it = _Blk::begin(*v.data);
    auto it_end = _Blk::end(*v.data);

    std::for_each(it, it_end,
        [](const typename _Blk::value_type& elem)
        {
            cout << " * " << elem << endl;
        }
    );
}

int main()
{
    mtv_type con(20); // Initialized with 20 empty elements.

    // Set values individually.
    con.set(0, 1.1);
    con.set(1, 1.2);
    con.set(2, 1.3);

    // Set a sequence of values in one step.
    std::vector<double> vals = { 10.1, 10.2, 10.3, 10.4, 10.5 };
    con.set(3, vals.begin(), vals.end());

    // Set string values.
    con.set(10, std::string("Andy"));
    con.set(11, std::string("Bruce"));
    con.set(12, std::string("Charlie"));

    // Iterate through all blocks and print all elements.
    std::for_each(con.begin(), con.end(),
        [](const mtv_type::value_type& v)
        {
            switch (v.type)
            {
                case mdds::mtv::element_type_numeric:
                {
                    cout << "numeric block of size " << v.size << endl;
                    print_block<mdds::mtv::numeric_element_block>(v);
                }
                break;
                case mdds::mtv::element_type_string:
                {
                    cout << "string block of size " << v.size << endl;
                    print_block<mdds::mtv::string_element_block>(v);
                }
                break;
                case mdds::mtv::element_type_empty:
                    cout << "empty block of size " << v.size << endl;
                    cout << " - no data - " << endl;
                default:
                    ;
            }
        }
    );
}

You’ll see the following console output when you compile and execute this code:

numeric block of size 8
 * 1.1
 * 1.2
 * 1.3
 * 10.1
 * 10.2
 * 10.3
 * 10.4
 * 10.5
empty block of size 2
 - no data -
string block of size 3
 * Andy
 * Bruce
 * Charlie
empty block of size 7
 - no data -
_images/mtv_block_structure.png

Figure depicting the ownership structure between the primary array, blocks, and element blocks.

Each container instance consists of an array of blocks each of which stores type, position, size and data members. In this example code, the type member is referenced to determine its block type and its logical size is determine from the size member. For the numeric and string blocks, their data members, which should point to valid memory addresses of their respective element blocks, are dereferenced to gain access to them in order to print out their contents to stdout inside the print_block function.

Use custom event handlers

It is also possible to define custom event handlers that get called when certain events take place. To define custom event handlers, you need to define either a class or a struct that has the following methods:

  • void element_block_acquired(mdds::mtv::base_element_block* block)
  • void element_block_released(mdds::mtv::base_element_block* block)

as its public methods, then pass it as the second template argument when instantiating your multi_type_vector type. Refer to mdds::multi_type_vector::event_func for the details on when each event handler method gets triggered.

The following code example demonstrates how this all works:

#include <mdds/multi_type_vector.hpp>
#include <mdds/multi_type_vector_trait.hpp>
#include <iostream>

using namespace std;

class event_hdl
{
public:
    void element_block_acquired(mdds::mtv::base_element_block* block)
    {
        cout << "  * element block acquired" << endl;
    }

    void element_block_released(mdds::mtv::base_element_block* block)
    {
        cout << "  * element block released" << endl;
    }
};

typedef mdds::multi_type_vector<mdds::mtv::element_block_func, event_hdl> mtv_type;

int main()
{
    mtv_type db;  // starts with an empty container.

    cout << "inserting string 'foo'..." << endl;
    db.push_back(string("foo"));  // creates a new string element block.

    cout << "inserting string 'bah'..." << endl;
    db.push_back(string("bah"));  // appends to an existing string block.

    cout << "inserting int 100..." << endl;
    db.push_back(int(100)); // creates a new int element block.

    cout << "emptying the container..." << endl;
    db.clear(); // releases both the string and int element blocks.

    cout << "exiting program..." << endl;

    return EXIT_SUCCESS;
}

You’ll see the following console output when you compile and execute this code:

inserting string 'foo'...
  * element block acquired
inserting string 'bah'...
inserting int 100...
  * element block acquired
emptying the container...
  * element block released
  * element block released
exiting program...

In this example, the element_block_acquired handler gets triggered each time the container creates (thus acquires) a new element block to store a value. It does not get called when a new value is appended to a pre-existing element block. Similarly, the element_block_releasd handler gets triggered each time an existing element block storing non-empty values gets deleted. One thing to keep in mind is that since these two handlers pertain to element blocks which are owned by non-empty blocks, and empty blocks don’t own element block instances, creations or deletions of empty blocks don’t trigger these event handlers.

Get raw pointer to element block array

Sometimes you need to expose a pointer to an element block array especially when you need to pass such an array pointer to C API that requires one. You can do this by calling the at method of the element_block template class and taking the memory address of the reference returned by the method. This works since the element block internally just wraps std::vector (or std::deque in case the MDDS_MULTI_TYPE_VECTOR_USE_DEQUE preprocessing macro is defined), and its at method simply exposes vector’s own at method which returns a reference to an element within it.

The following code demonstrates this by exposing raw array pointers to the internal arrays of numeric and string element blocks, and printing their element values directly from these array pointers.

#include <mdds/multi_type_vector.hpp>
#include <mdds/multi_type_vector_trait.hpp>
#include <iostream>

using namespace std;
using mdds::mtv::numeric_element_block;
using mdds::mtv::string_element_block;

typedef mdds::multi_type_vector<mdds::mtv::element_block_func> mtv_type;

int main()
{
    mtv_type db;  // starts with an empty container.

    db.push_back(1.1);
    db.push_back(1.2);
    db.push_back(1.3);
    db.push_back(1.4);
    db.push_back(1.5);

    db.push_back(string("A"));
    db.push_back(string("B"));
    db.push_back(string("C"));
    db.push_back(string("D"));
    db.push_back(string("E"));

    // At this point, you have 2 blocks in the container.
    cout << "block size: " << db.block_size() << endl;
    cout << "--" << endl;

    // Get an iterator that points to the first block in the primary array.
    mtv_type::const_iterator it = db.begin();

    // Get a pointer to the raw array of the numeric element block using the
    // 'at' method and taking the address of the returned reference.
    const double* p = &numeric_element_block::at(*it->data, 0);

    // Print the elements from this raw array pointer.
    for (const double* p_end = p + it->size; p != p_end; ++p)
        cout << *p << endl;

    cout << "--" << endl;

    ++it; // move to the next block, which is a string block.

    // Get a pointer to the raw array of the string element block.
    const string* pz = &string_element_block::at(*it->data, 0);

    // Print out the string elements.
    for (const string* pz_end = pz + it->size; pz != pz_end; ++pz)
        cout << *pz << endl;

    return EXIT_SUCCESS;
}

Compiling and execute this code produces the following output:

block size: 2
--
1.1
1.2
1.3
1.4
1.5
--
A
B
C
D
E

Performance Considerations

Use of position hint to avoid expensive block position lookup

Consider the following example code:

typedef mdds::multi_type_vector<mdds::mtv::element_block_func> mtv_type;

size_t size = 50000;

// Initialize the container with one empty block of size 50000.
mtv_type db(size);

// Set non-empty value at every other logical position from top down.
for (size_t i = 0; i < size; ++i)
{
    if (i % 2)
        db.set<double>(i, 1.0);
}

which, when executed, takes quite sometime to complete. This particular example exposes one weakness that multi_type_vector has; because it needs to first look up the position of the block to operate with, and that lookup always starts from the first block, the time it takes to find the correct block increases as the number of blocks goes up. This example demonstrates the worst case scenario of such lookup complexity since it always inserts the next value at the last block position.

Fortunately, there is a simple solution to this which the following code demonstrates:

typedef mdds::multi_type_vector<mdds::mtv::element_block_func> mtv_type;

size_t size = 50000;

// Initialize the container with one empty block of size 50000.
mtv_type db(size);
mtv_type::iterator pos = db.begin();

// Set non-empty value at every other logical position from top down.
for (size_t i = 0; i < size; ++i)
{
    if (i % 2)
        // Pass the position hint as the first argument, and receive a new
        // one returned from the method for the next call.
        pos = db.set<double>(pos, i, 1.0);
}

Compiling and executing this code should take only a fraction of a second.

The only difference between the second example and the first one is that the second one uses an interator as a position hint to keep track of the position of the last modified block. Each set method call returns an iterator which can then be passed to the next set call as the position hint. Because an iterator object internally stores the location of the block the value was inserted to, this lets the method to start the block position lookup process from the last modified block, which in this example is always one block behind the one the new value needs to go. Using the big-O notation, the use of the position hint essentially turns the complexity of O(n^2) in the first example into O(1) in the second one.

This strategy should work with any methods in multi_type_vector that take a position hint as the first argument.

API Reference

struct mdds::detail::mtv_event_func

Empty event function handler structure, used when no custom function handler is specified.

See
mdds::multi_type_vector

Public Functions

void element_block_acquired(const mdds::mtv::base_element_block *)
void element_block_released(const mdds::mtv::base_element_block *)
template <typename _ElemBlockFunc, typename _EventFunc = detail::mtv_event_func>
class mdds::multi_type_vector

Multi-type vector consists of a series of one or more blocks, and each block may either be empty, or stores a series of non-empty elements of identical type. These blocks collectively represent a single logical one-dimensional array that may store elements of different types. It is guaranteed that the block types of neighboring blocks are always different.

Structurally, the primary array stores block instances whose types are of value_type, which in turn consists of the following data members:

  • type which indicates the block type,
  • position which stores the logical position of the first element of the block,
  • size which stores the logical size of the block, and
  • data which stores the pointer to a secondary array (a.k.a. element block) which stores the actual element values, or nullptr in case the block represents an empty segment.

See
mdds::multi_type_vector::value_type

Public Types

typedef size_t size_type
typedef mdds::mtv::base_element_block element_block_type
typedef mdds::mtv::element_t element_category_type
typedef _ElemBlockFunc element_block_func
typedef _EventFunc event_func

Optional event handler function structure, whose functions get called at specific events. The following events are currently supported:

  • element_block_acquired - this gets called whenever the container acquires a new element block either as a result of a new element block creation or a tranfer of an existing element block from another container.
  • element_block_released - this gets called whenever the container releases an existing element block either because the block gets deleted or gets transferred to another container.

See
mdds::detail::mtv_event_func for the precise function signatures of the event handler functions.

typedef __mtv::iterator_base<iterator_trait, itr_forward_update> iterator
typedef __mtv::iterator_base<reverse_iterator_trait, itr_no_update> reverse_iterator
typedef __mtv::const_iterator_base<const_iterator_trait, itr_forward_update, iterator> const_iterator
typedef __mtv::const_iterator_base<const_reverse_iterator_trait, itr_no_update, reverse_iterator> const_reverse_iterator
typedef itr_node value_type

value_type is the type of a block stored in the primary array. It consists of the following data members:

  • type which indicates the block type,
  • position which stores the logical position of the first element of the block,
  • size which stores the logical size of the block, and
  • data which stores the pointer to a secondary array (a.k.a. element block) which stores the actual element values, or nullptr in case the block represents an empty segment.

typedef std::pair<iterator, size_type> position_type
typedef std::pair<const_iterator, size_type> const_position_type

Public Functions

iterator begin()
iterator end()
const_iterator begin() const
const_iterator end() const
reverse_iterator rbegin()
reverse_iterator rend()
const_reverse_iterator rbegin() const
const_reverse_iterator rend() const
event_func &event_handler()
const event_func &event_handler() const
multi_type_vector()

Default constructor. It initializes the container with empty size.

multi_type_vector(const event_func &hdl)

Constructor that takes an lvalue reference to an event handler object. The event handler instance will be copy-constructed.

Parameters
  • hdl -

    lvalue reference to an event handler object.

multi_type_vector(event_func &&hdl)

Constructor that takes an rvalue reference to an event handler object. The event handler instance will be move-constructed.

Parameters
  • hdl -

    rvalue reference to an event handler object.

multi_type_vector(size_type init_size)

Constructor that takes initial size of the container. When the size specified is greater than 0, it initializes the container with empty elements.

Parameters
  • init_size -

    initial container size.

template <typename _T>
multi_type_vector(size_type init_size, const _T &value)

Constructor that takes initial size of the container and an element value to initialize the elements to. When the size specified is greater than 0, it initializes the container with elements that are copies of the value specified.

Parameters
  • init_size -

    initial container size.

  • value -

    initial element value.

template <typename _T>
multi_type_vector(size_type init_size, const _T &it_begin, const _T &it_end)

Constructor that takes initial size of the container and begin and end iterator positions that specify a series of elements to initialize the container to. The container will contain copies of the elements specified after this call returns.

Parameters
  • init_size -

    initial container size.

  • it_begin -

    iterator that points to the begin position of the values the container is being initialized to.

  • it_end -

    iterator that points to the end position of the values the container is being initialized to. The end position is not inclusive.

multi_type_vector(const multi_type_vector &other)

Copy constructor.

Parameters
  • other -

    other column instance to copy values from.

~multi_type_vector()

Destructor. It deletes all allocated data blocks.

template <typename _T>
iterator set(size_type pos, const _T &value)

Set a value of an arbitrary type to a specified position. The type of the value is inferred from the value passed to this method. The new value will overwrite an existing value at the specified position position if any.

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Calling this method will not change the size of the container.

Return
iterator position pointing to the block where the value is inserted.
Parameters
  • pos -

    position to insert the value to.

  • value -

    value to insert.

template <typename _T>
iterator set(const iterator &pos_hint, size_type pos, const _T &value)

Set a value of an arbitrary type to a specified position. The type of the value is inferred from the value passed to this method. The new value will overwrite an existing value at the specified position position if any.

This variant takes an iterator as an additional parameter, which is used as a block position hint to speed up the lookup of the right block to insert the value into. The other variant that doesn’t take an iterator always starts the block lookup from the first block, which does not scale well as the block size grows.

This position hint iterator must precede the insertion position to yield any performance benefit.

The caller is responsible for ensuring that the passed iterator is valid. The behavior of this method when passing an invalid iterator is undefined.

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Calling this method will not change the size of the container.

Return
iterator position pointing to the block where the value is inserted.
Parameters
  • pos_hint -

    iterator used as a block position hint, to specify which block to start when searching for the right block to insert the value into.

  • pos -

    position to insert the value to.

  • value -

    value to insert.

template <typename _T>
iterator set(size_type pos, const _T &it_begin, const _T &it_end)

Set multiple values of identical type to a range of elements starting at specified position. Any existing values will be overwritten by the new values.

The method will throw an std::out_of_range exception if the range of new values would fall outside the current container range.

Calling this method will not change the size of the container.

Return
iterator position pointing to the block where the value is inserted. When no value insertion occurs because the value set is empty, the end iterator position is returned.
Parameters
  • pos -

    position of the first value of the series of new values being inserted.

  • it_begin -

    iterator that points to the begin position of the values being set.

  • it_end -

    iterator that points to the end position of the values being set.

template <typename _T>
iterator set(const iterator &pos_hint, size_type pos, const _T &it_begin, const _T &it_end)

Set multiple values of identical type to a range of elements starting at specified position. Any existing values will be overwritten by the new values.

This variant takes an iterator as an additional parameter, which is used as a block position hint to speed up the lookup of the first insertion block. The other variant that doesn’t take an iterator always starts the block lookup from the first block, which does not scale well as the block size grows.

This position hint iterator must precede the insertion position to yield any performance benefit.

The caller is responsible for ensuring that the passed iterator is valid. The behavior of this method when passing an invalid iterator is undefined.

The method will throw an std::out_of_range exception if the range of new values would fall outside the current container range.

Calling this method will not change the size of the container.

Return
iterator position pointing to the block where the value is inserted. When no value insertion occurs because the value set is empty, the end iterator position is returned.
Parameters
  • pos_hint -

    iterator used as a block position hint, to specify which block to start when searching for the right block to insert the value into.

  • pos -

    position of the first value of the series of new values being inserted.

  • it_begin -

    iterator that points to the begin position of the values being set.

  • it_end -

    iterator that points to the end position of the values being set.

template <typename _T>
iterator push_back(const _T &value)

Append a new value to the end of the container.

Return
iterator position pointing to the block where the value is appended, which in this case is always the last block of the container.
Parameters
  • value -

    new value to be appended to the end of the container.

iterator push_back_empty()

Append a new empty element to the end of the container.

Return
iterator position pointing to the block where the new empty element is appended, which in this case is always the last block of the container.

template <typename _T>
iterator insert(size_type pos, const _T &it_begin, const _T &it_end)

Insert multiple values of identical type to a specified position. Existing values that occur at or below the specified position will get shifted after the insertion. No existing values will be overwritten by the inserted values.

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Calling this method will increase the size of the container by the length of the new values inserted.

Return
iterator position pointing to the block where the value is inserted. When no value insertion occurs because the value set is empty, the end iterator position is returned.
Parameters
  • pos -

    position at which the new values are to be inserted.

  • it_begin -

    iterator that points to the begin position of the values being inserted.

  • it_end -

    iterator that points to the end position of the values being inserted.

template <typename _T>
iterator insert(const iterator &pos_hint, size_type pos, const _T &it_begin, const _T &it_end)

Insert multiple values of identical type to a specified position. Existing values that occur at or below the specified position will get shifted after the insertion. No existing values will be overwritten by the inserted values.

This variant takes an iterator as an additional parameter, which is used as a block position hint to speed up the lookup of the first insertion block. The other variant that doesn’t take an iterator always starts the block lookup from the first block, which does not scale well as the block size grows.

This position hint iterator must precede the insertion position to yield any performance benefit.

The caller is responsible for ensuring that the passed iterator is valid. The behavior of this method when passing an invalid iterator is undefined.

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Calling this method will increase the size of the container by the length of the new values inserted.

Return
iterator position pointing to the block where the value is inserted. When no value insertion occurs because the value set is empty, the end iterator position is returned.
Parameters
  • pos_hint -

    iterator used as a block position hint, to specify which block to start when searching for the right block to insert the value into.

  • pos -

    position at which the new values are to be inserted.

  • it_begin -

    iterator that points to the begin position of the values being inserted.

  • it_end -

    iterator that points to the end position of the values being inserted.

template <typename _T>
void get(size_type pos, _T &value) const

Get the value of an element at specified position. The caller must pass a variable of the correct type to store the value.

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Parameters
  • pos -

    position of the element value to retrieve.

  • value -

    (out) variable to store the retrieved value.

template <typename _T>
_T get(size_type pos) const

Get the value of an element at specified position. The caller must specify the type of the element as the template parameter e.g. get<double>(1).

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Return
element value.
Parameters
  • pos -

    position of the element value to retrieve.

template <typename _T>
_T release(size_type pos)

Return the value of an element at specified position and set that position empty. If the element resides in a managed element block, this call will release that element from that block. If the element is on a non-managed element block, this call is equivalent to set_empty(pos, pos).

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Return
element value.
Parameters
  • pos -

    position of the element to release.

template <typename _T>
iterator release(size_type pos, _T &value)

Retrieve the value of an element at specified position and set that position empty. If the element resides in a managed element block, this call will release that element from that block. If the element is on a non-managed element block, this call is equivalent to set_empty(pos, pos).

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Return
iterator referencing the block where the position of the released element is.
Parameters
  • pos -

    position of the element to release.

  • value -

    element value.

template <typename _T>
iterator release(const iterator &pos_hint, size_type pos, _T &value)

Retrieve the value of an element at specified position and set that position empty. If the element resides in a managed element block, this call will release that element from that block. If the element is on a non-managed element block, this call is equivalent to set_empty(pos, pos).

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Return
iterator referencing the block where the position of the released element is.
Parameters
  • pos -

    position of the element to release.

  • value -

    element value.

void release()

Release all its elements, and empties its content. Calling this method relinquishes the ownership of all elements stored in managed element blocks if any.

This call is equivalent of clear() if the container consists of no managed element blocks.

iterator release_range(size_type start_pos, size_type end_pos)

Make all elements within specified range empty, and relinquish the ownership of the elements in that range. All elements in the managed element blocks within the range will be released and the container will no longer manage their life cycles after the call.

The method will throw an std::out_of_range exception if either the starting or the ending position is outside the current container size.

Return
iterator position pointing to the block where the elements are released.
Parameters
  • start_pos -

    starting position

  • end_pos -

    ending position, inclusive.

iterator release_range(const iterator &pos_hint, size_type start_pos, size_type end_pos)

Make all elements within specified range empty, and relinquish the ownership of the elements in that range. All elements in the managed element blocks within the range will be released and the container will no longer manage their life cycles after the call.

This variant takes an iterator as an additional parameter, which is used as a block position hint to speed up the lookup of the first block to empty. The other variant that doesn’t take an iterator always starts the block lookup from the first block, which does not scale well as the block size grows.

The method will throw an std::out_of_range exception if either the starting or the ending position is outside the current container size.

Return
iterator position pointing to the block where the elements are released.
Parameters
  • pos_hint -

    iterator used as a block position hint, to specify which block to start when searching for the right blocks in which elements are to be released.

  • start_pos -

    starting position

  • end_pos -

    ending position, inclusive.

position_type position(size_type pos)

Given the logical position of an element, get the iterator of the block where the element is located, and its offset from the first element of that block.

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Return
position object that stores an iterator referencing the element block where the element resides, and its offset within that block.
Parameters
  • pos -

    logical position of the element.

position_type position(const iterator &pos_hint, size_type pos)

Given the logical position of an element, get the iterator of the block where the element is located, and its offset from the first element of that block.

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Return
position object that stores an iterator referencing the element block where the element resides, and its offset within that block.
Parameters
  • pos_hint -

    iterator used as a block position hint, to specify which block to start when searching for the element position.

  • pos -

    logical position of the element.

const_position_type position(size_type pos) const

Given the logical position of an element, get an iterator referencing the element block where the element is located, and its offset from the first element of that block.

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Return
position object that stores an iterator referencing the element block where the element resides, and its offset within that block.
Parameters
  • pos -

    position of the element.

const_position_type position(const const_iterator &pos_hint, size_type pos) const

Given the logical position of an element, get an iterator referencing the element block where the element is located, and its offset from the first element of that block.

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Return
position object that stores an iterator referencing the element block where the element resides, and its offset within the block.
Parameters
  • pos_hint -

    iterator used as a block position hint, to specify which block to start when searching for the element position.

  • pos -

    logical position of the element.

iterator transfer(size_type start_pos, size_type end_pos, multi_type_vector &dest, size_type dest_pos)

Move elements from one container to another. After the move, the segment where the elements were in the source container becomes empty. When transferring managed elements, this call transfers ownership of the moved elements to the destination container. The moved elements will overwrite any existing elements in the destination range of the receiving container. Transfer of elements within the same container is not allowed.

The method will throw an std::out_of_range exception if either the starting or the ending position is greater than or equal to the source container size, or the destination container is not large enough to accommodate the transferred elements.

Return
iterator referencing the block where the moved elements were prior to the transfer.
Parameters
  • start_pos -

    starting position

  • end_pos -

    ending position, inclusive.

  • dest -

    destination container to which the elements are to be moved.

  • dest_pos -

    position in the destination container to which the elements are to be moved.

iterator transfer(const iterator &pos_hint, size_type start_pos, size_type end_pos, multi_type_vector &dest, size_type dest_pos)

Move elements from one container to another. After the move, the segment where the elements were in the source container becomes empty. When transferring managed elements, this call transfers ownership of the moved elements to the new container. The moved elements will overwrite any existing elements in the destination range of the receiving container. Transfer of elements within the same container is not allowed.

The method will throw an std::out_of_range exception if either the starting or the ending position is greater than or equal to the source container size, or the destination container is not large enough to accommodate the transferred elements.

Return
iterator referencing the block where the moved elements were prior to the transfer.
Parameters
  • pos_hint -

    iterator used as a block position hint, to specify which block to start when searching for the blocks where the elements to be transferred reside.

  • start_pos -

    starting position

  • end_pos -

    ending position, inclusive.

  • dest -

    destination container to which the elements are to be moved.

  • dest_pos -

    position in the destination container to which the elements are to be moved.

mtv::element_t get_type(size_type pos) const

Get the type of an element at specified position.

Return
element type.
Parameters
  • pos -

    position of the element.

bool is_empty(size_type pos) const

Check if element at specified position is empty of not.

The method will throw an std::out_of_range exception if the specified position is outside the current container range.

Return
true if the element is empty, false otherwise.
Parameters
  • pos -

    position of the element to check.

iterator set_empty(size_type start_pos, size_type end_pos)

Set specified range of elements to be empty. Any existing values will be overwritten.

The method will throw an std::out_of_range exception if either the starting or the ending position is outside the current container size.

Return
iterator position pointing to the block where the elements are emptied.
Parameters
  • start_pos -

    starting position

  • end_pos -

    ending position, inclusive.

iterator set_empty(const iterator &pos_hint, size_type start_pos, size_type end_pos)

Set specified range of elements to be empty. Any existing values will be overwritten.

This variant takes an iterator as an additional parameter, which is used as a block position hint to speed up the lookup of the first block to empty. The other variant that doesn’t take an iterator always starts the block lookup from the first block, which does not scale well as the block size grows.

This position hint iterator must precede the start position to yield any performance benefit.

The caller is responsible for ensuring that the passed iterator is valid. The behavior of this method when passing an invalid iterator is undefined.

The method will throw an std::out_of_range exception if either the starting or the ending position is outside the current container size.

Return
iterator position pointing to the block where the elements are emptied.
Parameters
  • pos_hint -

    iterator used as a block position hint, to specify which block to start when searching for the right blocks to empty.

  • start_pos -

    starting position

  • end_pos -

    ending position, inclusive.

void erase(size_type start_pos, size_type end_pos)

Erase elements located between specified start and end positions. The end positions are both inclusive. Those elements originally located after the specified end position will get shifted up after the erasure.

The method will throw an std::out_of_range exception if either the starting or the ending position is outside the current container range.

Calling this method will decrease the size of the container by the length of the erased range.

Parameters
  • start_pos -

    starting position

  • end_pos -

    ending position, inclusive.

iterator insert_empty(size_type pos, size_type length)

Insert a range of empty elements at specified position. Those elements originally located after the insertion position will get shifted down after the insertion.

The method will throw an std::out_of_range exception if either the specified position is outside the current container range.

Calling this method will increase the size of the container by the length of the inserted empty elements.

Return
iterator position pointing to the block where the empty range is inserted. When no insertion occurs because the length is zero, the end iterator position is returned.
Parameters
  • pos -

    position at which to insert a range of empty elements.

  • length -

    number of empty elements to insert.

iterator insert_empty(const iterator &pos_hint, size_type pos, size_type length)

Insert a range of empty elements at specified position. Those elements originally located after the insertion position will get shifted down after the insertion.

This variant takes an iterator as an additional parameter, which is used as a block position hint to speed up the lookup of the block in which to insert the new empty segment. The other variant that doesn’t take an iterator always starts the block lookup from the first block, which does not scale well as the block size grows.

This position hint iterator must precede the start position to yield any performance benefit.

The caller is responsible for ensuring that the passed iterator is valid. The behavior of this method when passing an invalid iterator is undefined.

The method will throw an std::out_of_range exception if either the specified position is outside the current container range.

Calling this method will increase the size of the container by the length of the inserted empty elements.

Return
iterator position pointing to the block where the empty range is inserted. When no insertion occurs because the length is zero, the end iterator position is returned.
Parameters
  • pos_hint -

    iterator used as a block position hint, to specify which block to start when searching for the right block in which to insert the empty segment.

  • pos -

    position at which to insert a range of empty elements.

  • length -

    number of empty elements to insert.

void clear()

Clear the content of the container. The size of the container will become zero after calling this method.

size_type size() const

Return the current container size.

Return
current container size.

size_type block_size() const

Return the current number of blocks in the primary array. Each non-empty block stores a secondary block that stores elements in a contiguous region in memory (element block) and the number of elements it stores. An empty block only stores its logical size and does not store an actual element block.

For instance, if the container stores values of double-precision type at rows 0 to 2, values of std::string type at 3 to 7, and empty values at 8 to 10, it would consist of three blocks: one that stores double values, one that stores std::string values, and one that represents the empty value range in this exact order. In this specific scenario, block_size() returns 3, and size() returns 11.

Return
current number of blocks in the primary array.

bool empty() const

Return whether or not the container is empty.

Return
true if the container is empty, false otherwise.

void resize(size_type new_size)

Extend or shrink the container. When extending the container, it appends a series of empty elements to the end. When shrinking, the elements at the end of the container get stripped off.

Parameters
  • new_size -

    size of the container after the resize.

void swap(multi_type_vector &other)

Swap the content with another container.

Parameters
  • other -

    another container to swap content with.

void swap(size_type start_pos, size_type end_pos, multi_type_vector &other, size_type other_pos)

Swap a part of the content with another container.

Parameters
  • start_pos -

    starting position

  • end_pos -

    ending position, inclusive.

  • other -

    another container to swap the content with.

  • other_pos -

    insertion position in the other container.

void shrink_to_fit()

Trim excess capacity from all non-empty blocks.

bool operator==(const multi_type_vector &other) const
bool operator!=(const multi_type_vector &other) const
multi_type_vector &operator=(const multi_type_vector &other)

Public Static Functions

static position_type next_position(const position_type &pos)

Move the position object to the next logical position. Caller must ensure the the position object is valid.

Return
position object that points to the next logical position.
Parameters
  • pos -

    position object.

static position_type advance_position(const position_type &pos, int steps)

Increment or decrement the position object by specified steps. Caller must ensure the the position object is valid.

Return
position object that points to the new logical position.
Parameters
  • pos -

    position object.

  • steps -

    steps to advance the position object.

static const_position_type next_position(const const_position_type &pos)

Move the position object to the next logical position. Caller must ensure the the position object is valid.

Return
position object that points to the next logical position.
Parameters
  • pos -

    position object.

static const_position_type advance_position(const const_position_type &pos, int steps)

Increment or decrement the position object by specified steps. Caller must ensure the the position object is valid.

Return
position object that points to the new logical position.
Parameters
  • pos -

    position object.

  • steps -

    steps to advance the position object.

static size_type logical_position(const const_position_type &pos)

Extract the logical position from a position object.

Return
logical position of the element that the position object references.
Parameters
  • pos -

    position object.

template <typename _Blk>
static _Blk::value_type get(const const_position_type &pos)

Get element value from a position object. The caller must specify the type of block in which the element is expected to be stored.

Return
element value.
Parameters
  • pos -

    position object.

template <typename _T>
static mtv::element_t get_element_type(const _T &elem)

Return the numerical identifier that represents passed element.

Return
numerical identifier representing the element.
Parameters
  • elem -

    element value.