[med-svn] [adapterremoval] 01/03: New upstream version 2.2.2

Kevin Murray daube-guest at moszumanska.debian.org
Tue Jul 18 00:01:03 UTC 2017


This is an automated email from the git hooks/post-receive script.

daube-guest pushed a commit to branch master
in repository adapterremoval.

commit 663d1956708fb545a4e76bd9c6acf12fb01dc2ee
Author: Kevin Murray <kdmfoss at gmail.com>
Date:   Tue Jul 18 09:37:39 2017 +1000

    New upstream version 2.2.2
---
 .travis.yml                                        |   1 +
 CHANGES.md                                         |   7 ++
 Makefile                                           |  47 ++------
 README.md                                          |  11 +-
 include/ar/adapterremoval.h                        |  23 ----
 include/ar/adapterremoval.hpp                      |  23 ++++
 src/{adapterset.cc => adapterset.cpp}              |  47 ++++----
 src/{adapterset.h => adapterset.hpp}               |   4 +-
 src/{alignment.cc => alignment.cpp}                |  28 +++--
 src/{alignment.h => alignment.hpp}                 |   2 +-
 src/{argparse.cc => argparse.cpp}                  |  65 +++++-----
 src/{argparse.h => argparse.hpp}                   |  94 +++++++--------
 src/{commontypes.h => commontypes.hpp}             |  16 +--
 src/{debug.cc => debug.cpp}                        |   2 +-
 src/{debug.h => debug.hpp}                         |   0
 src/{demultiplex.cc => demultiplex.cpp}            |  46 +++----
 src/{demultiplex.h => demultiplex.hpp}             |  19 ++-
 src/{fastq.cc => fastq.cpp}                        |  62 +++++-----
 src/{fastq.h => fastq.hpp}                         |   4 +-
 src/{fastq_enc.cc => fastq_enc.cpp}                |  97 +++++++--------
 src/{fastq_enc.h => fastq_enc.hpp}                 |  29 +++--
 src/{fastq_io.cc => fastq_io.cpp}                  |  73 ++++++------
 src/{fastq_io.h => fastq_io.hpp}                   |  74 +++++-------
 src/{linereader.cc => linereader.cpp}              | 132 ++++++---------------
 src/{linereader.h => linereader.hpp}               |  36 ++----
 ...{linereader_joined.cc => linereader_joined.cpp} |   6 +-
 src/{linereader_joined.h => linereader_joined.hpp} |  14 +--
 src/{main.cc => main.cpp}                          |  43 ++++---
 src/{main.h => main.hpp}                           |   2 +-
 src/{main_adapter_id.cc => main_adapter_id.cpp}    |  37 +++---
 src/{main_adapter_rm.cc => main_adapter_rm.cpp}    | 109 ++++++++---------
 src/{main_demultiplex.cc => main_demultiplex.cpp}  |  26 ++--
 src/{scheduler.cc => scheduler.cpp}                |  23 ++--
 src/{scheduler.h => scheduler.hpp}                 |  21 ++--
 src/{statistics.h => statistics.hpp}               |   6 +-
 src/{strutils.cc => strutils.cpp}                  |  14 +--
 src/{strutils.h => strutils.hpp}                   |   0
 src/{threads.cc => threads.cpp}                    |   2 +-
 src/{threads.h => threads.hpp}                     |  10 +-
 src/{timer.cc => timer.cpp}                        |  10 +-
 src/{timer.h => timer.hpp}                         |   0
 src/{trimmed_reads.cc => trimmed_reads.cpp}        |  16 +--
 src/{trimmed_reads.h => trimmed_reads.hpp}         |  27 +++--
 src/{userconfig.cc => userconfig.cpp}              |  93 +++++++--------
 src/{userconfig.h => userconfig.hpp}               |  35 +++---
 src/{vecutils.h => vecutils.hpp}                   |   0
 tests/{alignment_test.cc => alignment_test.cpp}    |  37 +++---
 tests/{argparse_test.cc => argparse_test.cpp}      |  32 ++---
 tests/{testing.h => fastq_enc_test.cpp}            |  30 +++--
 tests/{fastq_test.cc => fastq_test.cpp}            |  41 ++++++-
 tests/{strutils_test.cc => strutils_test.cpp}      |  23 +++-
 tests/{testing.h => testing.hpp}                   |   2 +-
 validation/run                                     |   8 +-
 53 files changed, 776 insertions(+), 833 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index cbc22b9..0b1987f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -25,6 +25,7 @@ script:
     - make
     - make test COVERAGE=yes
     - make validate
+    - PATH=$PATH:$PWD/build/ make -C examples
 
 after_success:
   - coveralls --exclude tests --exclude googletest-release-1.8.0 --gcov-options '\-lp'
diff --git a/CHANGES.md b/CHANGES.md
index dea14bf..b4b42b5 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,4 +1,11 @@
 
+
+### Version 2.2.2 - 2017-07-17
+
+  * Made gzip and bzip2 support mandatory.
+  * Added support for Intel compilers, courtesy of Kevin Murray (kdmurray91).
+
+
 ### Version 2.2.1a - 2017-05-17
 
   * Fixed compilation on OSX.
diff --git a/Makefile b/Makefile
index 22e9315..8939a86 100644
--- a/Makefile
+++ b/Makefile
@@ -10,12 +10,6 @@ CXXFLAGS := ${CXXFLAGS} -std=c++11 -O3
 
 ## Optional features; comment out or set to value other than 'yes' to disable
 
-# Enable reading writing of gzip compressed files using libz.
-GZIP_SUPPORT := yes
-
-# Enable reading writing of bzip2 compressed files using libbz2.
-BZIP2_SUPPORT := yes
-
 # Hide individual commands during build; only shows summaries instead.
 QUIET_BUILD := yes
 
@@ -32,7 +26,7 @@ COVERAGE := no
 # Makefile internals. Normally you do not need to touch these.
 
 # Libraries required by AdapterRemoval
-LIBRARIES := -pthread
+LIBRARIES := -pthread -lz -lbz2
 
 # Build directory; modified depending on build options
 BDIR     := build/main
@@ -49,24 +43,6 @@ COLOR_CYAN := "\033[0;36m"
 COLOR_END := "\033[0m"
 endif
 
-ifeq ($(strip ${GZIP_SUPPORT}),yes)
-$(info Building AdapterRemoval with gzip support: yes)
-CXXFLAGS := ${CXXFLAGS} -DAR_GZIP_SUPPORT
-LIBRARIES := ${LIBRARIES} -lz
-BDIR := ${BDIR}_gz
-else
-$(info Building AdapterRemoval with gzip support: no)
-endif
-
-ifeq ($(strip ${BZIP2_SUPPORT}),yes)
-$(info Building AdapterRemoval with bzip2 support: yes)
-CXXFLAGS := ${CXXFLAGS} -DAR_BZIP2_SUPPORT
-LIBRARIES := ${LIBRARIES} -lbz2
-BDIR := ${BDIR}_bz2
-else
-$(info Building AdapterRemoval with bzip2 support: no)
-endif
-
 ifeq ($(strip ${COVERAGE}), yes)
 $(info Building AdapterRemoval with coverage instrumentation: yes)
 CXXFLAGS := ${CXXFLAGS} --coverage
@@ -149,24 +125,24 @@ install: build/$(PROG) build/$(PROG).1
 static: build/$(LIBNAME).a
 
 # Object files
-$(BDIR)/%.o: src/%.cc
-	@echo $(COLOR_CYAN)"Building '$@' from '$<'"$(COLOR_END)
+$(BDIR)/%.o: src/%.cpp
+	@echo $(COLOR_CYAN)"Building $@ from $<"$(COLOR_END)
 	$(QUIET) mkdir -p $(BDIR)
 	$(QUIET) $(CXX) $(CXXFLAGS) -pthread -c -o $@ $<
 	$(QUIET) $(CXX) $(CXXFLAGS) -w -MM -MT $@ -MF $(@:.o=.deps) $<
 
 # Executable
 build/$(PROG): $(OBJS)
-	@echo $(COLOR_GREEN)"Linking executable '$@'"$(COLOR_END)
+	@echo $(COLOR_GREEN)"Linking executable $@"$(COLOR_END)
 	$(QUIET) $(CXX) $(CXXFLAGS) ${LDFLAGS} $^ ${LIBRARIES} -o $@
 
 # Static library
 build/$(LIBNAME).a: $(LIBOBJS)
-	@echo $(COLOR_GREEN)"Linking static library '$@'"$(COLOR_END)
+	@echo $(COLOR_GREEN)"Linking static library $@"$(COLOR_END)
 	$(AR) rcs build/$(LIBNAME).a $(LIBOBJS)
 
 build/%.1: %.pod
-	@echo $(COLOR_GREEN)"Constructing man-page '$@' from '$<'"$(COLOR_END)
+	@echo $(COLOR_GREEN)"Constructing man-page $@ from $<"$(COLOR_END)
 	$(QUIET) mkdir -p $(BDIR)
 	$(QUIET) pod2man $< > $@
 
@@ -184,8 +160,9 @@ TEST_OBJS := $(TEST_DIR)/alignment.o \
              $(TEST_DIR)/argparse_test.o \
              $(TEST_DIR)/debug.o \
              $(TEST_DIR)/fastq.o \
-             $(TEST_DIR)/fastq_enc.o \
              $(TEST_DIR)/fastq_test.o \
+             $(TEST_DIR)/fastq_enc.o \
+             $(TEST_DIR)/fastq_enc_test.o \
              $(TEST_DIR)/strutils.o \
              $(TEST_DIR)/strutils_test.o
 TEST_DEPS := $(TEST_OBJS:.o=.deps)
@@ -210,23 +187,23 @@ $(TEST_DIR)/main: $(GTEST_LIB) $(TEST_OBJS)
 	$(QUIET) $(CXX) $(CXXFLAGS) ${LIBRARIES} $^ -o $@
 
 $(TEST_DIR)/libgtest.a: $(GTEST_OBJS)
-	@echo $(COLOR_GREEN)"Linking GTest library '$@'"$(COLOR_END)
+	@echo $(COLOR_GREEN)"Linking GTest library $@"$(COLOR_END)
 	$(QUIET) ar -rv $@ $^
 
-$(TEST_DIR)/%.o: tests/%.cc
+$(TEST_DIR)/%.o: tests/%.cpp
 	@echo $(COLOR_CYAN)"Building $@ from $<"$(COLOR_END)
 	$(QUIET) mkdir -p $(TEST_DIR)
 	$(QUIET) $(CXX) $(CXXFLAGS) $(TEST_CXXFLAGS) -c -o $@ $<
 	$(QUIET) $(CXX) $(CXXFLAGS) $(TEST_CXXFLAGS) -w -MM -MT $@ -MF $(@:.o=.deps) $<
 
-$(TEST_DIR)/%.o: src/%.cc
+$(TEST_DIR)/%.o: src/%.cpp
 	@echo $(COLOR_CYAN)"Building $@ from $<"$(COLOR_END)
 	$(QUIET) mkdir -p $(TEST_DIR)
 	$(QUIET) $(CXX) $(CXXFLAGS) $(TEST_CXXFLAGS) -c -o $@ $<
 	$(QUIET) $(CXX) $(CXXFLAGS) $(TEST_CXXFLAGS) -w -MM -MT $@ -MF $(@:.o=.deps) $<
 
 $(TEST_DIR)/gtest%.o: $(GTEST_DIR)/src/gtest%.cc
-	@echo $(COLOR_CYAN)"Building '$@' from '$<'"$(COLOR_END)
+	@echo $(COLOR_CYAN)"Building $@ from $<"$(COLOR_END)
 	$(QUIET) mkdir -p $(TEST_DIR)
 	$(QUIET) $(CXX) $(GTEST_CXXFLAGS) -c $< -o $@
 
diff --git a/README.md b/README.md
index 63b3c83..f045d7f 100644
--- a/README.md
+++ b/README.md
@@ -56,16 +56,7 @@ It is also possible to compile AdapterRemoval as a static library:
     $ sudo make static
 
 
-Note that AdapterRemoval requires that the zlib library and headers (www.zlib.net) are installed, that the bzlib2 library and headers are installed, and that the compiler used supports c++11. Please refer to your operating system documentation for installation instructions. Alternatively, use of these features may be disabled when running 'make':
-
-    # Disable gzip support
-    $ make GZIP_SUPPORT=no
-
-    # Disable bzip2 support
-    $ make BZIP2_SUPPORT=no
-
-    # Disable both gzip and bzip2 support
-    $ make GZIP_SUPPORT=no BZIP2_SUPPORT=no
+Note that AdapterRemoval requires that the zlib library and headers (www.zlib.net) are installed, that the bzlib2 library and headers are installed, and that the compiler used supports c++11. Please refer to your operating system documentation for installation instructions.
 
 
 ## Documentation
diff --git a/include/ar/adapterremoval.h b/include/ar/adapterremoval.h
deleted file mode 100644
index 64e228c..0000000
--- a/include/ar/adapterremoval.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef AR_ADAPTERREMOVAL_H
-#define AR_ADAPTERREMOVAL_H
-
-#include "../../src/adapterset.h"
-#include "../../src/alignment.h"
-#include "../../src/argparse.h"
-#include "../../src/commontypes.h"
-#include "../../src/debug.h"
-#include "../../src/demultiplex.h"
-#include "../../src/fastq_enc.h"
-#include "../../src/fastq.h"
-#include "../../src/fastq_io.h"
-#include "../../src/linereader.h"
-#include "../../src/main.h"
-#include "../../src/scheduler.h"
-#include "../../src/statistics.h"
-#include "../../src/strutils.h"
-#include "../../src/threads.h"
-#include "../../src/timer.h"
-#include "../../src/userconfig.h"
-#include "../../src/vecutils.h"
-
-#endif // AR_ADAPTERREMOVAL_H
diff --git a/include/ar/adapterremoval.hpp b/include/ar/adapterremoval.hpp
new file mode 100644
index 0000000..ecc29c7
--- /dev/null
+++ b/include/ar/adapterremoval.hpp
@@ -0,0 +1,23 @@
+#ifndef AR_ADAPTERREMOVAL_H
+#define AR_ADAPTERREMOVAL_H
+
+#include "../../src/adapterset.hpp"
+#include "../../src/alignment.hpp"
+#include "../../src/argparse.hpp"
+#include "../../src/commontypes.hpp"
+#include "../../src/debug.hpp"
+#include "../../src/demultiplex.hpp"
+#include "../../src/fastq_enc.hpp"
+#include "../../src/fastq.hpp"
+#include "../../src/fastq_io.hpp"
+#include "../../src/linereader.hpp"
+#include "../../src/main.hpp"
+#include "../../src/scheduler.hpp"
+#include "../../src/statistics.hpp"
+#include "../../src/strutils.hpp"
+#include "../../src/threads.hpp"
+#include "../../src/timer.hpp"
+#include "../../src/userconfig.hpp"
+#include "../../src/vecutils.hpp"
+
+#endif // AR_ADAPTERREMOVAL_H
diff --git a/src/adapterset.cc b/src/adapterset.cpp
similarity index 92%
rename from src/adapterset.cc
rename to src/adapterset.cpp
index ff0080a..9d900b3 100644
--- a/src/adapterset.cc
+++ b/src/adapterset.cpp
@@ -26,10 +26,10 @@
 #include <iostream>
 #include <sstream>
 
