• Stars
    star
    304
  • Rank 137,274 (Top 3 %)
  • Language
    C++
  • License
    Other
  • Created over 12 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Range-based for loops to iterate over a range of numbers or values

Re-imagining the for loop

C++11 now knows two distinct types of for loops: the classic loop over an “index” and the range-based for loop which vastly simplifies the iteration over a range specified by a pair of iterators.

By contrast, Python knows only one loop type – roughly equivalent to the range-based for loop. In fact, loops over indices are exceedingly rare, but made possible by the use of the range method:

for i in range(10):
    print i

Which does what it promises – although Python version < 3.0 does the “wrong” thing and actually instantiates the whole collection in memory at once; a remedy is xrange which yields values lazily as they are consumed by the loop.

C++11 effortlessly allows the same but there is no standard library function to provide this. Boost.Range provides part of the functionality via irange which only works on integers, and not for unlimited ranges (this will make sense in a second).

The header range.hpp provides a very basic implementation for this. It allows running the following code:

for (auto i : range(1, 5))
    cout << i << "\n";

for (auto u : range(0u))
    if (u == 3u) break;
    else         cout << u << "\n";

for (auto c : range('a', 'd'))
    cout << c << "\n";

for (auto i : range(100).step(-3))
    if (i < 90) break;
    else        cout << i << "\n";

range with a single argument deviates from the Python semantic and creates an endless loop, unless it’s interrupted manually. This is an interesting use-case that cannot be modelled in Python using range.

Iterating over container indices

In Python, the one-argument version of range is often used to iterate over the indices of a container via range(len(container)). Because that overload creates an infinite range in our C++ library, we cannot use this idiom.

But we can do better anyway. For those few cases where we actually want to iterate over a container’s indices, we just use the indices function:

std::vector<int> x{1, 2, 3};
for (auto i : indices(x))
    cout << i << '\n';

This works as expected for any type which has a member function size() const that returns some integral type. It also works with initializer_lists and C-style fixed-size arrays.1

Adding .step(…) to the end of either range or indices specifies a step size instead of the default, 1.

The construct works for arbitrary types which fulfil the interface requirements (incrementing, copying, equality comparison, default construction in the case of infinite ranges).

1 This includes string literals, which are C-style strings that include null termination; this may lead to surprising results, because indices("test") results in 0, 1, 2, 3, 4, whereas indices(std::string{"test"}) results in 0, 1, 2, 3.

Performance (the cost of beauty)

When compiling with optimisations enabled (and why wouldn’t you?), using the range function yield very similar output compared with a manual for loop. In fact, on g++ 4.8 with -O2 or higher, the following two loops yield identical assembly.

for (int i = 0; i < n; ++i)
    cout << i;

for (int i : range(0, n))
    cout << i;

Even though the range function creates a proxy container and an iterator wrapper, those are completely elided from the resulting code.

☞ Beauty is free.

More Repositories

1

box

Write reusable, composable and modular R code
R
737
star
2

named-operator

Named operators for C++
C++
487
star
3

thesis

My PhD thesis, “Investigating the link between tRNA and mRNA abundance in mammals”
TeX
38
star
4

lisp.cpp

Minimal Lisp implementation in C++, inspired by “lispy”
C++
37
star
5

decorator

R function decorators
R
33
star
6

multifunction

A multicast function type for C++
C++
27
star
7

minimappr

Code minimaps for R
R
19
star
8

hyperlight

Automatically exported from code.google.com/p/hyperlight
PHP
16
star
9

fun

Module for functional programming in R
R
16
star
10

sys

Easily create reusable command line scripts with R
R
13
star
11

example-r-analysis

An example for an R analysis workflow using a Makefile, shell scripts and Knitr
R
12
star
12

trna

tRNA gene regulation downstream analysis
R
8
star
13

cv

Resume
TeX
6
star
14

unpack

Vector unpack assignment syntax for R
R
5
star
15

math-art

R
4
star
16

streampunk

Compiler for a pipe-based stream language to construct complex pipelines
C++
4
star
17

knitr-example

An example of a genomics analysis using knitr
4
star
18

rcane

Miscellaneous R tools that I haven’t had time yet to properly integrate. (deprecated and unmaintained)
R
3
star
19

modules

An alternative module system for R
R
3
star
20

parser-combinators

Parser combinators in R
R
2
star
21

system-setup

Bootstrap a usable system configuration for OS X
Shell
2
star
22

vim-snakemake

Snakemake Vim definitions, copied from https://bitbucket.org/snakemake/snakemake/
Vim Script
2
star
23

.files

My dotfiles repository
Shell
2
star
24

klmr.github.io

My website
JavaScript
2
star
25

switch-r

R version switcher for macOS
Shell
2
star
26

cpp11-raw-ptr

A raw pointer type for C++11
C++
2
star
27

te

Map, quantify and analyse transposable element expression
Makefile
2
star
28

ggplots

Some (different, better) defaults for ggplot2
R
2
star
29

trna-chip-pipeline

Upstream ChIP-seq analysis pipeline for tRNA data
Python
2
star
30

rnaseq-norm

Presentation slides about RNA-seq normalisation methods
Makefile
1
star
31

pichip

Makefile
1
star
32

codons

Analysis of adaptation of translation efficiency by means of codon–anticodon selection
R
1
star
33

bog-2015-poster

Biology of Genomes 2015 poster
PostScript
1
star
34

aka

R
1
star
35

roxydoxy

R
1
star
36

r-dict

R
1
star
37

poly-u

R
1
star
38

royal-jelly

R
1
star