cpplinq: An introduction

cpplinq is a C++ template library that provides .NET-like query operators for sequences of objects in C++11. cpplinq is an open-source library that works both with VC++ compilers (2010 and 2012) and gcc (4.7.0 is the version used for unit tests). The library supports most of the .NET query operators and is extendable with additional operators that can suite some particular use. If you’re not familiar with .NET query operators, this article, http://msdn.microsoft.com/en-us/library/bb394939.aspx, lists and explain them.

The light-weighted library consists of a series of template classes and helper methods, provided in a single header under the namespace cpplinq.

This is a short introduction to the library. More posts will follow. Let’s see some examples.

The following code retrieves all the prime numbers from an array.

auto is_prime = [](int i) -> bool 
{
    if (i < 2) { return false; }
    else if (i == 2) { return true; }
    else
    {
        auto r = (int)std::ceil (std::sqrt (i));
        for (auto iter = 2; iter <= r; ++iter)
        {
            if (i % iter == 0) { return false; }
        }
        return true;
    }
};

int numbers[] = {1,2,3,4,5,6,7,8,9};
auto primes = from_array(numbers)
           >> where(is_prime)
           >> to_vector(); // yields {2,3,5,7}

A slightly variation produces a sequence of first N prime numbers and transforms them into strings.

std::vector<string> primes_as_strings(int n)
{
    auto primes = range(0, INT_MAX)
               >> where(is_prime)
               >> take(n)
               >> select([](int i) {std::stringstream s; s << i; return s.str();})
               >> to_vector();

   return primes;
}

The next sample retrieves all the orders from a customer.

struct order 
{
    std::size_t id;
    std::size_t customer_id;
    time_t      date;

    order(std::size_t id, std::size_t cid, time_t date):
        id(id), customer_id(cid), date(date)
    {
    }
};

struct order_line 
{
    std::size_t id;
    std::size_t order_id;
    std::size_t article_id;
    double      quantity;

    order_line(std::size_t id, std::size_t oid, std::size_t aid, double quantity):
        id(id), order_id(oid), article_id(aid), quantity(quantity)
    {
    }
};

order orders[] = 
{
    order(1, 1, time(NULL)),
    order(2, 2, time(NULL)),
    order(3, 1, time(NULL)),
};

order_line orderlines [] = 
{
    order_line(1, 1, 100, 1.0),
    order_line(2, 1, 101, 5.0),
    order_line(3, 1, 102, 2.0),
    order_line(4, 2, 400, 1.0),
    order_line(5, 3, 401, 1.0),
};

void print_orders_by_cust(std::size_t custid)
{
    auto result = from_array(orders)
               >> where([=](order const & o) {return o.customer_id == custid;})
               >> join(from_array(orderlines),
                        [](order const & o) {return o.id;},
                        [](order_line const & ol) {return ol.order_id;},
                        [](order const & o, order_line const & ol) {return std::make_pair(o, ol);});

    result >> for_each([](std::pair<order, order_line> const & p){
        std::cout << "order=" << p.first.id << ", " << ctime(&(p.first.date)) 
                  << "  article=" << p.second.article_id << ", quantity=" << p.second.quantity << std::endl; 
    });
}

Callinq print_orders_by_cust() with argument 1 would print:

order=1, Tue Oct 23 19:22:14 2012
  article=100, quantity=1
order=1, Tue Oct 23 19:22:14 2012
  article=101, quantity=5
order=1, Tue Oct 23 19:22:14 2012
  article=102, quantity=2
order=3, Tue Oct 23 19:23:22 2012
  article=401, quantity=1

On the other hand, if you want to print the last order from a particular customer, the function above would change to something like this:

void print_last_order_for_customer(std::size_t custid)
{
    auto result = from_array(orders)
               >> where([=](order const & o) {return o.customer_id == custid;})
               >> orderby_descending([](order const & o) {return o.date;})
               >> take(1)
               >> join(from_array(orderlines),
                        [](order const & o) {return o.id;},
                        [](order_line const & ol) {return ol.order_id;},
                        [](order const & o, order_line const & ol) {return std::make_pair(o, ol);});

    result >> for_each([](std::pair<order, order_line> const & p){
        std::cout << "order=" << p.first.id << ", " << ctime(&(p.first.date)) 
                  << "  article=" << p.second.article_id << ", quantity=" << p.second.quantity << std::endl; 
    });
}

Calling print_last_order_for_customer() with argument 1 would print:

order=3, Tue Oct 23 19:23:22 2012
  article=401, quantity=1

Hopefully this provides a quick view over the capabilities of the library. In following posts I will show more examples and discuss some of the query operators. To learn more about the library see the following articles:

2 Replies to “cpplinq: An introduction”

Leave a Reply

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