cpplinq: range generators and conversion operators

In my previous post I introduced cpplinq, a C++ template library that provides .NET-like query operators for sequences of objects in C++11. In this second installment I will discuss about two things: range generators and range conversion operators. These two sets of operators are ubiquitous in queries.

Range generators

A range generator builds an object that represents the range on which query operators are applied. The library provides several such generators:

  • from_iterators: constructs a range from a pair of iterators
  • from: constructs a range from an STL-like container that provides begin() and end() methods (representing the first and past-the-end elements). This is basically a wrapper on from_iterators operator.
    std::vector<int> numbers;
    auto result = from(numbers);
    result >> for_each([](int i) {std::cout << i << std::endl;});

    This is similar to:

    auto result = from_iterators(numbers.begin(), numbers.end());
  • from_array: constructs a range from an array.
    int numbers[] = {1,2,3,4,5};
    auto result = from_array(numbers);
    result >> for_each([](int i) {std::cout << i << std::endl;});

    This is similar to:

    auto result = from_iterators(arrnumbers, arrnumbers + 5);

In addition to the "from" operators, the library also provides several .NET like range generators:

  • range: generates a range of integral, consecutive numbers, starting with an initial seed and having a specified number of elements.
    auto result = range(10, 90); // creates a range of numbers in the interval [10, 100)
  • repeat: generates a range by repeating a value a given number of times
    auto result = repeat("cpplinq", 10); // creates a range with 10 strings with the value "cpplinq"
  • empty: returns an empty range of a given type
    auto result = empty<customer>(); // creates an empty range of customers

Range conversion operators

A conversion operator folds a range into a container that holds the values of the range. There are several such conversion operators that the library provides.

  • to_vector: creates a std::vector<TValue> from a range, where TValue is the type of the elements of the range.
    auto result = range(1, 10) >> to_vector();
    std::list<int> numbers;
    auto result = from(numbers) >> to_vector(); // transforms a list into a vector
  • to_list: creates a std::list<TValue> from a range, where TValue is the type of the elements of the range.
    auto result = range(1, 10) >> to_list();
  • to_map: creates a std::map<TKey, TValue> from a range. It takes a predicate that selects the value to use as the key for each element of the range. It implements a one-to-one dictionary that maps keys to single values.
    // creates a map where key is the customer ID, and the value is the customer object
    auto result = from_array (customers) >> to_map ([](customer const & c){return c.id;});
  • to_lookup: creates a cpplinq::lookup<TKey, TElement> from a sequence. It implements a one-to-many dictionary that maps keys to sequences of values.
    customer_address customer_addresses[] =
       customer_address (2, 4, "Finland"   ),
       customer_address (3, 4, "USA"       ),
       customer_address (1, 1, "USA"       ),
    auto lookup = from_array (customer_addresses) 
               >> to_lookup ([] (customer_address const & ca){return ca.customer_id;}); 
    auto countries = lookup[4] 
                  >> select([](customer_address const & ca) {return ca.country;}) 
                  >> to_vector();  // yields {"Finland", "USA"}

4 Replies to “cpplinq: range generators and conversion operators”

  1. Hi Marius, just wanted to first of all thank you for sharing this library online. Couple of questions: are you still doing any development on it? Also I was taking a look at the source posted on github and one take away is that it is quite hard to follow through file with 5K+ lines of code. Wondering how you felt about splitting it? I am working on such a thing maybe I can send you a pull request?

  2. First of all, I would like to encourage you to bring such issues on the library page.

    Second, is there some missing feature you’d like to have it added?

    And third, the idea was that the whole library would be a single file for ease of deployment. As a user you shouldn’t care what’s inside the library, you should only care about what operators are available and that they work as expected. But for the library developer, yes it might be a bit cumbersome to browse and edit a single file.

  3. I dont have any feature request per se, the library as it stands seems pretty complete, been playing around with it a bit. Just a comment on the splitting up the header file which I think would make library development/collaboration easier (…could always have a script create the amalgamation file for deployment).

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.