-#include "adapterset.h"
-#include "debug.h"
-#include "linereader.h"
-#include "strutils.h"
+#include "adapterset.hpp"
+#include "debug.hpp"
+#include "linereader.hpp"
+#include "strutils.hpp"
 
 namespace ar
 {
@@ -228,10 +228,7 @@ bool check_barcodes_sequences(const fastq_pair_vec& barcodes,
 
 bool valid_sample_name(const std::string& name)
 {
-    std::string::const_iterator it = name.begin();
-    for (; it != name.end(); ++it) {
-        const char c = *it;
-
+    for (const char c : name) {
         if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
             (c >= '0' && c <= '9') || (c == '_')) {
             continue;
@@ -263,8 +260,8 @@ bool check_sample_names(const string_vec& names)
         return true;
     }
 
-    for (string_vec_citer it = names.begin(); it != names.end(); ++it) {
-        if (!valid_sample_name(*it)) {
+    for (const auto& name : names) {
+        if (!valid_sample_name(name)) {
             return false;
         }
     }
@@ -324,12 +321,12 @@ bool adapter_set::load_adapters(const std::string& filename, bool paired_end)
         return false;
     }
 
-    for (fastq_table_citer it = raw_adapters.begin(); it != raw_adapters.end(); ++it) {
-        fastq adapter_5p = it->second.at(0);
+    for (const auto& row : raw_adapters) {
+        fastq adapter_5p = row.second.at(0);
         fastq adapter_3p;
 
-        if (it->second.size() > 1) {
-            adapter_3p = it->second.at(1);
+        if (row.second.size() > 1) {
+            adapter_3p = row.second.at(1);
         }
 
         m_adapters.push_back(fastq_pair(adapter_5p, adapter_3p));
@@ -349,15 +346,15 @@ bool adapter_set::load_barcodes(const std::string& filename, bool paired_end)
     m_samples.clear();
     m_barcodes.clear();
 
-    for (fastq_table_citer it = raw_barcodes.begin(); it != raw_barcodes.end(); ++it) {
-        fastq barcode_5p = it->second.at(0);
+    for (const auto& row : raw_barcodes) {
+        fastq barcode_5p = row.second.at(0);
         fastq barcode_3p;
 
-        if (it->second.size() > 1) {
-            barcode_3p = it->second.at(1);
+        if (row.second.size() > 1) {
+            barcode_3p = row.second.at(1);
         }
 
-        m_samples.push_back(it->first);
+        m_samples.push_back(row.first);
         m_barcodes.push_back(fastq_pair(barcode_5p, barcode_3p));
     }
 
@@ -399,9 +396,9 @@ fastq_pair_vec adapter_set::get_adapter_set(size_t nth) const
     barcodes.second.reverse_complement();
 
     fastq_pair_vec adapters;
-    for (fastq_pair_vec::const_iterator it = m_adapters.begin(); it != m_adapters.end(); ++it) {
-        fastq adapter_1("adapter_1", barcodes.second.sequence() + it->first.sequence());
-        fastq adapter_2("adapter_2", it->second.sequence() + barcodes.first.sequence());
+    for (const auto& adapter_pair : m_adapters) {
+        fastq adapter_1("adapter_1", barcodes.second.sequence() + adapter_pair.first.sequence());
+        fastq adapter_2("adapter_2", adapter_pair.second.sequence() + barcodes.first.sequence());
 
         adapters.push_back(fastq_pair(adapter_1, adapter_2));
     }
@@ -421,9 +418,9 @@ string_pair_vec adapter_set::get_pretty_adapter_set(size_t nth) const
 
     string_pair_vec adapters;
     const fastq_pair_vec adapter_pairs = get_adapter_set(nth);
-    for (fastq_pair_vec::const_iterator it = adapter_pairs.begin(); it != adapter_pairs.end(); ++it) {
-        fastq adapter_1 = it->first;
-        fastq adapter_2 = it->second;
+    for (const auto& adapter_pair : adapter_pairs) {
+        fastq adapter_1 = adapter_pair.first;
+        fastq adapter_2 = adapter_pair.second;
         adapter_2.reverse_complement();
 
         std::string seq_1 = adapter_1.sequence();
diff --git a/src/adapterset.h b/src/adapterset.hpp
similarity index 98%
rename from src/adapterset.h
rename to src/adapterset.hpp
index e48f79c..1564f9d 100644
--- a/src/adapterset.h
+++ b/src/adapterset.hpp
@@ -25,8 +25,8 @@
 #ifndef AR_ADAPTERS_H
 #define AR_ADAPTERS_H
 
-#include "commontypes.h"
-#include "fastq.h"
+#include "commontypes.hpp"
+#include "fastq.hpp"
 
 namespace ar
 {
diff --git a/src/alignment.cc b/src/alignment.cpp
similarity index 95%
rename from src/alignment.cc
rename to src/alignment.cpp
index 60a9327..379587c 100644
--- a/src/alignment.cc
+++ b/src/alignment.cpp
@@ -30,9 +30,9 @@
 #include <stdexcept>
 #include <cstring>
 
-#include "alignment.h"
-#include "debug.h"
-#include "fastq.h"
+#include "alignment.hpp"
+#include "debug.hpp"
+#include "fastq.hpp"
 
 namespace ar
 {
@@ -45,6 +45,8 @@ namespace ar
 const __m128i BIT_MASK_128 = _mm_set1_epi8(1);
 //! Zero'd 128b integer.
 const __m128i ZERO_128 = _mm_set1_epi8(0);
+//! A 0xffff... 128b integer.
+const __m128i ONES_128 = _mm_set1_epi8(-1);
 //! Mask of all Ns
 const __m128i N_MASK_128 = _mm_set1_epi8('N');
 
@@ -92,7 +94,11 @@ bool compare_subsequences(const alignment_info& best, alignment_info& current,
                                              _mm_cmpeq_epi8(s2, N_MASK_128));
 
         // Sets 0xFF for every byte where bytes differ, but neither is N
-        const __m128i mm_mask = ~_mm_or_si128(_mm_cmpeq_epi8(s1, s2), ns_mask);
+        const __m128i mm_mask = _mm_xor_si128(ONES_128, // This is a bitwise NOT
+                                              _mm_or_si128(_mm_cmpeq_epi8(s1, s2), ns_mask));
+        // The oddity above is because SSE doesn't have a bitwise not operator, and
+        // `~(some __m128i)` doesn't work on Intel compilers. XOR(thing, 0xff)
+        // is the same, so we use that
 
         current.n_ambiguous += COUNT_BITS_128(_mm_and_si128(ns_mask, BIT_MASK_128));
         current.n_mismatches += COUNT_BITS_128(_mm_and_si128(mm_mask, BIT_MASK_128));
@@ -326,8 +332,8 @@ alignment_info align_single_ended_sequence(const fastq& read,
 {
     size_t adapter_id = 0;
     alignment_info best_alignment;
-    for (fastq_pair_vec::const_iterator it = adapters.begin(); it != adapters.end(); ++it, ++adapter_id) {
-        const fastq& adapter = it->first;
+    for (const auto& adapter_pair : adapters) {
+        const fastq& adapter = adapter_pair.first;
         const alignment_info alignment = pairwise_align_sequences(best_alignment,
                                                                   read.sequence(),
                                                                   adapter.sequence(),
@@ -338,6 +344,8 @@ alignment_info align_single_ended_sequence(const fastq& read,
             best_alignment = alignment;
             best_alignment.adapter_id = adapter_id;
         }
+
+        ++adapter_id;
     }
 
     return best_alignment;
@@ -351,9 +359,9 @@ alignment_info align_paired_ended_sequences(const fastq& read1,
 {
     size_t adapter_id = 0;
     alignment_info best_alignment;
-    for (fastq_pair_vec::const_iterator it = adapters.begin(); it != adapters.end(); ++it, ++adapter_id) {
-        const fastq& adapter1 = it->first;
-        const fastq& adapter2 = it->second;
+    for (const auto& adapter_pair : adapters) {
+        const fastq& adapter1 = adapter_pair.first;
+        const fastq& adapter2 = adapter_pair.second;
 
         const std::string sequence1 = adapter2.sequence() + read1.sequence();
         const std::string sequence2 = read2.sequence() + adapter1.sequence();
@@ -374,6 +382,8 @@ alignment_info align_paired_ended_sequences(const fastq& read1,
             // Convert the alignment into an alignment between read 1 & 2 only
             best_alignment.offset -= adapter2.length();
         }
+
+        ++adapter_id;
     }
 
     return best_alignment;
diff --git a/src/alignment.h b/src/alignment.hpp
similarity index 99%
rename from src/alignment.h
rename to src/alignment.hpp
index 86a893f..5322202 100644
--- a/src/alignment.h
+++ b/src/alignment.hpp
@@ -27,7 +27,7 @@
 #include <string>
 #include <random>
 
-#include "fastq.h"
+#include "fastq.hpp"
 
 namespace ar
 {
diff --git a/src/argparse.cc b/src/argparse.cpp
similarity index 89%
rename from src/argparse.cc
rename to src/argparse.cpp
index 532f2a5..856509b 100644
--- a/src/argparse.cc
+++ b/src/argparse.cpp
@@ -33,9 +33,9 @@
 #include <sys/ioctl.h>
 #include <unistd.h>
 
-#include "argparse.h"
-#include "debug.h"
-#include "strutils.h"
+#include "argparse.hpp"
+#include "debug.hpp"
+#include "strutils.hpp"
 
 
 namespace ar
@@ -69,11 +69,11 @@ parser::parser(const std::string& name,
     , m_help(help)
 {
     // Built-in arguments (aliases are not shown!)
-    (*this)["--help"] = new flag(NULL, "Display this message.");
+    (*this)["--help"] = new flag(nullptr, "Display this message.");
     create_alias("--help", "-help");
     create_alias("--help", "-h");
 
-    (*this)["--version"] = new flag(NULL, "Print the version string.");
+    (*this)["--version"] = new flag(nullptr, "Print the version string.");
     create_alias("--version", "-version");
     create_alias("--version", "-v");
 
@@ -83,14 +83,12 @@ parser::parser(const std::string& name,
 
 parser::~parser()
 {
-    // Collect set of unique pointers, to handle parsers assigned to multiple keys.
+    // Track set of unique pointers, to handle parsers assigned to multiple keys.
     consumer_set pointers;
-    for (consumer_map::iterator it = m_parsers.begin(); it != m_parsers.end(); ++it) {
-        pointers.insert(it->second);
-    }
-
-    for (consumer_set::iterator it = pointers.begin(); it != pointers.end(); ++it) {
-        delete *it;
+    for (const auto& parser : m_parsers) {
+        if (pointers.insert(parser.second).second) {
+            delete parser.second;
+        }
     }
 }
 
@@ -136,24 +134,24 @@ parse_result parser::parse_args(int argc, char* argv[])
                               << "; aborting ..." << std::endl;
                 }
 
-                return pr_error;
+                return parse_result::error;
             }
 
             it += static_cast<consumer_map::iterator::difference_type>(consumed);
         } else {
-            return pr_error;
+            return parse_result::error;
         }
     }
 
     if (is_set("--help")) {
         print_help();
-        return pr_exit;
+        return parse_result::exit;
     } else if (is_set("--version")) {
         print_version();
-        return pr_exit;
+        return parse_result::exit;
     }
 
-    return pr_ok;
+    return parse_result::ok;
 }
 
 
@@ -204,14 +202,12 @@ void parser::print_help() const
 
 void parser::print_arguments(const key_pair_vec& keys) const
 {
-    typedef key_pair_vec::const_iterator key_pair_citer;
-
     size_t indentation = 0;
-    for (key_pair_citer it = keys.begin(); it != keys.end(); ++it) {
-        if (it->first) {
-            const consumer_ptr ptr = m_parsers.at(it->second);
-            const std::string metavar = get_metavar_str(ptr, it->second);
-            size_t current_len = it->second.length();
+    for (const auto& key_pair : keys) {
+        if (key_pair.first) {
+            const consumer_ptr ptr = m_parsers.at(key_pair.second);
+            const std::string metavar = get_metavar_str(ptr, key_pair.second);
+            size_t current_len = key_pair.second.length();
 
             if (!metavar.empty()) {
                 current_len += metavar.length();
@@ -234,20 +230,20 @@ void parser::print_arguments(const key_pair_vec& keys) const
     fmt.set_indent_first_line(false);
     fmt.set_column_width(get_terminal_columns() - indentation - 3);
 
-    for (key_pair_citer it = keys.begin(); it != keys.end(); ++it) {
-        if (!it->first) {
-            std::cerr << it->second << "\n";
+    for (const auto& key_pair : keys) {
+        if (!key_pair.first) {
+            std::cerr << key_pair.second << "\n";
             continue;
         }
 
-        const consumer_ptr ptr = m_parsers.at(it->second);
+        const consumer_ptr ptr = m_parsers.at(key_pair.second);
         if (ptr->help() == "HIDDEN") {
             continue;
         }
 
-        const std::string metavar = get_metavar_str(ptr, it->second);
+        const std::string metavar = get_metavar_str(ptr, key_pair.second);
         std::cerr << std::left << std::setw(indentation)
-                  << ("  " + it->second + " " + metavar);
+                  << ("  " + key_pair.second + " " + metavar);
 
         std::string value = ptr->help();
         if (!value.empty()) {
@@ -420,8 +416,8 @@ std::string any::to_str() const
 many::many(string_vec* value, const std::string& metavar, const std::string& help)
     : consumer_base(metavar, help)
     , m_ptr(value)
-    , m_sink()
 {
+    AR_DEBUG_ASSERT(m_ptr);
 }
 
 
@@ -435,7 +431,7 @@ size_t many::consume(string_vec_citer start, const string_vec_citer& end)
         }
     }
 
-    (m_ptr ? *m_ptr : m_sink).assign(start, it);
+    m_ptr->assign(start, it);
 
     return static_cast<size_t>(it - start);
 }
@@ -443,13 +439,12 @@ size_t many::consume(string_vec_citer start, const string_vec_citer& end)
 
 std::string many::to_str() const
 {
-    const string_vec& result = m_ptr ? *m_ptr : m_sink;
-    if (result.empty()) {
+    if (m_ptr->empty()) {
         return "<not set>";
     } else {
         std::string output;
 
-        for (auto& s: result) {
+        for (const auto& s: *m_ptr) {
             if (!output.empty()) {
                 output.push_back(';');
             }
diff --git a/src/argparse.h b/src/argparse.hpp
similarity index 87%
rename from src/argparse.h
rename to src/argparse.hpp
index c2f6036..c166430 100644
--- a/src/argparse.h
+++ b/src/argparse.hpp
@@ -29,7 +29,7 @@
 #include <vector>
 #include <map>
 
-#include "commontypes.h"
+#include "commontypes.hpp"
 
 namespace ar
 {
@@ -42,13 +42,13 @@ typedef std::map<std::string, consumer_ptr> consumer_map;
 
 
 //! Parse results for command-line arguments
-enum parse_result {
+enum class parse_result {
     //! Terminate now (e.g. --version or --help used)
-    pr_exit,
+    exit,
     //! Error occurred parsing arguments / invalid combination of args
-    pr_error,
+    error,
     //! No errors parsing commandline arguments
-    pr_ok
+    ok
 };
 
 
@@ -136,6 +136,11 @@ public:
     /** Helper functions; prints the full set of help-text. */
     void print_help() const;
 
+    //! Copy construction not supported
+    parser(const parser&) = delete;
+    //! Assignment not supported
+    parser& operator=(const parser&) = delete;
+
 private:
     typedef std::pair<bool, std::string> key_pair;
     typedef std::vector<key_pair> key_pair_vec;
@@ -225,16 +230,15 @@ public:
     /** Returns the value associated with the consumer as a string. **/
     virtual std::string to_str() const = 0;
 
+    //! Copy construction not supported
+    consumer_base(const consumer_base&) = delete;
+    //! Assignment not supported
+    consumer_base& operator=(const consumer_base&) = delete;
+
 protected:
     //! Should be set to true if a value has been consumed in a derived class.
     bool m_value_set;
 
-private:
-    //! Not implemented
-    consumer_base(const consumer_base&);
-    //! Not implemented
-    consumer_base& operator=(const consumer_base&);
-
     //! Stores the metavar associated with the consumer
     std::string m_metavar;
     //! Stores the optional description of default behavior.
@@ -258,7 +262,7 @@ public:
      * Unlike the base constructor, this class does not take a 'metavar', as
      * no values are consumed during parsing.
      */
-    flag(bool* sink = NULL, const std::string& help = "");
+    flag(bool* sink = nullptr, const std::string& help = "");
 
     /** See consumer_base::consume */
     virtual size_t consume(string_vec_citer start, const string_vec_citer& end);
@@ -266,13 +270,13 @@ public:
     /** See consumer_base::to_str */
     virtual std::string to_str() const;
 
-private:
-    //! Not implemented
-    flag(const flag&);
-    //! Not implemented
-    flag& operator=(const flag&);
+    //! Copy construction not supported
+    flag(const flag&) = delete;
+    //! Assignment not supported
+    flag& operator=(const flag&) = delete;
 
-    //! Optional pointer to storage for boolean value; if NULL, m_value is used.
+private:
+    //! Optional pointer to storage for boolean value; if nullptr, m_value is used.
     bool* m_ptr;
 };
 
@@ -287,7 +291,7 @@ public:
     /**
      * See consumer_base::consumer_base
      */
-    any(std::string* sink = NULL, const std::string& metavar = "", const std::string& help = "");
+    any(std::string* sink = nullptr, const std::string& metavar = "", const std::string& help = "");
 
     /** See consumer_base::consume */
     virtual size_t consume(string_vec_citer start, const string_vec_citer& end);
@@ -295,13 +299,13 @@ public:
     /** See consumer_base::to_str */
     virtual std::string to_str() const;
 
-private:
-    //! Not implemented
-    any(const any&);
-    //! Not implemented
-    any& operator=(const any&);
+    //! Copy construction not supported
+    any(const any&) = delete;
+    //! Assignment not supported
+    any& operator=(const any&) = delete;
 
-    //! Optional pointer to storage for string value; if NULL, m_value is used.
+private:
+    //! Optional pointer to storage for string value; if nullptr, m_value is used.
     std::string* m_ptr;
     //! Value sink used if a pointer to a sink is not provided.
     std::string m_sink;
@@ -318,7 +322,7 @@ public:
     /**
      * See consumer_base::consumer_base
      */
-    many(string_vec* sink = NULL, const std::string& metavar = "", const std::string& help = "");
+    many(string_vec* sink, const std::string& metavar = "", const std::string& help = "");
 
     /** See consumer_base::consume */
     virtual size_t consume(string_vec_citer start, const string_vec_citer& end);
@@ -326,16 +330,14 @@ public:
     /** See consumer_base::to_str */
     virtual std::string to_str() const;
 
-private:
-    //! Not implemented
-    many(const many&);
-    //! Not implemented
-    many& operator=(const many&);
+    //! Copy construction not supported
+    many(const many&) = delete;
+    //! Assignment not supported
+    many& operator=(const many&) = delete;
 
-    //! Optional pointer to storage for string value; if NULL, m_value is used.
+private:
+    //! Pointer to storage for string value; if nullptr, m_value is used.
     string_vec* m_ptr;
-    //! Value sink used if a pointer to a sink is not provided.
-    string_vec m_sink;
 };
 
 
@@ -359,12 +361,12 @@ public:
     /** See consumer_base::to_str */
     virtual std::string to_str() const;
 
-private:
-    //! Not implemented
-    knob(const knob&);
-    //! Not implemented
-    knob& operator=(const knob&);
+    //! Copy construction not supported
+    knob(const knob&) = delete;
+    //! Assignment not supported
+    knob& operator=(const knob&) = delete;
 
+private:
     //! Pointer to storage for unsigned value (required).
     unsigned* m_ptr;
 };
@@ -377,9 +379,7 @@ private:
 class floaty_knob : public consumer_base
 {
 public:
-    /**
-     * See consumer_base::consumer_base; a sink must be set.
-     */
+    /** See consumer_base::consumer_base; a sink must be set. */
     floaty_knob(double* sink, const std::string& metavar = "", const std::string& help = "");
 
     /** See consumer_base::consume */
@@ -388,12 +388,12 @@ public:
     /** See consumer_base::to_str */
     virtual std::string to_str() const;
 
-private:
-    //! Not implemented
-    floaty_knob(const floaty_knob&);
-    //! Not implemented
-    floaty_knob& operator=(const floaty_knob&);
+    //! Copy construction not supported
+    floaty_knob(const floaty_knob&) = delete;
+    //! Assignment not supported
+    floaty_knob& operator=(const floaty_knob&) = delete;
 
+private:
     //! Pointer to storage for unsigned value (required).
     double* m_ptr;
 };
diff --git a/src/commontypes.h b/src/commontypes.hpp
similarity index 96%
rename from src/commontypes.h
rename to src/commontypes.hpp
index 0180560..f72b87e 100644
--- a/src/commontypes.h
+++ b/src/commontypes.hpp
@@ -43,22 +43,22 @@ typedef fastq_vec::iterator fastq_vec_iter;
 
 
 /** Different file-types read / generated by AdapterRemoval. */
-enum read_type
+enum class read_type
 {
 	/** Mate 1 reads, either read or written by AR. */
-    rt_mate_1 = 0,
+    mate_1 = 0,
 	/** Mate 2 reads, either read or written by AR. */
-    rt_mate_2,
+    mate_2,
 	/** PE reads for which the mate has been discarded. */
-    rt_singleton,
+    singleton,
 	/** Overlapping PE reads merged into a single sequence. */
-    rt_collapsed,
+    collapsed,
 	/** Collapsed reads truncated due to trimming of low-quality bases. */
-    rt_collapsed_truncated,
+    collapsed_truncated,
     /** Discarded reads; e.g. too short reads. */
-    rt_discarded,
+    discarded,
     //! End value; not to be used as an argument.
-    rt_max
+    max
 };
 
 
diff --git a/src/debug.cc b/src/debug.cpp
similarity index 99%
rename from src/debug.cc
rename to src/debug.cpp
index 8bb34a7..c9bdb9a 100644
--- a/src/debug.cc
+++ b/src/debug.cpp
@@ -21,7 +21,7 @@
  * You should have received a copy of the GNU General Public License     *
  * along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 \*************************************************************************/
-#include "debug.h"
+#include "debug.hpp"
 
 #include <cstdlib>
 #include <iostream>
diff --git a/src/debug.h b/src/debug.hpp
similarity index 100%
rename from src/debug.h
rename to src/debug.hpp
diff --git a/src/demultiplex.cc b/src/demultiplex.cpp
similarity index 92%
rename from src/demultiplex.cc
rename to src/demultiplex.cpp
index d359207..936e9c4 100644
--- a/src/demultiplex.cc
+++ b/src/demultiplex.cpp
@@ -25,12 +25,12 @@
 #include <iostream>
 #include <algorithm>
 
-#include "debug.h"
-#include "demultiplex.h"
-#include "commontypes.h"
-#include "fastq_io.h"
-#include "userconfig.h"
-#include "strutils.h"
+#include "debug.hpp"
+#include "demultiplex.hpp"
+#include "commontypes.hpp"
+#include "fastq_io.hpp"
+#include "userconfig.hpp"
+#include "strutils.hpp"
 
 namespace ar
 {
@@ -167,8 +167,8 @@ void rec_lookup_sequence_no_mm(candidate_vec& candidates,
                                size_t mismatches = 0)
 {
     const demultiplexer_node& node = tree.at(parent);
-    for (int_vec::const_iterator it = node.barcodes.begin(); it != node.barcodes.end(); ++it) {
-        candidates.emplace_back(*it, mismatches);
+    for (const auto& barcode : node.barcodes) {
+        candidates.emplace_back(barcode, mismatches);
     }
 
     if (seq_pos < seq.length()) {
@@ -191,8 +191,8 @@ void rec_lookup_sequence(candidate_vec& candidates,
                          size_t mismatches = 0)
 {
     const demultiplexer_node& node = tree.at(parent);
-    for (int_vec::const_iterator it = node.barcodes.begin(); it != node.barcodes.end(); ++it) {
-        candidates.emplace_back(*it, mismatches);
+    for (const auto& barcode : node.barcodes) {
+        candidates.emplace_back(barcode, mismatches);
     }
 
     if (seq_pos < seq.length()) {
@@ -217,7 +217,7 @@ void rec_lookup_sequence(candidate_vec& candidates,
 
 
 demultiplex_reads::demultiplex_reads(const userconfig* config)
-    : analytical_step(analytical_step::ordered)
+    : analytical_step(analytical_step::ordering::ordered)
     , m_barcodes(config->adapters.get_barcodes())
     , m_tree(build_demux_tree(m_barcodes))
     , m_max_mismatches(config->barcode_mm)
@@ -287,10 +287,10 @@ int demultiplex_reads::select_barcode(const fastq& read_r1, const fastq& read_r2
 
     int best_barcode = -1;
     size_t min_mismatches = m_max_mismatches + 1;
-    for (candidate_vec::iterator it = candidates.begin(); it != candidates.end(); ++it) {
+    for (auto& candidate : candidates) {
         if (m_config->paired_ended_mode) {
-            const std::string& barcode = m_barcodes.at(it->first).second.sequence();
-            const size_t max_mismatches_r2 = std::min(m_max_mismatches - it->second,
+            const std::string& barcode = m_barcodes.at(candidate.first).second.sequence();
+            const size_t max_mismatches_r2 = std::min(m_max_mismatches - candidate.second,
                                                       m_max_mismatches_r2);
 
             const size_t mismatches = count_mismatches(barcode,
@@ -301,13 +301,13 @@ int demultiplex_reads::select_barcode(const fastq& read_r1, const fastq& read_r2
                 continue;
             }
 
-            it->second += mismatches;
+            candidate.second += mismatches;
         }
 
-        if (it->second < min_mismatches) {
-            best_barcode = it->first;
-            min_mismatches = it->second;
-        } else if (it->second == min_mismatches) {
+        if (candidate.second < min_mismatches) {
+            best_barcode = candidate.first;
+            min_mismatches = candidate.second;
+        } else if (candidate.second == min_mismatches) {
             // Ambiguous results; multiple best matches
             best_barcode = -1;
         }
@@ -376,11 +376,11 @@ chunk_vec demultiplex_se_reads::process(analytical_chunk* chunk)
     read_chunk_ptr read_chunk(dynamic_cast<fastq_read_chunk*>(chunk));
 
     const fastq empty_read;
-    for (fastq_vec::iterator it = read_chunk->reads_1.begin(); it != read_chunk->reads_1.end(); ++it) {
-        const int best_barcode = select_barcode(*it, empty_read);
+    for (const auto& read : read_chunk->reads_1) {
+        const int best_barcode = select_barcode(read, empty_read);
 
         if (best_barcode < 0) {
-            m_unidentified_1->add(*m_config->quality_output_fmt, *it);
+            m_unidentified_1->add(*m_config->quality_output_fmt, read);
 
             if (best_barcode == -1) {
                 m_statistics.unidentified += 1;
@@ -389,7 +389,7 @@ chunk_vec demultiplex_se_reads::process(analytical_chunk* chunk)
             }
         } else {
             read_chunk_ptr& dst = m_cache.at(best_barcode);
-            dst->reads_1.push_back(*it);
+            dst->reads_1.push_back(read);
             dst->reads_1.back().truncate(m_barcodes.at(best_barcode).first.length());
 
            m_statistics.barcodes.at(best_barcode) += 1;
diff --git a/src/demultiplex.h b/src/demultiplex.hpp
similarity index 94%
rename from src/demultiplex.h
rename to src/demultiplex.hpp
index ebd4402..5a616ac 100644
--- a/src/demultiplex.h
+++ b/src/demultiplex.hpp
@@ -25,10 +25,10 @@
 #ifndef DEMULTIPLEX_H
 #define DEMULTIPLEX_H
 
-#include "fastq.h"
-#include "scheduler.h"
-#include "statistics.h"
-#include "fastq_io.h"
+#include "fastq.hpp"
+#include "scheduler.hpp"
+#include "statistics.hpp"
+#include "fastq_io.hpp"
 
 namespace ar
 {
@@ -57,6 +57,11 @@ public:
     /** Returns a statistics object summarizing the results up till now. */
     demux_statistics statistics() const;
 
+    //! Copy construction not supported
+    demultiplex_reads(const demultiplex_reads&) = delete;
+    //! Assignment not supported
+    demultiplex_reads& operator=(const demultiplex_reads&) = delete;
+
 protected:
     /**
      * Returns the id of the best matching barcode(s), or -1 if no matches were
@@ -98,12 +103,6 @@ protected:
 
     //! Lock used to verify that the analytical_step is only run sequentially.
     std::mutex m_lock;
-
-private:
-    //! Not implemented
-    demultiplex_reads(const demultiplex_reads&);
-    //! Not implemented
-    demultiplex_reads& operator=(const demultiplex_reads&);
 };
 
 
diff --git a/src/fastq.cc b/src/fastq.cpp
similarity index 89%
rename from src/fastq.cc
rename to src/fastq.cpp
index f2c409c..8df5941 100644
--- a/src/fastq.cc
+++ b/src/fastq.cpp
@@ -28,33 +28,39 @@
 #include <stdexcept>
 #include <sstream>
 
-#include "debug.h"
-#include "fastq.h"
-#include "linereader.h"
+#include "debug.hpp"
+#include "fastq.hpp"
+#include "linereader.hpp"
 
 namespace ar
 {
 
+enum class read_mate {
+    unknown,
+    mate_1,
+    mate_2,
+};
+
+
 struct mate_info
 {
     mate_info()
       : name()
-      , mate(unknown)
+      , mate(read_mate::unknown)
     {}
 
     std::string desc() const
     {
         switch (mate) {
-            case unknown: return "unknown";
-            case mate1: return "mate 1";
-            case mate2: return "mate 2";
-            default:
-                throw std::invalid_argument("Invalid mate in mate_info::desc");
+            case read_mate::unknown: return "unknown";
+            case read_mate::mate_1: return "mate 1";
+            case read_mate::mate_2: return "mate 2";
+            default: AR_DEBUG_FAIL("Invalid mate in mate_info::desc");
         }
     }
 
     std::string name;
-    enum { unknown, mate1, mate2 } mate;
+    read_mate mate;
 };
 
 
@@ -73,11 +79,11 @@ inline mate_info get_and_fix_mate_info(fastq& read, char mate_separator)
 
         if (digit == '1') {
             header[pos - 2] = MATE_SEPARATOR;
-            info.mate = mate_info::mate1;
+            info.mate = read_mate::mate_1;
             pos -= 2;
         } else if (digit == '2') {
             header[pos - 2] = MATE_SEPARATOR;
-            info.mate = mate_info::mate2;
+            info.mate = read_mate::mate_2;
             pos -= 2;
         }
     }
@@ -252,8 +258,8 @@ void fastq::reverse_complement()
 
     // Lookup table for complementary bases based only on the last 4 bits
     static const char complements[] = "-T-GA--C------N-";
-    for(std::string::iterator it = m_sequence.begin(); it != m_sequence.end(); ++it) {
-        *it = complements[*it & 0xf];
+    for (auto& nuc : m_sequence) {
+        nuc = complements[nuc & 0xf];
     }
 }
 
@@ -305,8 +311,8 @@ bool fastq::read(line_reader_base& reader, const fastq_encoding& encoding)
 
     if (!reader.getline(m_qualities)) {
         throw fastq_error("partial FASTQ record; cut off after separator");
-    } else if (m_sequence.empty()) {
-        throw fastq_error("sequence is empty");
+    } else if (m_qualities.empty()) {
+        throw fastq_error("no qualities");
     }
 
     process_record(encoding);
@@ -325,15 +331,9 @@ std::string fastq::to_str(const fastq_encoding& encoding) const
     result.push_back('\n');
     result.append(m_sequence);
     result.append("\n+\n", 3);
-    result.append(m_qualities);
+    encoding.encode(m_qualities, result);
     result.push_back('\n');
 
-    // Encode quality-scores in place
-    size_t quality_start = m_header.size() + m_sequence.size() + 5;
-    size_t quality_end = quality_start + m_sequence.size();
-    encoding.encode_string(result.begin() + quality_start,
-                           result.begin() + quality_end);
-
     return result;
 }
 
@@ -344,8 +344,8 @@ std::string fastq::to_str(const fastq_encoding& encoding) const
 
 void fastq::clean_sequence(std::string& sequence)
 {
-    for (std::string::iterator it = sequence.begin(); it != sequence.end(); ++it) {
-        switch (*it) {
+    for (char& nuc : sequence) {
+        switch (nuc) {
             case 'A':
             case 'C':
             case 'G':
@@ -358,11 +358,11 @@ void fastq::clean_sequence(std::string& sequence)
             case 'g':
             case 't':
             case 'n':
-                *it += 'A' - 'a';
+                nuc += 'A' - 'a';
                 break;
 
             case '.':
-                *it = 'N';
+                nuc = 'N';
                 break;
 
             default:
@@ -398,7 +398,7 @@ void fastq::validate_paired_reads(fastq& mate1, fastq& mate2,
               << " - '" << info1.name << "'\n"
               << " - '" << info2.name << "'";
 
-        if (info1.mate == mate_info::unknown || info2.mate == mate_info::unknown) {
+        if (info1.mate == read_mate::unknown || info2.mate == read_mate::unknown) {
             error << "\n\nNote that AdapterRemoval by determines the mate "
                      "numbers as the digit found at the end of the read name, "
                      "if this is preceded by the character '"
@@ -412,8 +412,8 @@ void fastq::validate_paired_reads(fastq& mate1, fastq& mate2,
         throw fastq_error(error.str());
     }
 
-    if (info1.mate != mate_info::unknown || info2.mate != mate_info::unknown) {
-        if (info1.mate != mate_info::mate1 || info2.mate != mate_info::mate2) {
+    if (info1.mate != read_mate::unknown || info2.mate != read_mate::unknown) {
+        if (info1.mate != read_mate::mate_1 || info2.mate != read_mate::mate_2) {
             std::stringstream error;
             error << "Inconsistent mate numbering; please verify data:\n"
                   << "\nRead 1 identified as " << info1.desc() << ": " << mate1.name()
@@ -435,7 +435,7 @@ void fastq::process_record(const fastq_encoding& encoding)
     }
 
     clean_sequence(m_sequence);
-    encoding.decode_string(m_qualities.begin(), m_qualities.end());
+    encoding.decode(m_qualities);
 }
 
 
diff --git a/src/fastq.h b/src/fastq.hpp
similarity index 99%
rename from src/fastq.h
rename to src/fastq.hpp
index bccfd66..ac67c7a 100644
--- a/src/fastq.h
+++ b/src/fastq.hpp
@@ -29,8 +29,8 @@
 
 #include <string>
 
-#include "commontypes.h"
-#include "fastq_enc.h"
+#include "commontypes.hpp"
+#include "fastq_enc.hpp"
 
 namespace ar
 {
diff --git a/src/fastq_enc.cc b/src/fastq_enc.cpp
similarity index 77%
rename from src/fastq_enc.cc
rename to src/fastq_enc.cpp
index e5a45bc..8185bf6 100644
--- a/src/fastq_enc.cc
+++ b/src/fastq_enc.cpp
@@ -29,11 +29,16 @@
 #include <sstream>
 #include <iostream>
 
-#include "fastq_enc.h"
+#include "debug.hpp"
+#include "fastq_enc.hpp"
+
 
 namespace ar
 {
 
+void invalid_solexa(const char offset, const char max_score, const char raw) __attribute__((noreturn));
+
+
 ///////////////////////////////////////////////////////////////////////////////
 // fastq_error
 
@@ -106,6 +111,8 @@ const std::string g_phred_to_solexa = calc_phred_to_solexa();
 void invalid_phred(const char offset, const char max_score, const char raw)
 {
     if (raw < offset) {
+        AR_DEBUG_ASSERT(offset == 33 || offset == 64);
+
         if (offset == 33) {
             throw fastq_error("ASCII value of quality score is less than 33 "
                               "(ASCII < '!'); input is corrupt or not in "
@@ -113,7 +120,7 @@ void invalid_phred(const char offset, const char max_score, const char raw)
         } else if (offset == 64) {
             if (raw < ';') {
                 throw fastq_error("Phred+64 encoded quality score is less than 0 "
-                                  "(ASCII < '@'); Are these FASTQ reads actually in "
+                                  "(ASCII < ';'); Are these FASTQ reads actually in "
                                   "Phred+33 format? If so, use the command-line "
                                   "option \"--qualitybase 33\"\n\n"
 
@@ -129,7 +136,7 @@ void invalid_phred(const char offset, const char max_score, const char raw)
                                   "See README for more information.");
             }
         } else {
-            throw std::logic_error("Unexpected offset in fastq_encoding::decode");
+            AR_DEBUG_FAIL("Unexpected offset in fastq_encoding::decode");
         }
     } else if (raw > max_score) {
         if (raw > '~') {
@@ -172,7 +179,7 @@ void invalid_phred(const char offset, const char max_score, const char raw)
 
             throw fastq_error(ss.str());
         } else {
-            throw std::logic_error("Unexpected offset in fastq_encoding::decode");
+            AR_DEBUG_FAIL("Unexpected offset in fastq_encoding::decode");
         }
     }
 }
@@ -191,28 +198,26 @@ void invalid_solexa(const char offset, const char max_score, const char raw)
                               "the '--qualitybase 33' command-line option.\n\n"
                               "See the README for more information.");
         }
-    } else if (raw > offset + max_score) {
-        if (raw > '~') {
-            throw fastq_error("ASCII value of quality score is greater than "
-                              "126 (ASCII > '~'); input is corrupt or not in "
-                              "FASTQ format!");
-        } else {
-            std::stringstream ss;
+    } else if (raw > '~') {
+        throw fastq_error("ASCII value of quality score is greater than "
+                        "126 (ASCII > '~'); input is corrupt or not in "
+                            "FASTQ format!");
+    } else {
+        std::stringstream ss;
 
-            ss << "Solaxa encoded quality score is greater than the "
-               << "expected maximum (" << max_score << " = "
-               << static_cast<char>(offset + max_score) << "). Please "
-               << "verify the format of these files.\n\n"
+        ss << "Solaxa encoded quality score is greater than the "
+            << "expected maximum (" << max_score << " = "
+            << static_cast<char>(offset + max_score) << "). Please "
+            << "verify the format of these files.\n\n"
 
-               << "If the quality scores are Solexa encoded, but includes "
-               << "scores in a greater range than expected, then use the "
-               << "'--maxquality' command-line option. Note that this option "
-               << "effects both reading and writing of FASTQ files.\n\n"
+            << "If the quality scores are Solexa encoded, but includes "
+            << "scores in a greater range than expected, then use the "
+            << "'--maxquality' command-line option. Note that this option "
+            << "effects both reading and writing of FASTQ files.\n\n"
 
-               << "See README for more information.";
+            << "See README for more information.";
 
-            throw fastq_error(ss.str());
-        }
+        throw fastq_error(ss.str());
     }
 }
 
@@ -239,42 +244,41 @@ fastq_encoding::~fastq_encoding()
 }
 
 
-void fastq_encoding::encode_string(std::string::iterator it,
-                                   const std::string::iterator& end) const
+void fastq_encoding::encode(const std::string& qualities,
+                            std::string& dst) const
 {
     const char ascii_max = m_offset + m_max_score;
     const char offset = m_offset - '!';
 
-    for (; it != end; ++it) {
-        *it = std::min<int>(ascii_max, *it + offset);
+    for (const auto& quality : qualities) {
+        dst.push_back(std::min<int>(ascii_max, quality + offset));
     }
 }
 
 
-void fastq_encoding::decode_string(std::string::iterator it,
-                                   const std::string::iterator& end) const
+void fastq_encoding::decode(std::string& qualities) const
 {
     const char max_score = m_offset + m_max_score;
-    for (; it != end; ++it) {
-        const char raw = *it;
+    const char offset = PHRED_OFFSET_33 - m_offset;
 
-        if (raw < m_offset || raw > max_score) {
-            invalid_phred(m_offset, m_max_score, raw);
+    for (auto& quality : qualities) {
+        if (quality < m_offset || quality > max_score) {
+            invalid_phred(m_offset, m_max_score, quality);
         }
 
-        *it = raw - m_offset + PHRED_OFFSET_33;
+        quality += offset;
     }
 }
 
 
-std::string fastq_encoding::name() const
+const char* fastq_encoding::name() const
 {
     if (m_offset == 33) {
         return "Phred+33";
     } else if (m_offset == 64) {
         return "Phred+64";
     } else {
-        throw std::logic_error("Unexpected offset in fastq_encoding::name");
+        AR_DEBUG_FAIL("Unexpected offset in fastq_encoding::name");
     }
 }
 
@@ -291,34 +295,31 @@ fastq_encoding_solexa::fastq_encoding_solexa(unsigned max_score)
 }
 
 
-void fastq_encoding_solexa::encode_string(std::string::iterator it,
-                                   const std::string::iterator& end) const
+void fastq_encoding_solexa::encode(const std::string& qualities,
+                                   std::string& dst) const
 {
     const char ascii_max = m_offset + m_max_score;
 
-    for (; it != end; ++it) {
-        *it = std::min<int>(ascii_max, g_phred_to_solexa.at(*it - '!') + '@');
+    for (const auto& quality : qualities) {
+        dst.push_back(std::min<int>(ascii_max, g_phred_to_solexa.at(quality - '!') + '@'));
     }
 }
 
 
-void fastq_encoding_solexa::decode_string(std::string::iterator it,
-                                   const std::string::iterator& end) const
+void fastq_encoding_solexa::decode(std::string& qualities) const
 {
     const char max_score = m_offset + m_max_score;
-    for (; it != end; ++it) {
-        const char raw = *it;
-
-        if (raw < ';' || raw > max_score) {
-            invalid_phred(m_offset, m_max_score, raw);
+    for (auto& quality : qualities) {
+        if (quality < ';' || quality > max_score) {
+            invalid_phred(m_offset, m_max_score, quality);
         }
 
-        *it = g_solexa_to_phred.at(raw - ';') + '!';
+        quality = g_solexa_to_phred.at(quality - ';') + '!';
     }
 }
 
 
-std::string fastq_encoding_solexa::name() const
+const char* fastq_encoding_solexa::name() const
 {
     return "Solexa";
 }
diff --git a/src/fastq_enc.h b/src/fastq_enc.hpp
similarity index 86%
rename from src/fastq_enc.h
rename to src/fastq_enc.hpp
index dba7025..e33151e 100644
--- a/src/fastq_enc.h
+++ b/src/fastq_enc.hpp
@@ -85,31 +85,30 @@ public:
 
     virtual ~fastq_encoding();
 
-    /** Encodes a string of Phred+33/66 quality-scores in-place. */
-    virtual void encode_string(std::string::iterator it, const std::string::iterator& end) const;
+    /** Appends encoded Phred+33/66 quality-scores to dst. */
+    virtual void encode(const std::string& qualities, std::string& dst) const;
     /** Decodes a string of ASCII values in-place. */
-    virtual void decode_string(std::string::iterator it, const std::string::iterator& end) const;
+    virtual void decode(std::string& qualities) const;
 
     /** Returns the standard name for this encoding. */
-    virtual std::string name() const;
+    virtual const char* name() const;
 
     /**
      * Returns the maximum allowed quality score for input, and the range to
      * range to which output scores are truncated.
      */
-    virtual size_t max_score() const;
+    size_t max_score() const;
+
+    //! Copy construction not supported
+    fastq_encoding(const fastq_encoding&) = delete;
+    //! Assignment not supported
+    fastq_encoding& operator=(const fastq_encoding&) = delete;
 
 protected:
     //! Character offset for Phred encoded scores (33 or 64)
     const char m_offset;
     //! Maximum allowed score; used for checking input / truncating output
     const char m_max_score;
-
-private:
-    //! Not implemented
-    fastq_encoding(const fastq_encoding&);
-    //! Not implemented
-    fastq_encoding& operator=(const fastq_encoding&);
 };
 
 
@@ -132,13 +131,13 @@ public:
      */
     fastq_encoding_solexa(unsigned max_score = MAX_PHRED_SCORE_DEFAULT);
 
-    /** Encodes a string of Phred+33/66 quality-scores in-place. */
-    virtual void encode_string(std::string::iterator it, const std::string::iterator& end) const;
+    /** Appends encoded Phred+33/66 quality-scores to dst. */
+    virtual void encode(const std::string& qualities, std::string& dst) const override;
     /** Decodes a string of ASCII values in-place. */
-    virtual void decode_string(std::string::iterator it, const std::string::iterator& end) const;
+    virtual void decode(std::string& qualities) const override;
 
     /** Returns the standard name for this encoding. */
-    std::string name() const;
+    const char* name() const;
 };
 
 
diff --git a/src/fastq_io.cc b/src/fastq_io.cpp
similarity index 92%
rename from src/fastq_io.cc
rename to src/fastq_io.cpp
index 589ddce..81f71f7 100644
--- a/src/fastq_io.cc
+++ b/src/fastq_io.cpp
@@ -26,9 +26,10 @@
 #include <cerrno>
 #include <cstring>
 
-#include "debug.h"
-#include "fastq_io.h"
-#include "userconfig.h"
+#include "debug.hpp"
+#include "fastq_io.hpp"
+#include "userconfig.hpp"
+
 
 namespace ar
 {
@@ -88,8 +89,8 @@ fastq_output_chunk::fastq_output_chunk(bool eof_)
 
 fastq_output_chunk::~fastq_output_chunk()
 {
-    for (buffer_vec::iterator it = buffers.begin(); it != buffers.end(); ++it) {
-        delete[] it->second;
+    for (auto& buffer : buffers) {
+        delete[] buffer.second;
     }
 }
 
@@ -109,7 +110,7 @@ void fastq_output_chunk::add(const fastq_encoding& encoding,
 read_single_fastq::read_single_fastq(const fastq_encoding* encoding,
                                      const string_vec& filenames,
                                      size_t next_step)
-  : analytical_step(analytical_step::ordered, true)
+  : analytical_step(analytical_step::ordering::ordered, true)
   , m_encoding(encoding)
   , m_line_offset(1)
   , m_io_input(filenames)
@@ -124,7 +125,7 @@ read_single_fastq::read_single_fastq(const fastq_encoding* encoding,
 chunk_vec read_single_fastq::process(analytical_chunk* chunk)
 {
     AR_DEBUG_LOCK(m_lock);
-    AR_DEBUG_ASSERT(chunk == NULL);
+    AR_DEBUG_ASSERT(chunk == nullptr);
     if (m_eof) {
         return chunk_vec();
     }
@@ -166,7 +167,7 @@ read_paired_fastq::read_paired_fastq(const fastq_encoding* encoding,
                                      const string_vec& filenames_1,
                                      const string_vec& filenames_2,
                                      size_t next_step)
-  : analytical_step(analytical_step::ordered, true)
+  : analytical_step(analytical_step::ordering::ordered, true)
   , m_encoding(encoding)
   , m_line_offset(1)
   , m_io_input_1(filenames_1)
@@ -182,7 +183,7 @@ read_paired_fastq::read_paired_fastq(const fastq_encoding* encoding,
 chunk_vec read_paired_fastq::process(analytical_chunk* chunk)
 {
     AR_DEBUG_LOCK(m_lock);
-    AR_DEBUG_ASSERT(chunk == NULL);
+    AR_DEBUG_ASSERT(chunk == nullptr);
     if (m_eof) {
         return chunk_vec();
     }
@@ -234,7 +235,7 @@ void read_paired_fastq::finalize()
 read_interleaved_fastq::read_interleaved_fastq(const fastq_encoding* encoding,
                                           const string_vec& filenames,
                                           size_t next_step)
-  : analytical_step(analytical_step::ordered, true)
+  : analytical_step(analytical_step::ordering::ordered, true)
   , m_encoding(encoding)
   , m_line_offset(1)
   , m_io_input(filenames)
@@ -249,7 +250,7 @@ read_interleaved_fastq::read_interleaved_fastq(const fastq_encoding* encoding,
 chunk_vec read_interleaved_fastq::process(analytical_chunk* chunk)
 {
     AR_DEBUG_LOCK(m_lock);
-    AR_DEBUG_ASSERT(chunk == NULL);
+    AR_DEBUG_ASSERT(chunk == nullptr);
     if (m_eof) {
         return chunk_vec();
     }
@@ -332,38 +333,36 @@ void read_interleaved_fastq::finalize()
 std::pair<size_t, unsigned char*> build_input_buffer(const string_vec& lines)
 {
     size_t buffer_size = 0;
-    for (string_vec::const_iterator it = lines.begin(); it != lines.end(); ++it) {
-        buffer_size += it->size();
+    for (const auto& line : lines) {
+        buffer_size += line.size();
     }
 
     unsigned char* input_buffer = new unsigned char[buffer_size];
     unsigned char* input_buffer_ptr = input_buffer;
-    for (string_vec::const_iterator it = lines.begin(); it != lines.end(); ++it) {
-        std::memcpy(input_buffer_ptr, it->data(), it->size());
-        input_buffer_ptr += it->size();
+    for (const auto& line : lines) {
+        std::memcpy(input_buffer_ptr, line.data(), line.size());
+        input_buffer_ptr += line.size();
     }
 
     return std::pair<size_t, unsigned char*>(buffer_size, input_buffer);
 }
 
 
-#ifdef AR_BZIP2_SUPPORT
-
 ///////////////////////////////////////////////////////////////////////////////
 // Implementations for 'gzip_fastq'
 
 
 bzip2_fastq::bzip2_fastq(const userconfig& config, size_t next_step)
-  : analytical_step(analytical_step::ordered, false)
+  : analytical_step(analytical_step::ordering::ordered, false)
   , m_buffered_reads(0)
   , m_next_step(next_step)
   , m_stream()
   , m_eof(false)
   , m_lock()
 {
-    m_stream.bzalloc = NULL;
-    m_stream.bzfree = NULL;
-    m_stream.opaque = NULL;
+    m_stream.bzalloc = nullptr;
+    m_stream.bzfree = nullptr;
+    m_stream.opaque = nullptr;
 
     const int errorcode = BZ2_bzCompressInit(/* strm          = */ &m_stream,
                                              /* blockSize100k = */ config.bzip2_level,
@@ -470,7 +469,7 @@ chunk_vec bzip2_fastq::process(analytical_chunk* chunk)
                     delete[] output_buffer.second;
                 }
 
-                output_buffer.second = NULL;
+                output_buffer.second = nullptr;
             } while (m_stream.avail_in || errorcode == BZ_FINISH_OK);
         }
 
@@ -493,25 +492,21 @@ chunk_vec bzip2_fastq::process(analytical_chunk* chunk)
     return chunks;
 }
 
-#endif
-
-
-#ifdef AR_GZIP_SUPPORT
 
 ///////////////////////////////////////////////////////////////////////////////
 // Implementations for 'gzip_fastq'
 
 gzip_fastq::gzip_fastq(const userconfig& config, size_t next_step)
-  : analytical_step(analytical_step::ordered, false)
+  : analytical_step(analytical_step::ordering::ordered, false)
   , m_buffered_reads(0)
   , m_next_step(next_step)
   , m_stream()
   , m_eof(false)
   , m_lock()
 {
-    m_stream.zalloc = Z_NULL;
-    m_stream.zfree = Z_NULL;
-    m_stream.opaque = Z_NULL;
+    m_stream.zalloc = nullptr;
+    m_stream.zfree = nullptr;
+    m_stream.opaque = nullptr;
 
     const int errorcode = deflateInit2(/* strm       = */ &m_stream,
                                        /* level      = */ config.gzip_level,
@@ -619,7 +614,7 @@ chunk_vec gzip_fastq::process(analytical_chunk* chunk)
                     delete[] output_buffer.second;
                 }
 
-                output_buffer.second = NULL;
+                output_buffer.second = nullptr;
             } while (m_stream.avail_out == 0 || (m_eof && returncode != Z_STREAM_END));
         }
 
@@ -642,8 +637,6 @@ chunk_vec gzip_fastq::process(analytical_chunk* chunk)
     return chunks;
 }
 
-#endif
-
 
 ///////////////////////////////////////////////////////////////////////////////
 // Implementations for 'write_fastq'
@@ -657,7 +650,7 @@ static bool s_finalized = false;
 
 
 write_fastq::write_fastq(const std::string& filename)
-  : analytical_step(analytical_step::ordered, true)
+  : analytical_step(analytical_step::ordering::ordered, true)
   , m_output(filename.c_str(), std::ofstream::out | std::ofstream::binary)
   , m_eof(false)
   , m_lock()
@@ -683,14 +676,14 @@ chunk_vec write_fastq::process(analytical_chunk* chunk)
 
     m_eof = file_chunk->eof;
     if (file_chunk->buffers.empty()) {
-        for (string_vec::const_iterator it = lines.begin(); it != lines.end(); ++it) {
-            m_output << *it;
+        for (const auto& line : lines) {
+            m_output << line;
         }
     } else {
         buffer_vec& buffers = file_chunk->buffers;
-        for (buffer_vec::iterator it = buffers.begin(); it != buffers.end(); ++it) {
-            if (it->first) {
-                m_output.write(reinterpret_cast<char*>(it->second), it->first);
+        for (const auto& buffer : buffers) {
+            if (buffer.first) {
+                m_output.write(reinterpret_cast<const char*>(buffer.second), buffer.first);
             }
         }
     }
diff --git a/src/fastq_io.h b/src/fastq_io.hpp
similarity index 91%
rename from src/fastq_io.h
rename to src/fastq_io.hpp
index 54d92c7..8b58166 100644
--- a/src/fastq_io.h
+++ b/src/fastq_io.hpp
@@ -29,17 +29,15 @@
 
 #include <zlib.h>
 
-#ifdef AR_BZIP2_SUPPORT
 #include <bzlib.h>
-#endif
 
 
-#include "commontypes.h"
-#include "fastq.h"
-#include "linereader_joined.h"
-#include "scheduler.h"
-#include "strutils.h"
-#include "timer.h"
+#include "commontypes.hpp"
+#include "fastq.hpp"
+#include "linereader_joined.hpp"
+#include "scheduler.hpp"
+#include "strutils.hpp"
+#include "timer.hpp"
 
 namespace ar
 {
@@ -56,13 +54,8 @@ typedef std::vector<buffer_pair> buffer_vec;
 
 //! Number of FASTQ records to read for each data-chunk
 const size_t FASTQ_CHUNK_SIZE = 2 * 1024;
-
-#if defined(AR_GZIP_SUPPORT) || defined(AR_BZIP2_SUPPORT)
 //! Size of compressed chunks used to transport compressed data
 const size_t FASTQ_COMPRESSED_CHUNK = 40 * 1024;
-#endif
-
-
 
 
 /**
@@ -148,12 +141,12 @@ public:
     /** Finalizer; checks that all input has been processed. */
     virtual void finalize();
 
-private:
-    //! Not implemented
-    read_single_fastq(const read_single_fastq&);
-    //! Not implemented
-    read_single_fastq& operator=(const read_single_fastq&);
+    //! Copy construction not supported
+    read_single_fastq(const read_single_fastq&) = delete;
+    //! Assignment not supported
+    read_single_fastq& operator=(const read_single_fastq&) = delete;
 
+private:
     //! Encoding used to parse FASTQ reads.
     const fastq_encoding* m_encoding;
     //! Current line in the input file (1-based)
@@ -193,12 +186,12 @@ public:
     /** Finalizer; checks that all input has been processed. */
     virtual void finalize();
 
-private:
-    //! Not implemented
-    read_paired_fastq(const read_paired_fastq&);
-    //! Not implemented
-    read_paired_fastq& operator=(const read_paired_fastq&);
+    //! Copy construction not supported
+    read_paired_fastq(const read_paired_fastq&) = delete;
+    //! Assignment not supported
+    read_paired_fastq& operator=(const read_paired_fastq&) = delete;
 
+private:
     //! Encoding used to parse FASTQ reads.
     const fastq_encoding* m_encoding;
     //! Current line in the input file (1-based)
@@ -239,12 +232,12 @@ public:
     /** Finalizer; checks that all input has been processed. */
     virtual void finalize();
 
-private:
-    //! Not implemented
-    read_interleaved_fastq(const read_interleaved_fastq&);
-    //! Not implemented
-    read_interleaved_fastq& operator=(const read_interleaved_fastq&);
+    //! Copy construction not supported
+    read_interleaved_fastq(const read_interleaved_fastq&) = delete;
+    //! Assignment not supported
+    read_interleaved_fastq& operator=(const read_interleaved_fastq&) = delete;
 
+private:
     //! Encoding used to parse FASTQ reads.
     const fastq_encoding* m_encoding;
     //! Current line in the input file (1-based)
@@ -261,7 +254,6 @@ private:
 
 
 
-#ifdef AR_BZIP2_SUPPORT
 /**
  * BZip2 compression step; takes any lines in the input chunk, compresses them,
  * and adds them to the buffer list of the chunk, before forwarding it. */
@@ -277,12 +269,12 @@ public:
     /** Checks that all input has been processed and frees stream. */
     virtual void finalize();
 
-private:
-    //! Not implemented
-    bzip2_fastq(const bzip2_fastq&);
-    //! Not implemented
-    bzip2_fastq& operator=(const bzip2_fastq&);
+    //! Copy construction not supported
+    bzip2_fastq(const bzip2_fastq&) = delete;
+    //! Assignment not supported
+    bzip2_fastq& operator=(const bzip2_fastq&) = delete;
 
+private:
     //! N reads which did not result in an output chunk
     size_t m_buffered_reads;
     //! The analytical step following this step
@@ -295,10 +287,7 @@ private:
     std::mutex m_lock;
 };
 
-#endif
 
-
-#ifdef AR_GZIP_SUPPORT
 /**
  * GZip compression step; takes any lines in the input chunk, compresses them,
  * and adds them to the buffer list of the chunk, before forwarding it. */
@@ -314,12 +303,12 @@ public:
     /** Checks that all input has been processed and frees stream. */
     virtual void finalize();
 
-private:
-    //! Not implemented
-    gzip_fastq(const gzip_fastq&);
-    //! Not implemented
-    gzip_fastq& operator=(const gzip_fastq&);
+    //! Copy construction not supported
+    gzip_fastq(const gzip_fastq&) = delete;
+    //! Assignment not supported
+    gzip_fastq& operator=(const gzip_fastq&) = delete;
 
+private:
     //! N reads which did not result in an output chunk
     size_t m_buffered_reads;
     //! The analytical step following this step
@@ -331,7 +320,6 @@ private:
     //! Lock used to verify that the analytical_step is only run sequentially.
     std::mutex m_lock;
 };
-#endif
 
 
 /**
diff --git a/src/linereader.cc b/src/linereader.cpp
similarity index 88%
rename from src/linereader.cc
rename to src/linereader.cpp
index fb573e4..dcdeab4 100644
--- a/src/linereader.cc
+++ b/src/linereader.cpp
@@ -28,8 +28,8 @@
 #include <iostream>
 #include <sstream>
 
-#include "linereader.h"
-#include "threads.h"
+#include "linereader.hpp"
+#include "threads.hpp"
 
 namespace ar
 {
@@ -96,15 +96,11 @@ bzip2_error::bzip2_error(const std::string& message)
 
 line_reader::line_reader(const std::string& fpath)
   : m_file(fopen(fpath.c_str(), "rb"))
-#ifdef AR_GZIP_SUPPORT
-  , m_gzip_stream(NULL)
-#endif
-#ifdef AR_BZIP2_SUPPORT
-  , m_bzip2_stream(NULL)
-#endif
-  , m_buffer(NULL)
-  , m_buffer_ptr(NULL)
-  , m_buffer_end(NULL)
+  , m_gzip_stream(nullptr)
+  , m_bzip2_stream(nullptr)
+  , m_buffer(nullptr)
+  , m_buffer_ptr(nullptr)
+  , m_buffer_end(nullptr)
   , m_raw_buffer(new char[BUF_SIZE])
   , m_raw_buffer_end(m_raw_buffer + BUF_SIZE)
   , m_eof(false)
@@ -118,7 +114,15 @@ line_reader::line_reader(const std::string& fpath)
 line_reader::~line_reader()
 {
     try {
-        close();
+        close_buffers_gzip();
+        close_buffers_bzip2();
+
+        delete[] m_raw_buffer;
+        m_raw_buffer = nullptr;
+
+        if (fclose(m_file)) {
+            throw io_error("line_reader::close: error closing file", errno);
+        }
     } catch (const std::exception& error) {
         print_locker lock;
         std::cerr << "Error closing file: " << error.what() << std::endl;
@@ -160,50 +164,14 @@ bool line_reader::getline(std::string& dst)
 }
 
 
-void line_reader::close()
-{
-    close_buffers_gzip();
-    close_buffers_bzip2();
-
-    delete[] m_raw_buffer;
-    m_raw_buffer = NULL;
-
-    if (m_file && fclose(m_file)) {
-        throw io_error("line_reader::close: error closing file", errno);
-    }
-
-    m_file = NULL;
-}
-
-
-bool line_reader::eof() const
-{
-    return m_eof;
-}
-
-
-bool line_reader::is_open() const
-{
-    return m_file;
-}
-
-
 void line_reader::refill_buffers()
 {
     if (m_buffer) {
-#ifdef AR_GZIP_SUPPORT
         if (m_gzip_stream) {
             refill_buffers_gzip();
-        } else
-#endif
-
-#ifdef AR_BZIP2_SUPPORT
-        if (m_bzip2_stream) {
+        } else if (m_bzip2_stream) {
             refill_buffers_bzip2();
-        } else
-#endif
-
-        {
+        } else {
             refill_raw_buffer();
             refill_buffers_uncompressed();
         }
@@ -259,15 +227,14 @@ bool line_reader::identify_gzip() const
 
 void line_reader::initialize_buffers_gzip()
 {
-#ifdef AR_GZIP_SUPPORT
     m_buffer = new char[BUF_SIZE];
     m_buffer_ptr = m_buffer + BUF_SIZE;
     m_buffer_end = m_buffer + BUF_SIZE;
 
     m_gzip_stream = new z_stream();
-    m_gzip_stream->zalloc = Z_NULL;
-    m_gzip_stream->zfree = Z_NULL;
-    m_gzip_stream->opaque = Z_NULL;
+    m_gzip_stream->zalloc = nullptr;
+    m_gzip_stream->zfree = nullptr;
+    m_gzip_stream->opaque = nullptr;
 
     m_gzip_stream->avail_in = m_raw_buffer_end - m_raw_buffer;
     m_gzip_stream->next_in = reinterpret_cast<Bytef*>(m_raw_buffer);
@@ -278,31 +245,25 @@ void line_reader::initialize_buffers_gzip()
 
         case Z_MEM_ERROR:
             throw gzip_error("line_reader::initialize_buffers_gzip: insufficient memory",
-                             m_gzip_stream ? m_gzip_stream->msg : NULL);
+                             m_gzip_stream ? m_gzip_stream->msg : nullptr);
 
         case Z_VERSION_ERROR:
             throw gzip_error("line_reader::initialize_buffers_gzip: incompatible zlib version",
-                             m_gzip_stream ? m_gzip_stream->msg : NULL);
+                             m_gzip_stream ? m_gzip_stream->msg : nullptr);
 
         case Z_STREAM_ERROR:
             throw gzip_error("line_reader::initialize_buffers_gzip: invalid parameters",
-                             m_gzip_stream ? m_gzip_stream->msg : NULL);
+                             m_gzip_stream ? m_gzip_stream->msg : nullptr);
 
         default:
             throw gzip_error("line_reader::initialize_buffers_gzip: unknown error",
-                             m_gzip_stream ? m_gzip_stream->msg : NULL);
+                             m_gzip_stream ? m_gzip_stream->msg : nullptr);
     }
-#else
-    throw gzip_error("Attempted to read gzipped file, but gzip"
-                     "support was not enabled when AdapterRemoval"
-                     "was compiled");
-#endif
 }
 
 
 void line_reader::refill_buffers_gzip()
 {
-#ifdef AR_GZIP_SUPPORT
     if (!m_gzip_stream->avail_in) {
         refill_raw_buffer();
         m_gzip_stream->avail_in = m_raw_buffer_end - m_raw_buffer;
@@ -320,28 +281,26 @@ void line_reader::refill_buffers_gzip()
             // Handle concatenated streams; causes unnecessary reset at EOF
             if (inflateReset(m_gzip_stream) != Z_OK) {
                 throw gzip_error("line_reader::refill_buffers_gzip: failed to reset stream",
-                             m_gzip_stream ? m_gzip_stream->msg : NULL);
+                             m_gzip_stream ? m_gzip_stream->msg : nullptr);
             }
             break;
 
         case Z_STREAM_ERROR:
             throw gzip_error("line_reader::refill_buffers_gzip: inconsistent stream state",
-                             m_gzip_stream ? m_gzip_stream->msg : NULL);
+                             m_gzip_stream ? m_gzip_stream->msg : nullptr);
 
         default:
             throw gzip_error("line_reader::refill_buffers_gzip: unknown error",
-                             m_gzip_stream ? m_gzip_stream->msg : NULL);
+                             m_gzip_stream ? m_gzip_stream->msg : nullptr);
     }
 
     m_buffer_ptr = m_buffer;
     m_buffer_end = m_buffer + (BUF_SIZE - m_gzip_stream->avail_out);
-#endif
 }
 
 
 void line_reader::close_buffers_gzip()
 {
-#ifdef AR_GZIP_SUPPORT
     if (m_gzip_stream) {
         switch (inflateEnd(m_gzip_stream)) {
             case Z_OK:
@@ -349,28 +308,25 @@ void line_reader::close_buffers_gzip()
 
             case Z_STREAM_ERROR:
                 throw gzip_error("line_reader::close: stream error",
-                                 m_gzip_stream ? m_gzip_stream->msg : NULL);
+                                 m_gzip_stream ? m_gzip_stream->msg : nullptr);
 
             default:
                 throw gzip_error("Unknown error in line_reader::close",
-                                 m_gzip_stream ? m_gzip_stream->msg : NULL);
+                                 m_gzip_stream ? m_gzip_stream->msg : nullptr);
         }
 
         delete m_gzip_stream;
-        m_gzip_stream = NULL;
+        m_gzip_stream = nullptr;
 
         delete[] m_buffer;
-        m_buffer = NULL;
+        m_buffer = nullptr;
     }
-#endif
 }
 
 
-#ifdef AR_BZIP2_SUPPORT
-
 void bzip2_initialize_stream(bz_stream* stream)
 {
-    switch (BZ2_bzDecompressInit(stream, 0, 0)) {
+    switch (BZ2_bzDecompressInit(stream, /* verbosity */ 0, /* small */ 0)) {
         case BZ_OK:
             break;
 
@@ -412,8 +368,6 @@ void bzip2_close_stream(bz_stream* stream)
     }
 }
 
-#endif
-
 
 bool line_reader::identify_bzip2() const
 {
@@ -436,31 +390,24 @@ bool line_reader::identify_bzip2() const
 
 void line_reader::initialize_buffers_bzip2()
 {
-#ifdef AR_BZIP2_SUPPORT
     m_buffer = new char[BUF_SIZE];
     m_buffer_ptr = m_buffer + BUF_SIZE;
     m_buffer_end = m_buffer + BUF_SIZE;
 
     m_bzip2_stream = new bz_stream();
-    m_bzip2_stream->bzalloc = NULL;
-    m_bzip2_stream->bzfree = NULL;
-    m_bzip2_stream->opaque = NULL;
+    m_bzip2_stream->bzalloc = nullptr;
+    m_bzip2_stream->bzfree = nullptr;
+    m_bzip2_stream->opaque = nullptr;
 
     m_bzip2_stream->avail_in = m_raw_buffer_end - m_raw_buffer;
     m_bzip2_stream->next_in = m_raw_buffer;
 
     bzip2_initialize_stream(m_bzip2_stream);
-#else
-    throw bzip2_error("Attempted to read bzipped file, but bzip2"
-                      "support was not enabled when AdapterRemoval"
-                      "was compiled");
-#endif
 }
 
 
 void line_reader::refill_buffers_bzip2()
 {
-#ifdef AR_BZIP2_SUPPORT
     if (!m_bzip2_stream->avail_in) {
         refill_raw_buffer();
         m_bzip2_stream->avail_in = m_raw_buffer_end - m_raw_buffer;
@@ -505,23 +452,20 @@ void line_reader::refill_buffers_bzip2()
 
     m_buffer_ptr = m_buffer;
     m_buffer_end = m_buffer + (BUF_SIZE - m_bzip2_stream->avail_out);
-#endif
 }
 
 
 void line_reader::close_buffers_bzip2()
 {
-#ifdef AR_BZIP2_SUPPORT
     if (m_bzip2_stream) {
         bzip2_close_stream(m_bzip2_stream);
 
         delete m_bzip2_stream;
-        m_bzip2_stream = NULL;
+        m_bzip2_stream = nullptr;
 
         delete[] m_buffer;
-        m_buffer = NULL;
+        m_buffer = nullptr;
     }
-#endif
 }
 
 } // namespace ar
diff --git a/src/linereader.h b/src/linereader.hpp
similarity index 91%
rename from src/linereader.h
rename to src/linereader.hpp
index 4bd6e94..83da28b 100644
--- a/src/linereader.h
+++ b/src/linereader.hpp
@@ -24,16 +24,13 @@
 #ifndef GZFILE_H
 #define GZFILE_H
 
-#include <string>
 #include <cstdio>
+#include <ios>
+#include <string>
 
-#ifdef AR_GZIP_SUPPORT
 #include <zlib.h>
-#endif
-
-#ifdef AR_BZIP2_SUPPORT
 #include <bzlib.h>
-#endif
+
 
 namespace ar
 {
@@ -50,7 +47,7 @@ public:
 class gzip_error : public io_error
 {
 public:
-    gzip_error(const std::string& message, const char* gzip_msg = NULL);
+    gzip_error(const std::string& message, const char* gzip_msg = nullptr);
 };
 
 
@@ -83,6 +80,7 @@ public:
  * Currently reads
  *  - uncompressed files
  *  - gzip compressed files
+ *  - bzip2 compressed files
  *
  * Errors are reported using either 'io_error' or 'gzip_error'.
  */
@@ -98,21 +96,12 @@ public:
     /** Reads a lien into dst, returning false on EOF. */
     bool getline(std::string& dst);
 
-    /** Closes the file, if still open. */
-    void close();
-
-    /** Returns true if the file has been closed. */
-    bool is_open() const;
-
-    /** Returns true if a read after EOF has been attempted. */
-    bool eof() const;
+    //! Copy construction not supported
+    line_reader(const line_reader&) = delete;
+    //! Assignment not supported
+    line_reader& operator=(const line_reader&) = delete;
 
 private:
-    //! Not implemented
-    line_reader(const line_reader&);
-    //! Not implemented
-    line_reader& operator=(const line_reader&);
-
     //! Refills 'm_buffer' and sets 'm_buffer_ptr' and 'm_buffer_end'.
     void refill_buffers();
 
@@ -123,11 +112,8 @@ private:
     /** Points 'm_buffer' and other points to corresponding 'm_raw_buffer's. */
     void refill_buffers_uncompressed();
 
-
-#ifdef AR_GZIP_SUPPORT
     //! GZip stream pointer; used if input it detected to be gzip compressed.
     z_stream* m_gzip_stream;
-#endif
 
     /** Returns true if the raw buffer contains gzip'd data. */
     bool identify_gzip() const;
@@ -138,11 +124,8 @@ private:
     /** Closes gzip buffers and frees associated memory. */
     void close_buffers_gzip();
 
-
-#ifdef AR_BZIP2_SUPPORT
     //! GZip stream pointer; used if input it detected to be gzip compressed.
     bz_stream* m_bzip2_stream;
-#endif
 
     /** Returns true if the raw buffer contains bzip2'd data. */
     bool identify_bzip2() const;
@@ -153,7 +136,6 @@ private:
     /** Closes gzip2 buffers and frees associated memory. */
     void close_buffers_bzip2();
 
-
     //! Pointer to buffer of decompressed data.
     char* m_buffer;
     //! Pointer to current location in input buffer.
diff --git a/src/linereader_joined.cc b/src/linereader_joined.cpp
similarity index 97%
rename from src/linereader_joined.cc
rename to src/linereader_joined.cpp
index 6010134..c4ebee6 100644
--- a/src/linereader_joined.cc
+++ b/src/linereader_joined.cpp
@@ -29,9 +29,9 @@
 #include <iostream>
 #include <sstream>
 
-#include "debug.h"
-#include "linereader_joined.h"
-#include "threads.h"
+#include "debug.hpp"
+#include "linereader_joined.hpp"
+#include "threads.hpp"
 
 
 namespace ar
diff --git a/src/linereader_joined.h b/src/linereader_joined.hpp
similarity index 91%
rename from src/linereader_joined.h
rename to src/linereader_joined.hpp
index 81283f8..45d69de 100644
--- a/src/linereader_joined.h
+++ b/src/linereader_joined.hpp
@@ -26,8 +26,8 @@
 
 #include <memory>
 
-#include "commontypes.h"
-#include "linereader.h"
+#include "commontypes.hpp"
+#include "linereader.hpp"
 
 
 namespace ar
@@ -57,6 +57,11 @@ public:
      */
     bool getline(std::string& dst);
 
+    //! Copy construction not supported
+    joined_line_readers(const joined_line_readers&) = delete;
+    //! Assignment not supported
+    joined_line_readers& operator=(const joined_line_readers&) = delete;
+
 private:
     /**
      * Open the next file, removes it from the queue, and returns true; returns
@@ -64,11 +69,6 @@ private:
      */
     bool open_next_file();
 
-    //! Not implemented
-    joined_line_readers(const joined_line_readers&);
-    //! Not implemented
-    joined_line_readers& operator=(const joined_line_readers&);
-
     //! Files left to read; stored in reverse order.
     string_vec m_filenames;
     //! Currently open file, if any.
diff --git a/src/main.cc b/src/main.cpp
similarity index 81%
rename from src/main.cc
rename to src/main.cpp
index a6e88f1..6382b76 100644
--- a/src/main.cc
+++ b/src/main.cpp
@@ -24,18 +24,18 @@
 \*************************************************************************/
 #include <iostream>
 
-#include "debug.h"
-#include "main.h"
-#include "userconfig.h"
+#include "debug.hpp"
+#include "main.hpp"
+#include "userconfig.hpp"
 
 namespace ar
 {
 
-// See main_adapter_rm.cc
+// See main_adapter_rm.cpp
 int remove_adapter_sequences(const userconfig& config);
-// See main_adapter_id.cc
+// See main_adapter_id.cpp
 int identify_adapter_sequences(const userconfig& config);
-// See main_demultiplex.cc
+// See main_demultiplex.cpp
 int demultiplex_sequences(const userconfig& config);
 
 } // namespace ar
@@ -47,32 +47,43 @@ int main(int argc, char *argv[])
     std::ios_base::sync_with_stdio(false);
 
     userconfig config(NAME, VERSION, HELPTEXT);
-    const argparse::parse_result result = config.parse_args(argc, argv);
-    if (result == argparse::pr_error) {
-        return 1;
-    } else if (result == argparse::pr_exit) {
-        // --version, --help, or similar used.
-        return 0;
+    switch (config.parse_args(argc, argv)) {
+        case argparse::parse_result::error: {
+            return 1;
+        }
+
+        case argparse::parse_result::exit: {
+            // --version, --help, or similar used.
+            return 0;
+        }
+
+        default: {
+            // Ok
+        }
     }
 
     auto returncode = 0;
     switch (config.run_type) {
-        case ar_trim_adapters:
+        case ar_command::trim_adapters: {
             returncode = remove_adapter_sequences(config);
             break;
+        }
 
-        case ar_demultiplex_sequences:
+        case ar_command::demultiplex_sequences: {
             returncode = demultiplex_sequences(config);
             break;
+        }
 
-        case ar_identify_adapters:
+        case ar_command::identify_adapters: {
             return identify_adapter_sequences(config);
+        }
 
-        default:
+        default: {
             std::cerr << "ERROR: Unknown run-type: "
                       << static_cast<size_t>(config.run_type)
                       << std::endl;
             return 1;
+        }
     }
 
     if (returncode) {
diff --git a/src/main.h b/src/main.hpp
similarity index 98%
rename from src/main.h
rename to src/main.hpp
index 23c86b1..66bef93 100644
--- a/src/main.h
+++ b/src/main.hpp
@@ -31,7 +31,7 @@ namespace ar
 {
 
 const std::string NAME = "AdapterRemoval";
-const std::string VERSION = "ver. 2.2.1a";
+const std::string VERSION = "ver. 2.2.2";
 const std::string HELPTEXT = \
     "This program searches for and removes remnant adapter sequences from\n"
     "your read data.  The program can analyze both single end and paired end\n"
diff --git a/src/main_adapter_id.cc b/src/main_adapter_id.cpp
similarity index 95%
rename from src/main_adapter_id.cc
rename to src/main_adapter_id.cpp
index 7cf07c4..f00f2a3 100644
--- a/src/main_adapter_id.cc
+++ b/src/main_adapter_id.cpp
@@ -30,13 +30,13 @@
 #include <stdexcept>
 #include <vector>
 
-#include "alignment.h"
-#include "debug.h"
-#include "fastq_io.h"
-#include "scheduler.h"
-#include "strutils.h"
-#include "timer.h"
-#include "userconfig.h"
+#include "alignment.hpp"
+#include "debug.hpp"
+#include "fastq_io.hpp"
+#include "scheduler.hpp"
+#include "strutils.hpp"
+#include "timer.hpp"
+#include "userconfig.hpp"
 
 
 namespace ar
@@ -307,11 +307,10 @@ public:
     //! Statistics object for (number of) processed reads
     statistics_ptr stats;
 
-private:
-    //! Not implemented
-    adapter_stats(const adapter_stats&);
-    //! Not implemented
-    adapter_stats& operator=(const adapter_stats&);
+    //! Copy construction not supported
+    adapter_stats(const adapter_stats&) = delete;
+    //! Assignment not supported
+    adapter_stats& operator=(const adapter_stats&) = delete;
 };
 
 
@@ -333,12 +332,12 @@ protected:
         (*dst) += (*src);
     }
 
-private:
-    //! Not implemented
-    adapter_sink(const adapter_sink&);
-    //! Not implemented
-    adapter_sink& operator=(const adapter_sink&);
+    //! Copy construction not supported
+    adapter_sink(const adapter_sink&) = delete;
+    //! Assignment not supported
+    adapter_sink& operator=(const adapter_sink&) = delete;
 
+private:
     const userconfig& m_config;
 };
 
@@ -350,7 +349,7 @@ class adapter_identification : public analytical_step
 {
 public:
     adapter_identification(const userconfig& config)
-      : analytical_step(analytical_step::unordered)
+      : analytical_step(analytical_step::ordering::unordered)
       , m_config(config)
       , m_timer("reads")
       , m_sinks(config)
@@ -360,7 +359,7 @@ public:
     chunk_vec process(analytical_chunk* chunk)
     {
         if (!chunk) {
-            throw std::invalid_argument("sink received NULL chunk");
+            throw std::invalid_argument("sink received nullptr chunk");
         }
 
         const fastq empty_adapter("dummy", "", "");
diff --git a/src/main_adapter_rm.cc b/src/main_adapter_rm.cpp
similarity index 90%
rename from src/main_adapter_rm.cc
rename to src/main_adapter_rm.cpp
index a544a64..1df49eb 100644
--- a/src/main_adapter_rm.cc
+++ b/src/main_adapter_rm.cpp
@@ -31,15 +31,15 @@
 #include <string>
 #include <vector>
 
-#include "alignment.h"
-#include "debug.h"
-#include "demultiplex.h"
-#include "fastq.h"
-#include "fastq_io.h"
-#include "main.h"
-#include "strutils.h"
-#include "trimmed_reads.h"
-#include "userconfig.h"
+#include "alignment.hpp"
+#include "debug.hpp"
+#include "demultiplex.hpp"
+#include "fastq.hpp"
+#include "fastq_io.hpp"
+#include "main.hpp"
+#include "strutils.hpp"
+#include "trimmed_reads.hpp"
+#include "userconfig.hpp"
 
 
 namespace ar
@@ -105,7 +105,7 @@ void write_settings(const userconfig& config, std::ostream& output, int nth)
     if (nth == -1) {
         const fastq_pair_vec adapters = config.adapters.get_raw_adapters();
         size_t adapter_id = 0;
-        for (fastq_pair_vec::const_iterator it = adapters.begin(); it != adapters.end(); ++it, ++adapter_id) {
+        for (auto it = adapters.cbegin(); it != adapters.cend(); ++it, ++adapter_id) {
             output << "\nAdapter1[" << adapter_id + 1 << "]: " << it->first.sequence();
 
             fastq adapter_2 = it->second;
@@ -116,7 +116,7 @@ void write_settings(const userconfig& config, std::ostream& output, int nth)
     } else {
         const string_pair_vec adapters = config.adapters.get_pretty_adapter_set(nth);
         size_t adapter_id = 0;
-        for (string_pair_vec::const_iterator it = adapters.begin(); it != adapters.end(); ++it, ++adapter_id) {
+        for (auto it = adapters.cbegin(); it != adapters.cend(); ++it, ++adapter_id) {
             output << "\nAdapter1[" << adapter_id + 1 << "]: " << it->first;
             output << "\nAdapter2[" << adapter_id + 1 << "]: " << it->second << "\n";
         }
@@ -214,19 +214,19 @@ void write_trimming_settings(const userconfig& config,
         const std::vector<size_t>& lengths = stats.read_lengths.at(length);
         const size_t total = std::accumulate(lengths.begin(), lengths.end(), 0);
 
-        settings << length << '\t' << lengths.at(rt_mate_1);
+        settings << length << '\t' << lengths.at(static_cast<size_t>(read_type::mate_1));
 
         if (config.paired_ended_mode) {
-            settings << '\t' << lengths.at(rt_mate_2)
-                     << '\t' << lengths.at(rt_singleton);
+            settings << '\t' << lengths.at(static_cast<size_t>(read_type::mate_2))
+                     << '\t' << lengths.at(static_cast<size_t>(read_type::singleton));
         }
 
         if (config.collapse) {
-            settings << '\t' << lengths.at(rt_collapsed)
-                     << '\t' << lengths.at(rt_collapsed_truncated);
+            settings << '\t' << lengths.at(static_cast<size_t>(read_type::collapsed))
+                     << '\t' << lengths.at(static_cast<size_t>(read_type::collapsed_truncated));
         }
 
-        settings << '\t' << lengths.at(rt_discarded)
+        settings << '\t' << lengths.at(static_cast<size_t>(read_type::discarded))
                  << '\t' << total << '\n';
     }
 
@@ -234,7 +234,7 @@ void write_trimming_settings(const userconfig& config,
 }
 
 
-//! Implemented in main_demultiplex.cc
+//! Implemented in main_demultiplex.cpp
 void write_demultiplex_statistics(std::ofstream& output,
                                   const userconfig& config,
                                   const demultiplex_reads* step);
@@ -292,25 +292,25 @@ void process_collapsed_read(const userconfig& config,
     if (config.is_acceptable_read(collapsed_read)) {
         stats.total_number_of_nucleotides += collapsed_read.length();
         stats.total_number_of_good_reads++;
-        stats.inc_length_count(was_trimmed ? rt_collapsed_truncated : rt_collapsed,
+        stats.inc_length_count(was_trimmed ? read_type::collapsed_truncated : read_type::collapsed,
                                collapsed_read.length());
 
         if (was_trimmed) {
-            chunks.add_collapsed_truncated_read(collapsed_read, PASSED, read_count);
+            chunks.add_collapsed_truncated_read(collapsed_read, read_status::passed, read_count);
             stats.number_of_truncated_collapsed++;
         } else {
-            chunks.add_collapsed_read(collapsed_read, PASSED, read_count);
+            chunks.add_collapsed_read(collapsed_read, read_status::passed, read_count);
             stats.number_of_full_length_collapsed++;
         }
     } else {
         stats.discard1++;
         stats.discard2++;
-        stats.inc_length_count(rt_discarded, collapsed_read.length());
+        stats.inc_length_count(read_type::discarded, collapsed_read.length());
 
         if (was_trimmed) {
-            chunks.add_collapsed_truncated_read(collapsed_read, FAILED, read_count);
+            chunks.add_collapsed_truncated_read(collapsed_read, read_status::failed, read_count);
         } else {
-            chunks.add_collapsed_read(collapsed_read, FAILED, read_count);
+            chunks.add_collapsed_read(collapsed_read, read_status::failed, read_count);
         }
     }
 }
@@ -320,7 +320,7 @@ class reads_processor : public analytical_step
 {
 public:
     reads_processor(const userconfig& config, size_t nth)
-      : analytical_step(analytical_step::unordered)
+      : analytical_step(analytical_step::ordering::unordered)
       , m_config(config)
       , m_adapters(config.adapters.get_adapter_set(nth))
       , m_stats(config)
@@ -377,9 +377,7 @@ public:
         trimmed_reads chunks(m_config, offset, read_chunk->eof);
         stats_sink::pointer stats = m_stats.get_sink();
 
-        for (fastq_vec::iterator it = read_chunk->reads_1.begin(); it != read_chunk->reads_1.end(); ++it) {
-            fastq& read = *it;
-
+        for (auto& read : read_chunk->reads_1) {
             const alignment_info alignment = align_single_ended_sequence(read, m_adapters, m_config.shift);
 
             if (m_config.is_good_alignment(alignment)) {
@@ -388,7 +386,7 @@ public:
                 stats->well_aligned_reads++;
 
                 if (m_config.is_alignment_collapsible(alignment)) {
-                    process_collapsed_read(m_config, *stats, read, NULL, chunks);
+                    process_collapsed_read(m_config, *stats, read, nullptr, chunks);
                     continue;
                 }
             } else {
@@ -401,13 +399,13 @@ public:
                 stats->total_number_of_good_reads++;
                 stats->total_number_of_nucleotides += read.length();
 
-                chunks.add_mate_1_read(read, PASSED);
-                stats->inc_length_count(rt_mate_1, read.length());
+                chunks.add_mate_1_read(read, read_status::passed);
+                stats->inc_length_count(read_type::mate_1, read.length());
             } else {
                 stats->discard1++;
-                stats->inc_length_count(rt_discarded, read.length());
+                stats->inc_length_count(read_type::discarded, read.length());
 
-                chunks.add_mate_1_read(read, FAILED);
+                chunks.add_mate_1_read(read, read_status::failed);
             }
         }
 
@@ -437,12 +435,12 @@ protected:
         // Intentionally left empty
     }
 
-private:
-    //! Not implemented
-    rng_sink(const rng_sink&);
-    //! Not implemented
-    rng_sink& operator=(const rng_sink&);
+    //! Copy construction not supported
+    rng_sink(const rng_sink&) = delete;
+    //! Assignment not supported
+    rng_sink& operator=(const rng_sink&) = delete;
 
+private:
     mutable std::mt19937 m_seed;
 };
 
@@ -468,8 +466,8 @@ public:
 
         AR_DEBUG_ASSERT(read_chunk->reads_1.size() == read_chunk->reads_2.size());
 
-        fastq_vec::iterator it_1 = read_chunk->reads_1.begin();
-        fastq_vec::iterator it_2 = read_chunk->reads_2.begin();
+        auto it_1 = read_chunk->reads_1.begin();
+        auto it_2 = read_chunk->reads_2.begin();
         while (it_1 != read_chunk->reads_1.end()) {
             fastq read_1 = *it_1++;
             fastq read_2 = *it_2++;
@@ -494,13 +492,13 @@ public:
                                            *stats,
                                            collapsed_read,
                                            // Make sure read_2 header is updated, if needed
-                                           m_config.combined_output ? &read_2 : NULL,
+                                           m_config.combined_output ? &read_2 : nullptr,
                                            chunks);
 
                     if (m_config.combined_output) {
                         // Dummy read with read-count of zero; both mates have
                         // already been accounted for in process_collapsed_read
-                        chunks.add_mate_2_read(read_2, FAILED, 0);
+                        chunks.add_mate_2_read(read_2, read_status::failed, 0);
                     }
                     continue;
                 }
@@ -523,12 +521,12 @@ public:
             stats->total_number_of_good_reads += read_1_acceptable;
             stats->total_number_of_good_reads += read_2_acceptable;
 
-            const read_status state_1 = read_1_acceptable ? PASSED : FAILED;
-            const read_status state_2 = read_2_acceptable ? PASSED : FAILED;
+            const read_status state_1 = read_1_acceptable ? read_status::passed : read_status::failed;
+            const read_status state_2 = read_2_acceptable ? read_status::passed : read_status::failed;
 
             if (read_1_acceptable && read_2_acceptable) {
-                stats->inc_length_count(rt_mate_1, read_1.length());
-                stats->inc_length_count(rt_mate_2, read_2.length());
+                stats->inc_length_count(read_type::mate_1, read_1.length());
+                stats->inc_length_count(read_type::mate_2, read_2.length());
             } else {
                 // Count singleton reads
                 stats->keep1 += read_1_acceptable && !read_2_acceptable;
@@ -537,8 +535,8 @@ public:
                 stats->discard1 += !read_1_acceptable;
                 stats->discard2 += !read_2_acceptable;
 
-                stats->inc_length_count(read_1_acceptable ? rt_singleton : rt_discarded, read_1.length());
-                stats->inc_length_count(read_2_acceptable ? rt_singleton : rt_discarded, read_2.length());
+                stats->inc_length_count(read_1_acceptable ? read_type::singleton : read_type::discarded, read_1.length());
+                stats->inc_length_count(read_2_acceptable ? read_type::singleton : read_type::discarded, read_2.length());
             }
 
             // Queue reads last, since this result in modifications to lengths
@@ -588,22 +586,15 @@ bool write_settings(const userconfig& config, const std::vector<reads_processor*
 void add_write_step(const userconfig& config, scheduler& sch, size_t offset,
                     const std::string& name, analytical_step* step)
 {
-#ifdef AR_GZIP_SUPPORT
     if (config.gzip) {
         sch.add_step(offset + ai_zip_offset, "write_gzip_" + name, step);
         sch.add_step(offset, "gzip_" + name,
                      new gzip_fastq(config, offset + ai_zip_offset));
-    } else
-#endif
-
-#ifdef AR_BZIP2_SUPPORT
-    if (config.bzip2) {
+    } else if (config.bzip2) {
         sch.add_step(offset + ai_zip_offset, "write_bzip2_" + name, step);
         sch.add_step(offset, "bzip2_" + name,
                      new bzip2_fastq(config, offset + ai_zip_offset));
-    } else
-#endif
-    {
+    } else {
         sch.add_step(offset, "write_" + name, step);
     }
 }
@@ -615,7 +606,7 @@ int remove_adapter_sequences_se(const userconfig& config)
 
     scheduler sch;
     std::vector<reads_processor*> processors;
-    demultiplex_reads* demultiplexer = NULL;
+    demultiplex_reads* demultiplexer = nullptr;
 
     try {
         if (config.adapters.barcode_count()) {
@@ -687,7 +678,7 @@ int remove_adapter_sequences_pe(const userconfig& config)
 
     scheduler sch;
     std::vector<reads_processor*> processors;
-    demultiplex_reads* demultiplexer = NULL;
+    demultiplex_reads* demultiplexer = nullptr;
 
     try {
         // Step 1: Read input file
diff --git a/src/main_demultiplex.cc b/src/main_demultiplex.cpp
similarity index 96%
rename from src/main_demultiplex.cc
rename to src/main_demultiplex.cpp
index 6f209f6..51309b9 100644
--- a/src/main_demultiplex.cc
+++ b/src/main_demultiplex.cpp
@@ -28,19 +28,19 @@
 #include <iostream>
 #include <string>
 
-#include "debug.h"
-#include "demultiplex.h"
-#include "fastq.h"
-#include "fastq_io.h"
-#include "main.h"
-//#include "strutils.h"
-#include "userconfig.h"
+#include "debug.hpp"
+#include "demultiplex.hpp"
+#include "fastq.hpp"
+#include "fastq_io.hpp"
+#include "main.hpp"
+//#include "strutils.hpp"
+#include "userconfig.hpp"
 
 
 namespace ar
 {
 
-//! Implemented in main_adapter_rm.cc
+//! Implemented in main_adapter_rm.cpp
 void add_write_step(const userconfig& config, scheduler& sch, size_t offset,
                     const std::string& name, analytical_step* step);
 
@@ -183,7 +183,7 @@ class se_demultiplexed_reads_processor : public analytical_step
 {
 public:
     se_demultiplexed_reads_processor(const userconfig& config, size_t nth)
-      : analytical_step(analytical_step::unordered)
+      : analytical_step(analytical_step::ordering::unordered)
       , m_config(config)
       , m_nth(nth)
     {
@@ -196,7 +196,7 @@ public:
 
         output_chunk_ptr encoded_reads(new fastq_output_chunk(read_chunk->eof));
 
-        for (auto const& read: read_chunk->reads_1) {
+        for (const auto& read : read_chunk->reads_1) {
             encoded_reads->add(*m_config.quality_output_fmt, read);
         }
 
@@ -216,7 +216,7 @@ class pe_demultiplexed_reads_processor : public analytical_step
 {
 public:
     pe_demultiplexed_reads_processor(const userconfig& config, size_t nth)
-      : analytical_step(analytical_step::unordered)
+      : analytical_step(analytical_step::ordering::unordered)
       , m_config(config)
       , m_nth(nth)
     {
@@ -269,7 +269,7 @@ int demultiplex_sequences_se(const userconfig& config)
     std::cerr << "Demultiplexing single ended reads ..." << std::endl;
 
     scheduler sch;
-    demultiplex_reads* demultiplexer = NULL;
+    demultiplex_reads* demultiplexer = nullptr;
 
     try {
         // Step 1: Read input file
@@ -323,7 +323,7 @@ int demultiplex_sequences_pe(const userconfig& config)
     std::cerr << "Demultiplexing paired end reads ..." << std::endl;
 
     scheduler sch;
-    demultiplex_reads* demultiplexer = NULL;
+    demultiplex_reads* demultiplexer = nullptr;
 
     try {
         // Step 1: Read input file
diff --git a/src/scheduler.cc b/src/scheduler.cpp
similarity index 95%
rename from src/scheduler.cc
rename to src/scheduler.cpp
index f95f0d4..2702f58 100644
--- a/src/scheduler.cc
+++ b/src/scheduler.cpp
@@ -29,9 +29,9 @@
 #include <stdexcept>
 #include <unistd.h>
 
-#include "debug.h"
-#include "scheduler.h"
-#include "strutils.h"
+#include "debug.hpp"
+#include "scheduler.hpp"
+#include "strutils.hpp"
 
 namespace ar
 {
@@ -172,7 +172,7 @@ struct scheduler_step
 
     bool can_run(size_t next_chunk)
     {
-        if (ptr->get_ordering() == analytical_step::ordered) {
+        if (ptr->get_ordering() == analytical_step::ordering::ordered) {
             return (current_chunk == next_chunk);
         }
 
@@ -193,11 +193,10 @@ struct scheduler_step
     //! Short name for step used for error reporting
     std::string name;
 
-private:
-    //! Not implemented
-    scheduler_step(const scheduler_step&);
-    //! Not implemented
-    scheduler_step& operator=(const scheduler_step&);
+    //! Copy construction not supported
+    scheduler_step(const scheduler_step&) = delete;
+    //! Assignment not supported
+    scheduler_step& operator=(const scheduler_step&) = delete;
 };
 
 
@@ -378,12 +377,12 @@ void scheduler::execute_analytical_step(const step_ptr& step)
     // Schedule each of the resulting blocks
     for (auto& result: chunks) {
         step_ptr& other_step = m_steps.at(result.first);
-        AR_DEBUG_ASSERT(other_step != NULL);
+        AR_DEBUG_ASSERT(other_step != nullptr);
 
         std::lock_guard<std::mutex> step_lock(other_step->lock);
         // Inherit reference count from source chunk
         data_chunk next_chunk(chunk, std::move(result.second));
-        if (step->ptr->get_ordering() == analytical_step::ordered) {
+        if (step->ptr->get_ordering() == analytical_step::ordering::ordered) {
             // Ordered steps are allowed to not return results, so the chunk
             // numbering is remembered for down-stream steps
             next_chunk.chunk_id = other_step->last_chunk++;
@@ -402,7 +401,7 @@ void scheduler::execute_analytical_step(const step_ptr& step)
     }
 
     // Reschedule current step if ordered and next chunk is available
-    if (step->ptr->get_ordering() == analytical_step::ordered) {
+    if (step->ptr->get_ordering() == analytical_step::ordering::ordered) {
         std::lock_guard<std::mutex> step_lock(step->lock);
 
         step->current_chunk++;
diff --git a/src/scheduler.h b/src/scheduler.hpp
similarity index 95%
rename from src/scheduler.h
rename to src/scheduler.hpp
index c9d54ec..21d5028 100644
--- a/src/scheduler.h
+++ b/src/scheduler.hpp
@@ -32,7 +32,7 @@
 #include <string>
 #include <vector>
 
-#include "threads.h"
+#include "threads.hpp"
 
 namespace ar
 {
@@ -120,7 +120,7 @@ private:
 class analytical_step
 {
 public:
-    enum ordering {
+    enum class ordering {
         //! Data must be consumed in the input order
         ordered,
         //! Data may be consumed in any order
@@ -143,7 +143,7 @@ public:
     /**
      * Function called by pipeline to generate / process / consume data chunks.
      *
-     * Initially, the first step in the pipeline will receive NULL; during
+     * Initially, the first step in the pipeline will receive nullptr; during
      * subsequent cycles, the pipeline will return the value output from the
      * last step to the initial step, which may re-use it to avoid allocations;
      * if this is not done, the chunk must be freed by the first step.
@@ -176,6 +176,11 @@ public:
     /** Returns true if the step involves file IO. */
     bool file_io() const;
 
+    //! Copy construction not supported
+    analytical_step(const analytical_step&) = delete;
+    //! Assignment not supported
+    analytical_step& operator=(const analytical_step&) = delete;
+
 private:
     //! Stores the ordering of data chunks expected by the step
     const ordering m_step_order;
@@ -215,16 +220,16 @@ public:
     /** Runs the pipeline with n threads; return false on error. */
     bool run(int nthreads);
 
+    //! Copy construction not supported
+    scheduler(const scheduler&) = delete;
+    //! Assignment not supported
+    scheduler& operator=(const scheduler&) = delete;
+
 private:
     typedef std::shared_ptr<scheduler_step> step_ptr;
     typedef std::queue<step_ptr> runables;
     typedef std::vector<step_ptr> pipeline;
 
-    //! Not implemented
-    scheduler(const scheduler&);
-    //! Not implemented
-    scheduler& operator=(const scheduler&);
-
     /** Wrapper function which calls do_run on the provided thread. */
     static void run_wrapper(scheduler*);
     /** Work function; invoked by each thread. */
diff --git a/src/statistics.h b/src/statistics.hpp
similarity index 98%
rename from src/statistics.h
rename to src/statistics.hpp
index 13bdadb..0acb858 100644
--- a/src/statistics.h
+++ b/src/statistics.hpp
@@ -28,7 +28,9 @@
 #include <cstdlib>
 #include <vector>
 
-#include "vecutils.h"
+#include "commontypes.hpp"
+#include "vecutils.hpp"
+
 
 namespace ar
 {
@@ -86,7 +88,7 @@ struct statistics
     /** Increment the number of reads with of a given type / length. */
     void inc_length_count(read_type type, size_t length) {
         if (length >= read_lengths.size()) {
-            read_lengths.resize(length + 1, std::vector<size_t>(rt_max));
+            read_lengths.resize(length + 1, std::vector<size_t>(static_cast<size_t>(read_type::max)));
         }
 
         ++read_lengths.at(length).at(static_cast<size_t>(type));
diff --git a/src/strutils.cc b/src/strutils.cpp
similarity index 96%
rename from src/strutils.cc
rename to src/strutils.cpp
index 0693db5..6c248a9 100644
--- a/src/strutils.cc
+++ b/src/strutils.cpp
@@ -24,23 +24,21 @@
 #include <sys/ioctl.h>
 #include <unistd.h>
 
-#include "strutils.h"
+#include "strutils.hpp"
 
 namespace ar
 {
 
 std::string toupper(const std::string& str)
 {
-    std::string news = str;
-    for(size_t i = 0; i < news.length(); ++i) {
-        const char current = news.at(i);
+    std::string uppercased = str;
+    for (auto& current : uppercased) {
         if (current >= 'a' && current <= 'z') {
-            news.at(i) -= 32;
+            current -= 32;
         }
+    };
 
-    }
-
-    return news;
+    return uppercased;
 }
 
 
diff --git a/src/strutils.h b/src/strutils.hpp
similarity index 100%
rename from src/strutils.h
rename to src/strutils.hpp
diff --git a/src/threads.cc b/src/threads.cpp
similarity index 99%
rename from src/threads.cc
rename to src/threads.cpp
index 5533c85..8ec754b 100644
--- a/src/threads.cc
+++ b/src/threads.cpp
@@ -29,7 +29,7 @@
 #include <stdexcept>
 #include <unistd.h>
 
-#include "threads.h"
+#include "threads.hpp"
 
 #include <ctime>
 
diff --git a/src/threads.h b/src/threads.hpp
similarity index 95%
rename from src/threads.h
rename to src/threads.hpp
index 67d92f0..fe46865 100644
--- a/src/threads.h
+++ b/src/threads.hpp
@@ -90,12 +90,12 @@ public:
     //! Call to indicate that a partial line has been written to STDERR.
     void partial_stderr_output();
 
-private:
-    //! Not implemented
-    print_locker(const print_locker&);
-    //! Not implemented
-    print_locker& operator=(const print_locker&);
+    //! Copy construction not supported
+    print_locker(const print_locker&) = delete;
+    //! Assignment not supported
+    print_locker& operator=(const print_locker&) = delete;
 
+private:
     std::lock_guard<std::mutex> m_lock;
 };
 
diff --git a/src/timer.cc b/src/timer.cpp
similarity index 95%
rename from src/timer.cc
rename to src/timer.cpp
index 0f07083..7d798ca 100644
--- a/src/timer.cc
+++ b/src/timer.cpp
@@ -29,8 +29,8 @@
 #include <algorithm>
 #include <sys/time.h>
 
-#include "timer.h"
-#include "threads.h"
+#include "timer.hpp"
+#include "threads.hpp"
 
 namespace ar
 {
@@ -44,7 +44,7 @@ const size_t AVG_BLOCKS = 10;
 double get_current_time()
 {
     struct timeval timestamp;
-    gettimeofday(&timestamp, NULL);
+    gettimeofday(&timestamp, nullptr);
 
     return timestamp.tv_sec + timestamp.tv_usec / 1e6;
 }
@@ -117,8 +117,8 @@ void timer::increment(size_t inc)
         const double seconds = current_time - m_counts.front().first;
 
         size_t current_total = 0;
-        for (time_count_deque::iterator it = m_counts.begin(); it != m_counts.end(); ++it) {
-            current_total += it->second;
+        for (const auto& time_block : m_counts) {
+            current_total += time_block.second;
         }
 
         do_print(static_cast<size_t>(current_total / seconds), current_time);
diff --git a/src/timer.h b/src/timer.hpp
similarity index 100%
rename from src/timer.h
rename to src/timer.hpp
diff --git a/src/trimmed_reads.cc b/src/trimmed_reads.cpp
similarity index 91%
rename from src/trimmed_reads.cc
rename to src/trimmed_reads.cpp
index 651a6f7..b0534e6 100644
--- a/src/trimmed_reads.cc
+++ b/src/trimmed_reads.cpp
@@ -22,8 +22,8 @@
  * You should have received a copy of the GNU General Public License     *
  * along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 \*************************************************************************/
-#include "trimmed_reads.h"
-#include "userconfig.h"
+#include "trimmed_reads.hpp"
+#include "userconfig.hpp"
 
 
 
@@ -73,7 +73,7 @@ void trimmed_reads::add_mate_1_read(fastq& read, read_status state,
                                     size_t read_count)
 {
     // Single end reads always go into the mate 1 file or the discarded file
-    distribute_read(m_mate_1, m_mate_1, read, state, PASSED, read_count);
+    distribute_read(m_mate_1, m_mate_1, read, state, read_status::passed, read_count);
 }
 
 
@@ -81,7 +81,7 @@ void trimmed_reads::add_mate_2_read(fastq& read, read_status state,
                                     size_t read_count)
 {
     // Single end reads always go into the mate 2 file or the discarded file
-    distribute_read(m_mate_2, m_mate_1, read, state, PASSED, read_count);
+    distribute_read(m_mate_2, m_mate_1, read, state, read_status::passed, read_count);
 }
 
 
@@ -100,7 +100,7 @@ void trimmed_reads::add_collapsed_read(fastq& read,
     output_chunk_ptr& destination = m_config.combined_output ? m_mate_1 : m_collapsed;
 
     // Collapsed reads may go into the mate 1, mate 2, or discard file
-    distribute_read(destination, destination, read, state, PASSED, read_count);
+    distribute_read(destination, destination, read, state, read_status::passed, read_count);
 }
 
 
@@ -111,7 +111,7 @@ void trimmed_reads::add_collapsed_truncated_read(fastq& read,
     output_chunk_ptr& destination = m_config.combined_output ? m_mate_1 : m_collapsed_truncated;
 
     // Collapsed tr. reads may go into the mate 1, mate 2, or discard file
-    distribute_read(destination, destination, read, state, PASSED, read_count);
+    distribute_read(destination, destination, read, state, read_status::passed, read_count);
 }
 
 
@@ -137,8 +137,8 @@ void trimmed_reads::distribute_read(output_chunk_ptr& regular,
                                     read_status state_2,
                                     size_t read_count)
 {
-    if (state_1 == PASSED) {
-        if (state_2 == PASSED || m_config.combined_output) {
+    if (state_1 == read_status::passed) {
+        if (state_2 == read_status::passed || m_config.combined_output) {
             if (m_config.interleaved_output) {
                 interleaved->add(m_encoding, read, read_count);
             } else {
diff --git a/src/trimmed_reads.h b/src/trimmed_reads.hpp
similarity index 91%
rename from src/trimmed_reads.h
rename to src/trimmed_reads.hpp
index 5e5d1f7..5f5f4f6 100644
--- a/src/trimmed_reads.h
+++ b/src/trimmed_reads.hpp
@@ -27,9 +27,9 @@
 
 #include <string>
 
-#include "fastq_io.h"
-#include "scheduler.h"
-#include "statistics.h"
+#include "fastq_io.hpp"
+#include "scheduler.hpp"
+#include "statistics.hpp"
 
 
 class fastq;
@@ -41,13 +41,13 @@ namespace ar
 
 
 //! Enum representing the possible states of read processing
-enum read_status
+enum class read_status
 {
     //! Read passed all checks, and should be written to the main output file
-    PASSED,
+    passed,
     //! Read failed one or more checks, and should be discarded; this may
     //! include stripping the sequence and qualities, and flagging the read
-    FAILED,
+    failed,
 };
 
 
@@ -128,6 +128,11 @@ public:
     /** Returns vector of chunks from all cached reads. */
     chunk_vec finalize();
 
+    //! Copy construction not supported
+    trimmed_reads(const trimmed_reads&) = delete;
+    //! Assignment not supported
+    trimmed_reads& operator=(const trimmed_reads&) = delete;
+
 private:
     /*
      * Helper function; assigns a given read to a cache depending on state and
@@ -154,15 +159,15 @@ private:
 
     //! Pointer to cached mate 1 reads.
     output_chunk_ptr m_mate_1;
-    //! Pointer to cached mate 2 reads; may be NULL.
+    //! Pointer to cached mate 2 reads; may be nullptr.
     output_chunk_ptr m_mate_2;
-    //! Pointer to cached singleton reads; may be NULL.
+    //! Pointer to cached singleton reads; may be nullptr.
     output_chunk_ptr m_singleton;
-    //! Pointer to cached collapsed reads; may be NULL.
+    //! Pointer to cached collapsed reads; may be nullptr.
     output_chunk_ptr m_collapsed;
-    //! Pointer to cached collapsed, truncated reads; may be NULL.
+    //! Pointer to cached collapsed, truncated reads; may be nullptr.
     output_chunk_ptr m_collapsed_truncated;
-    //! Pointer to cached discarded reads; may be NULL.
+    //! Pointer to cached discarded reads; may be nullptr.
     output_chunk_ptr m_discarded;
 };
 
diff --git a/src/userconfig.cc b/src/userconfig.cpp
similarity index 94%
rename from src/userconfig.cc
rename to src/userconfig.cpp
index f4b7518..c2a8fa1 100644
--- a/src/userconfig.cc
+++ b/src/userconfig.cpp
@@ -30,21 +30,20 @@
 #include <sys/time.h>
 #include <limits>
 
-#include "alignment.h"
-#include "debug.h"
-#include "fastq.h"
-#include "strutils.h"
-#include "userconfig.h"
+#include "alignment.hpp"
+#include "debug.hpp"
+#include "fastq.hpp"
+#include "strutils.hpp"
+#include "userconfig.hpp"
 
 
 namespace ar
 {
 
-
 size_t get_seed()
 {
     struct timeval timestamp;
-    gettimeofday(&timestamp, NULL);
+    gettimeofday(&timestamp, nullptr);
 
     return (timestamp.tv_sec << 20) | timestamp.tv_usec;
 }
@@ -76,7 +75,7 @@ fastq_encoding_ptr select_encoding(const std::string& name,
 userconfig::userconfig(const std::string& name,
                        const std::string& version,
                        const std::string& help)
-    : run_type(ar_trim_adapters)
+    : run_type(ar_command::trim_adapters)
     , basename("your_output")
     , input_files_1()
     , input_files_2()
@@ -184,26 +183,26 @@ userconfig::userconfig(const std::string& name,
             "Default prefix for all output files for which no filename was "
             "explicitly set [current: %default].");
     argparser["--settings"] =
-        new argparse::any(NULL, "FILE",
+        new argparse::any(nullptr, "FILE",
             "Output file containing information on the parameters used in the "
             "run as well as overall statistics on the reads after trimming "
             "[default: BASENAME.settings]");
     argparser["--output1"] =
-        new argparse::any(NULL, "FILE",
+        new argparse::any(nullptr, "FILE",
             "Output file containing trimmed mate1 reads [default: "
             "BASENAME.pair1.truncated (PE), BASENAME.truncated (SE), or "
             "BASENAME.paired.truncated (interleaved PE)]");
     argparser["--output2"] =
-        new argparse::any(NULL, "FILE",
+        new argparse::any(nullptr, "FILE",
             "Output file containing trimmed mate 2 reads [default: "
             "BASENAME.pair2.truncated (only used in PE mode, but not if "
             "--interleaved-output is enabled)]");
     argparser["--singleton"] =
-        new argparse::any(NULL, "FILE",
+        new argparse::any(nullptr, "FILE",
             "Output file to which containing paired reads for which the mate "
             "has been discarded [default: BASENAME.singleton.truncated]");
     argparser["--outputcollapsed"] =
-        new argparse::any(NULL, "FILE",
+        new argparse::any(nullptr, "FILE",
             "If --collapsed is set, contains overlapping mate-pairs which "
             "have been merged into a single read (PE mode) or reads for which "
             "the adapter was identified by a minimum overlap, indicating that "
@@ -211,35 +210,29 @@ userconfig::userconfig(const std::string& name,
             "which have subsequently been trimmed due to low-quality or "
             "ambiguous nucleotides [default: BASENAME.collapsed]");
     argparser["--outputcollapsedtruncated"] =
-        new argparse::any(NULL, "FILE",
+        new argparse::any(nullptr, "FILE",
             "Collapsed reads (see --outputcollapsed) which were trimmed due "
             "the presence of low-quality or ambiguous nucleotides "
             "[default: BASENAME.collapsed.truncated]");
     argparser["--discarded"] =
-        new argparse::any(NULL, "FILE",
+        new argparse::any(nullptr, "FILE",
             "Contains reads discarded due to the --minlength, --maxlength or "
             "--maxns options [default: BASENAME.discarded]");
 
-#if defined(AR_GZIP_SUPPORT) || defined(AR_BZIP2_SUPPORT)
-   argparser.add_header("OUTPUT COMPRESSION:");
-#endif
-
-#ifdef AR_GZIP_SUPPORT
+    argparser.add_header("OUTPUT COMPRESSION:");
     argparser["--gzip"] =
         new argparse::flag(&gzip,
             "Enable gzip compression [current: %default]");
     argparser["--gzip-level"] =
         new argparse::knob(&gzip_level, "LEVEL",
             "Compression level, 0 - 9 [current: %default]");
-#endif
-#ifdef AR_BZIP2_SUPPORT
+
     argparser["--bzip2"] =
         new argparse::flag(&bzip2,
             "Enable bzip2 compression [current: %default]");
     argparser["--bzip2-level"] =
         new argparse::knob(&bzip2_level, "LEVEL",
             "Compression level, 0 - 9 [current: %default]");
-#endif
 
     argparser.add_header("TRIMMING SETTINGS:");
     // Backwards compatibility with AdapterRemoval v1; not recommended due to
@@ -388,29 +381,29 @@ argparse::parse_result userconfig::parse_args(int argc, char *argv[])
 {
     if (argc <= 1) {
         argparser.print_help();
-        return argparse::pr_error;
+        return argparse::parse_result::error;
     }
 
     const argparse::parse_result result = argparser.parse_args(argc, argv);
-    if (result != argparse::pr_ok) {
+    if (result != argparse::parse_result::ok) {
         return result;
     }
 
     quality_input_fmt = select_encoding("--qualitybase", quality_input_base, quality_max);
     if (!quality_input_fmt.get()) {
-        return argparse::pr_error;
+        return argparse::parse_result::error;
     }
 
     if (argparser.is_set("--qualitybase-output")) {
         quality_output_fmt = select_encoding("--qualitybase-out", quality_output_base, quality_max);
         if (!quality_output_fmt.get()) {
-            return argparse::pr_error;
+            return argparse::parse_result::error;
         }
     } else {
         // Default to using the same output encoding as the input
         quality_output_fmt = select_encoding("--qualitybase", quality_input_base, quality_max);
         if (!quality_output_fmt.get()) {
-            return argparse::pr_error;
+            return argparse::parse_result::error;
         }
     }
 
@@ -419,7 +412,7 @@ argparse::parse_result userconfig::parse_args(int argc, char *argv[])
                      "exactly one character long, not "
                      << mate_separator_str.size()
                      << " characters!" << std::endl;
-        return argparse::pr_error;
+        return argparse::parse_result::error;
     } else {
         mate_separator = mate_separator_str.at(0);
     }
@@ -430,7 +423,7 @@ argparse::parse_result userconfig::parse_args(int argc, char *argv[])
         // sequences. However, arguments are still checked above.
         quality_input_fmt.reset(new fastq_encoding(PHRED_OFFSET_33, MAX_PHRED_SCORE));
         quality_output_fmt.reset(new fastq_encoding(PHRED_OFFSET_33, MAX_PHRED_SCORE));
-        run_type = ar_identify_adapters;
+        run_type = ar_command::identify_adapters;
     }
 
     if (demultiplex_sequences) {
@@ -439,16 +432,16 @@ argparse::parse_result userconfig::parse_args(int argc, char *argv[])
                       << "--demultiplex-only at the same time!"
                       << std::endl;
 
-            return argparse::pr_error;
+            return argparse::parse_result::error;
         } else if (!argparser.is_set("--barcode-list")) {
             std::cerr << "Error: Cannot use --demultiplex-only without specifying "
                       << "a list of barcodes using --barcode-list!"
                       << std::endl;
 
-            return argparse::pr_error;
+            return argparse::parse_result::error;
         }
 
-        run_type = ar_demultiplex_sequences;
+        run_type = ar_command::demultiplex_sequences;
     }
 
     if (low_quality_score > static_cast<unsigned>(MAX_PHRED_SCORE)) {
@@ -456,14 +449,14 @@ argparse::parse_result userconfig::parse_args(int argc, char *argv[])
                   << low_quality_score << "\n"
                   << "   must be in the range 0 .. " << MAX_PHRED_SCORE
                   << std::endl;
-        return argparse::pr_error;
+        return argparse::parse_result::error;
     } else if (trim_window_length >= 0) {
         trim_by_quality = true;
     } else if (trim_window_length < 0.0) {
         std::cerr << "Error: Invalid value for --trimwindows ("
                   << trim_window_length << "); value must be >= 0."
                   << std::endl;
-        return argparse::pr_error;
+        return argparse::parse_result::error;
     }
 
     // Check for invalid combinations of settings
@@ -472,11 +465,11 @@ argparse::parse_result userconfig::parse_args(int argc, char *argv[])
                   << "Please specify at least one input file using --file1 FILENAME."
                   << std::endl;
 
-        return argparse::pr_error;
+        return argparse::parse_result::error;
     } else if (!input_files_2.empty() && (input_files_1.size() != input_files_2.size())) {
         std::cerr << "Error: Different number of files specified for --file1 and --file2." << std::endl;
 
-        return argparse::pr_error;
+        return argparse::parse_result::error;
     } else if (!input_files_2.empty()) {
         paired_ended_mode = true;
         min_adapter_overlap = 0;
@@ -492,7 +485,7 @@ argparse::parse_result userconfig::parse_args(int argc, char *argv[])
                       << "together with the --file2 option; only --file1 must "
                       << "be specified!"
                       << std::endl;
-            return argparse::pr_error;
+            return argparse::parse_result::error;
         }
 
         // Enable paired end mode .. other than the FASTQ reader, all other
@@ -506,12 +499,12 @@ argparse::parse_result userconfig::parse_args(int argc, char *argv[])
                   << "be interleaved FASTQ reads (requires --interleaved)."
                   << std::endl;
 
-        return argparse::pr_error;
+        return argparse::parse_result::error;
     }
 
     // (Optionally) read adapters from file and validate
     if (!setup_adapter_sequences()) {
-        return argparse::pr_error;
+        return argparse::parse_result::error;
     }
 
     // Set mismatch threshold
@@ -529,25 +522,23 @@ argparse::parse_result userconfig::parse_args(int argc, char *argv[])
     if (gzip_level > 9) {
         std::cerr << "Error: --gzip-level must be in the range 0 to 9, not "
                   << gzip_level << std::endl;
-        return argparse::pr_error;
+        return argparse::parse_result::error;
 
     }
 
-#ifdef AR_BZIP2_SUPPORT
     if (bzip2_level < 1 || bzip2_level > 9) {
         std::cerr << "Error: --bzip2-level must be in the range 1 to 9, not "
                   << bzip2_level << std::endl;
-        return argparse::pr_error;
+        return argparse::parse_result::error;
     } else if (bzip2 && gzip) {
         std::cerr << "Error: Cannot enable --gzip and --bzip2 at the same time!"
                   << std::endl;
-        return argparse::pr_error;
+        return argparse::parse_result::error;
     }
-#endif
 
     if (!max_threads) {
         std::cerr << "Error: --threads must be at least 1!" << std::endl;
-        return argparse::pr_error;
+        return argparse::parse_result::error;
     } else if (max_threads > 1 && argparser.is_set("--seed")) {
         std::cerr << "Warning: The option --seed should not be used when "
                   << "using multiple threads; multi-threaded behavior is not "
@@ -555,7 +546,7 @@ argparse::parse_result userconfig::parse_args(int argc, char *argv[])
                   << std::endl;
     }
 
-    return argparse::pr_ok;
+    return argparse::parse_result::ok;
 }
 
 
@@ -643,7 +634,7 @@ std::string userconfig::get_output_filename(const std::string& key,
         }
 
         // Currently only when demultiplexing; for backwards compatibility
-        if (run_type == ar_demultiplex_sequences) {
+        if (run_type == ar_command::demultiplex_sequences) {
             filename += ".fastq";
         }
 
@@ -684,11 +675,11 @@ std::string userconfig::get_output_filename(const std::string& key,
             throw std::invalid_argument("invalid read-type in userconfig::get_output_filename constructor: " + key);
         }
 
-        if (run_type != ar_demultiplex_sequences) {
+        if (run_type != ar_command::demultiplex_sequences) {
             filename += ".truncated";
         }
     } else if (key == "--output1") {
-        if (run_type != ar_demultiplex_sequences) {
+        if (run_type != ar_command::demultiplex_sequences) {
             filename += ".truncated";
         }
     } else if (key != "demux_unknown") {
@@ -696,7 +687,7 @@ std::string userconfig::get_output_filename(const std::string& key,
     }
 
     // Currently only when demultiplexing; for backwards compatibility
-    if (run_type == ar_demultiplex_sequences) {
+    if (run_type == ar_command::demultiplex_sequences) {
         filename += ".fastq";
     }
 
diff --git a/src/userconfig.h b/src/userconfig.hpp
similarity index 94%
rename from src/userconfig.h
rename to src/userconfig.hpp
index 41de227..b3c92d0 100644
--- a/src/userconfig.h
+++ b/src/userconfig.hpp
@@ -28,12 +28,12 @@
 #include <string>
 #include <memory>
 
-#include "adapterset.h"
-#include "argparse.h"
-#include "commontypes.h"
-#include "fastq.h"
-#include "alignment.h"
-#include "statistics.h"
+#include "adapterset.hpp"
+#include "argparse.hpp"
+#include "commontypes.hpp"
+#include "fastq.hpp"
+#include "alignment.hpp"
+#include "statistics.hpp"
 
 namespace ar
 {
@@ -44,11 +44,11 @@ typedef std::unique_ptr<fastq_encoding> fastq_encoding_ptr;
 typedef std::unique_ptr<statistics> statistics_ptr;
 
 
-enum ar_run_types
+enum class ar_command
 {
-    ar_trim_adapters,
-    ar_identify_adapters,
-    ar_demultiplex_sequences,
+    trim_adapters,
+    identify_adapters,
+    demultiplex_sequences,
 };
 
 
@@ -91,8 +91,8 @@ public:
     /** Trims a read if enabled, returning the #bases removed from each end. */
     fastq::ntrimmed trim_sequence_by_quality_if_enabled(fastq& read) const;
 
-    //! Type of run to execute; see ar_run_types
-    ar_run_types run_type;
+    //! Type of run to execute; see command
+    ar_command run_type;
 
     //! Prefix used for output files for which no filename was explicitly set
     std::string basename;
@@ -177,13 +177,12 @@ public:
 
     adapter_set adapters;
 
-private:
-    //! Not implemented
-    userconfig(const userconfig&);
-    //! Not implemented
-    userconfig& operator=(const userconfig&);
-
+    //! Copy construction not supported
+    userconfig(const userconfig&) = delete;
+    //! Assignment not supported
+    userconfig& operator=(const userconfig&) = delete;
 
+private:
     /** Sets up adapter sequences based on user settings.
      *
      * @return True on success, false otherwise.
diff --git a/src/vecutils.h b/src/vecutils.hpp
similarity index 100%
rename from src/vecutils.h
rename to src/vecutils.hpp
diff --git a/tests/alignment_test.cc b/tests/alignment_test.cpp
similarity index 98%
rename from tests/alignment_test.cc
rename to tests/alignment_test.cpp
index bed7ed1..e05d413 100644
--- a/tests/alignment_test.cc
+++ b/tests/alignment_test.cpp
@@ -27,9 +27,9 @@
 #include <vector>
 #include <gtest/gtest.h>
 
-#include "testing.h"
-#include "alignment.h"
-#include "fastq.h"
+#include "testing.hpp"
+#include "alignment.hpp"
+#include "fastq.hpp"
 
 namespace ar
 {
@@ -71,6 +71,14 @@ std::ostream& operator<<(std::ostream& stream, const alignment_info& aln)
 }
 
 
+TEST(alignment, alignment_info) {
+    std::stringstream stream;
+    stream << new_aln(1, 2, 3, 4, 5, 6);
+
+    ASSERT_EQ(stream.str(), "alignment_info(1, 2, 3, 4, 5, 6)");
+}
+
+
 void ASSERT_TRUNCATED_PE_IS_UNCHANGED(const alignment_info& alignment,
                                       const fastq& record1,
                                       const fastq& record2)
@@ -672,6 +680,16 @@ TEST(alignment_pe, only_adadapter_sequence__missing_base__shift)
 }
 
 
+TEST(alignment_pe, invalid_alignment)
+{
+    fastq record1("Rec", "", "");
+    fastq record2("Rec", "", "");
+    const alignment_info alignment = new_aln(0, 1);
+
+    ASSERT_THROW(truncate_paired_ended_sequences(alignment, record1, record2), std::invalid_argument);
+}
+
+
 ///////////////////////////////////////////////////////////////////////////////
 
 TEST(alignment_pe, empty_mate_1)
@@ -1072,9 +1090,7 @@ void update_alignment(alignment_info& aln,
                       const std::string& b,
                       size_t nbases)
 {
-    if (a.length() != b.length()) {
-        throw std::invalid_argument("length does not match");
-    }
+    ASSERT_EQ(a.length(), b.length());
 
     for (size_t i = 0; i < nbases; ++i) {
         const char nt1 = a.at(i);
@@ -1137,14 +1153,7 @@ TEST(compare_subsequences, brute_force_validation)
                     current.length = seqlen;
                     compare_subsequences(best, current, mate1.c_str(), mate2.c_str());
 
-                    if (!(expected == current)) {
-                        std::cerr << "seqlen = " << seqlen << "\n"
-                                  << "pos    = " << pos << "\n"
-                                  << "nbases = " << nbases << "\n"
-                                  << "mate1  = " << mate1 << "\n"
-                                  << "mate2  = " << mate2 << std::endl;
-                        ASSERT_EQ(expected, current);
-                    }
+                    ASSERT_EQ(expected, current);
                 }
             }
         }
diff --git a/tests/argparse_test.cc b/tests/argparse_test.cpp
similarity index 96%
rename from tests/argparse_test.cc
rename to tests/argparse_test.cpp
index 2e42f65..9ac83a7 100644
--- a/tests/argparse_test.cc
+++ b/tests/argparse_test.cpp
@@ -27,8 +27,8 @@
 #include <stdexcept>
 #include <gtest/gtest.h>
 
-#include "argparse.h"
-#include "debug.h"
+#include "argparse.hpp"
+#include "debug.hpp"
 
 namespace ar
 {
@@ -184,7 +184,8 @@ TEST(any, consume__with_sink__preset)
 
 TEST(many, defaults)
 {
-	consumer_autoptr ptr(new argparse::many());
+	string_vec sink;
+	consumer_autoptr ptr(new argparse::many(&sink));
 	ASSERT_FALSE(ptr->is_set());
 	ASSERT_EQ("", ptr->metavar());
 	ASSERT_EQ("", ptr->help());
@@ -209,7 +210,9 @@ TEST(many, consumes_one_argument)
 {
 	string_vec arguments;
 	arguments.push_back("foo");
-	consumer_autoptr ptr(new argparse::many());
+
+	string_vec sink;
+	consumer_autoptr ptr(new argparse::many(&sink));
 	ASSERT_FALSE(ptr->is_set());
 	ASSERT_EQ(1, ptr->consume(arguments.begin(), arguments.end()));
 	ASSERT_TRUE(ptr->is_set());
@@ -222,7 +225,9 @@ TEST(many, consumes_two_arguments)
 	string_vec arguments;
 	arguments.push_back("foo");
 	arguments.push_back("bar");
-	consumer_autoptr ptr(new argparse::many());
+
+	string_vec sink;
+	consumer_autoptr ptr(new argparse::many(&sink));
 	ASSERT_FALSE(ptr->is_set());
 	ASSERT_EQ(2, ptr->consume(arguments.begin(), arguments.end()));
 	ASSERT_TRUE(ptr->is_set());
@@ -236,7 +241,9 @@ TEST(many, consumes_until_next)
 	arguments.push_back("foo");
 	arguments.push_back("--zoo");
 	arguments.push_back("bar");
-	consumer_autoptr ptr(new argparse::many());
+
+	string_vec sink;
+	consumer_autoptr ptr(new argparse::many(&sink));
 	ASSERT_FALSE(ptr->is_set());
 	ASSERT_EQ(1, ptr->consume(arguments.begin(), arguments.end()));
 	ASSERT_TRUE(ptr->is_set());
@@ -246,8 +253,9 @@ TEST(many, consumes_until_next)
 
 TEST(many, consume_past_the_end)
 {
+	string_vec sink;
 	const string_vec arguments;
-	consumer_autoptr ptr(new argparse::many());
+	consumer_autoptr ptr(new argparse::many(&sink));
 	ASSERT_FALSE(ptr->is_set());
 	ASSERT_EQ(0, ptr->consume(arguments.begin(), arguments.end()));
 	ASSERT_TRUE(ptr->is_set());
@@ -306,10 +314,7 @@ TEST(knob, defaults)
 
 TEST(knob, defaults__sink_required)
 {
-	try {
-		argparse::knob knob(NULL);
-		FAIL();
-	} catch (const assert_failed&) {}
+	ASSERT_THROW(argparse::knob(NULL), assert_failed);
 }
 
 
@@ -445,10 +450,7 @@ TEST(floaty_knob, default_nan)
 
 TEST(floaty_knob, defaults__sink_required)
 {
-	try {
-		argparse::floaty_knob knob(NULL);
-		FAIL();
-	} catch (const assert_failed&) {}
+	ASSERT_THROW(argparse::floaty_knob(NULL), assert_failed);
 }
 
 
diff --git a/tests/testing.h b/tests/fastq_enc_test.cpp
similarity index 77%
copy from tests/testing.h
copy to tests/fastq_enc_test.cpp
index 9abea6d..c193559 100644
--- a/tests/testing.h
+++ b/tests/fastq_enc_test.cpp
@@ -22,21 +22,27 @@
  * You should have received a copy of the GNU General Public License     *
  * along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 \*************************************************************************/
-#ifndef TESTING_H
-#define TESTING_H
+#include <limits>
+#include <stdexcept>
+#include <gtest/gtest.h>
 
-#include <iostream>
+#include "testing.hpp"
+#include "debug.hpp"
+#include "fastq.hpp"
 
-#include "fastq.h"
 
+namespace ar
+{
 
-namespace ar {
-    inline void PrintTo(const fastq& record, std::ostream* stream)
-    {
-        *stream << "'@" << record.header() << "\\n"
-                << record.sequence() << "\\n+\\n"
-                << record.qualities() << "\\n'";
-    }
+///////////////////////////////////////////////////////////////////////////////
+// Names (default objects)
+
+TEST(fastq_enc, global_objects__name)
+{
+    ASSERT_STREQ("Phred+33", FASTQ_ENCODING_33.name());
+    ASSERT_STREQ("Phred+64", FASTQ_ENCODING_64.name());
+    ASSERT_STREQ("Phred+33", FASTQ_ENCODING_SAM.name());
+    ASSERT_STREQ("Solexa", FASTQ_ENCODING_SOLEXA.name());
 }
 
-#endif
\ No newline at end of file
+}
diff --git a/tests/fastq_test.cc b/tests/fastq_test.cpp
similarity index 97%
rename from tests/fastq_test.cc
rename to tests/fastq_test.cpp
index 885c32c..47c6bee 100644
--- a/tests/fastq_test.cc
+++ b/tests/fastq_test.cpp
@@ -26,10 +26,10 @@
 #include <stdexcept>
 #include <gtest/gtest.h>
 
-#include "testing.h"
-#include "debug.h"
-#include "fastq.h"
-#include "linereader.h"
+#include "testing.hpp"
+#include "debug.hpp"
+#include "fastq.hpp"
+#include "linereader.hpp"
 
 namespace ar
 {
@@ -88,7 +88,7 @@ TEST(fastq, constructor_simple_record_phred_33_encoded)
     const fastq record("record_1", "ACGAGTCA", "!7BF8DGI");
     ASSERT_EQ("record_1", record.header());
     ASSERT_EQ("ACGAGTCA", record.sequence());
-    ASSERT_EQ(std::string("!7BF8DGI", 8), record.qualities());
+    ASSERT_EQ("!7BF8DGI", record.qualities());
 }
 
 
@@ -97,7 +97,7 @@ TEST(fastq, constructor_simple_record_phred_64_encoded)
     const fastq record("record_2", "ACGAGTCA", "@VaeWcfh", FASTQ_ENCODING_64);
     ASSERT_EQ("record_2", record.header());
     ASSERT_EQ("ACGAGTCA", record.sequence());
-    ASSERT_EQ(std::string("!7BF8DGI", 8), record.qualities());
+    ASSERT_EQ("!7BF8DGI", record.qualities());
 }
 
 
@@ -190,8 +190,37 @@ TEST(fastq, constructor_invalid_nucleotides)
 
 
 ///////////////////////////////////////////////////////////////////////////////
+// Constructor without qualities
+
+TEST(fastq, constructor_no_qualities)
+{
+    const fastq record("record_1", "ACGT");
+    ASSERT_EQ("record_1", record.header());
+    ASSERT_EQ("ACGT", record.sequence());
+    ASSERT_EQ("!!!!", record.qualities());
+}
+
+
+TEST(fastq, constructor_no_qualities_no_sequence)
+{
+    const fastq record("record_1", "");
+    ASSERT_EQ("record_1", record.header());
+    ASSERT_EQ("", record.sequence());
+    ASSERT_EQ("", record.qualities());
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
 // misc properties
 
+TEST(fastq, name)
+{
+    ASSERT_EQ("name", fastq("name", "", "").name());
+    ASSERT_EQ("name", fastq("name meta", "", "").name());
+    ASSERT_EQ("name", fastq("name meta more", "", "").name());
+}
+
+
 TEST(fastq, length)
 {
     ASSERT_EQ(0, fastq("record_1", "", "").length());
diff --git a/tests/strutils_test.cc b/tests/strutils_test.cpp
similarity index 95%
rename from tests/strutils_test.cc
rename to tests/strutils_test.cpp
index 3feef18..21386e6 100644
--- a/tests/strutils_test.cc
+++ b/tests/strutils_test.cpp
@@ -26,12 +26,27 @@
 #include <stdexcept>
 #include <gtest/gtest.h>
 
-#include "strutils.h"
+#include "strutils.hpp"
 
 namespace ar
 {
 
 ///////////////////////////////////////////////////////////////////////////////
+// Tests for 'toupper'
+
+TEST(strutils_toupper, empty_input_empty_output)
+{
+    ASSERT_EQ("", toupper(""));
+}
+
+
+TEST(strutils_toupper, mixed_input)
+{
+    ASSERT_EQ("A1{2BZ`ZADEK", toupper("a1{2BZ`zAdeK"));
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
 // Tests for 'indent_lines'
 
 TEST(strutils_indent, empty_input_empty_output)
@@ -106,11 +121,7 @@ TEST(strutils_indent, empty_lines_trailing)
 
 
 ///////////////////////////////////////////////////////////////////////////////
-// Tests for 'columnize_'
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Tests for 'indent_lines'
+// Tests for 'columnize_text'
 
 TEST(strutils_columnize, empty_lines)
 {
diff --git a/tests/testing.h b/tests/testing.hpp
similarity index 98%
rename from tests/testing.h
rename to tests/testing.hpp
index 9abea6d..01d8be1 100644
--- a/tests/testing.h
+++ b/tests/testing.hpp
@@ -27,7 +27,7 @@
 
 #include <iostream>
 
-#include "fastq.h"
+#include "fastq.hpp"
 
 
 namespace ar {
diff --git a/validation/run b/validation/run
index e98e1a0..f8a2258 100755
--- a/validation/run
+++ b/validation/run
@@ -246,7 +246,9 @@ class TestCase(object):
         return final_files["input_1"], final_files["input_2"]
 
     def _do_call(self, root, input_1, input_2, compression, interleaved):
-        command = self._build_command(root, input_1, input_2, compression, interleaved)
+        command = self._build_command(root, input_1, input_2,
+                                      compression, interleaved)
+
         with open(os.devnull, "w") as dev_null:
             proc = subprocess.Popen(command,
                                     stdin=dev_null,
@@ -363,7 +365,7 @@ class TestCase(object):
         result = []
         for line in handle:
             line = re.sub(r"RNG seed: [0-9]+", "RNG seed: NA", line)
-            line = re.sub(r"AdapterRemoval ver. [0-9]+.[0-9]+.[0-9]+",
+            line = re.sub(r"AdapterRemoval ver. [0-9]+.[0-9]+.[0-9]+[a-zA-Z]?",
                           "AdapterRemoval ver. X.Y.Z", line)
             # Removed keyword to allow automatic interleaved tests
             line = re.sub(r" interleaved paired-end reads",
@@ -501,7 +503,7 @@ def main(argv):
     else:
         print_ok("\nAll %i tests succeeded .." % (len(tests),))
 
-    return 0
+    return n_failures
 
 
 if __name__ == '__main__':

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/adapterremoval.git



More information about the debian-med-commit mailing list