C++/WinRT: Creating Collections Simply and Efficiently

Previous: Coroutines and the Calling Context

A question recently came up on an internal alias about how to create a WinRT collection, specifically an IVectorView, to represent some allocation of floating point values. Here’s my response. It illustrates how C++/WinRT helps you to create collections very efficiently and with very little effort. WinRT collections are rather complicated internally. C++/WinRT takes all of that complexity out of your hands, saving you a lot of time and effort.

I highly recommend using a std::vector for your data storage. You can then create an IVectorView quite simply:

std::vector<float> values{ 0.1f, 0.2f, 0.3f };
IVectorView<float> view = single_threaded_vector(std::move(values)).GetView();

for (auto&& value : view)
{
    printf("%.2f\n", value);
}

This is very efficient and avoids copies. If you need complete flexibility, you can implement IVectorView and IIterable yourself:

struct Sample : 
    implements<Sample, IVectorView<float>, IIterable<float>>
{
    float GetAt(uint32_t const index);
    uint32_t Size();
    bool IndexOf(float value, uint32_t& index);
    uint32_t GetMany(uint32_t startIndex, array_view<float> values) const;

    IIterator<float> First() const;
};

IVectorView<float> view = make<Sample>();

If you need a bit of help you can use the collection base classes (in RS5) to implement those interfaces:

struct Sample : 
    implements<Sample, IVectorView<float>, IIterable<float>>,
    vector_view_base<Sample, float>
{
    auto& get_container() const noexcept
    {
        return m_values;
    }

    std::vector<float> m_values{ 0.1f, 0.2f, 0.3f };
};

You can also return a custom container if you really don’t want to use std::vector:

struct Sample : 
    implements<Sample, IVectorView<float>, IIterable<float>>,
    vector_view_base<Sample, float>
{
    auto get_container() const noexcept
    {
        struct container
        {
            float const* const first;
            float const* const last;

            auto begin() const noexcept
            {
                return first;
            }

            auto end() const noexcept
            {
                return last;
            }
        };

        return container{ m_values.data(), m_values.data() + m_values.size() };
    }

    std::array<float, 3> m_values{ 0.2f, 0.3f, 0.4f };
};

Additional collection base classes exist for all of the generic collections in the Windows Runtime. There are also a number of cool features that the collection base classes offer for customizing the implementation and I’ll explore those in a future article. You can also learn more about this in our recent talk at Build 2018 where Brent and I introduced many of the productivity improvements in the version of C++/WinRT that ships with the Windows SDK as well as the Visual Studio extension for C++/WinRT that makes it a lot easier to get started with a new project.