The Results of the Expressive C++17 Coding Challenge | Fluent{C++}

Jonathan Boccara; The Results of the Expressive C++17 Coding Challenge; In His Blog entitled Fluent{C++}; 2017-10-23.

Mentions

Winner:

Fernando B. Giannasi,

honorifics
  • Brazil (lives in, citizen of)
Humblebrags
  • [He's] not […] a professional programmer.
  • Wasn’t even trying
  • One hand tied behind his back,
  • etc.…

Neat code tho.

Problem Statement

A command line tool that takes in a CSV file, overwrites all the data of a given column by a given value, and outputs the results into a new CSV file. Accept the following arguments:

  • the filename of a CSV file,
  • the name of the column to overwrite in that file,
  • the string that will be used as a replacement for that column,
  • the filename where the output will be written.

Details & clarifications in the post.

Referenced

Previously

In His Blog

Actuality

g++ -std=c++1z -O2 -Wall -pedantic -pthread main.cpp -lstdc++fs && ./a.out
Bad arguments
Usage: ./a.out [IN_FILE] [COLUMN] [NEW_VALUE] [OUT_FILE]
bash: line 7: 31459 Aborted                 (core dumped) ./a.out

Exhibited at coliru

Source

/* Name: Fernando B. Giannasi
 * Email: phoemur@gmail.com
 *
 * Features of C++17 used:
 * - std::filesystem
 * - nodiscard and noreturn attributes
 * - structured bindings
 * - string_view
 * - Template argument deduction for class templates
 * - Init-statement for if/switch
 * - std::optional
 */
#include <algorithm>
#include <experimental/filesystem>
#include <fstream>
#include <iostream>
#include <optional>
#include <string>
#include <string_view>
#include <sstream>
#include <utility>
#include <vector>

using namespace std;
namespace fs = std::experimental::filesystem;

[[nodiscard]] auto split_string(const string_view& input, const char delimiter) {
  stringstream ss {input.data()};
  vector<string> result;
  // result.reserve(count(begin(input), end(input), delimiter));
  for (string buffer; getline(ss, buffer, delimiter); /*empty*/) {
    result.push_back(move(buffer));
  }
  return result;
}

[[nodiscard]] optional<int> get_target_column(ifstream& input, const string_view& label, const char delimiter) {
  string first_line;
  // if-init
  if (getline(input, first_line); first_line.size() == 0) {
    throw runtime_error("Input file missing");
  }
  input.seekg(0);
  auto tokens = split_string(first_line, delimiter);
  if (auto it = find(begin(tokens), end(tokens), label); it == tokens.end()) {
    return {}; //return empty optional
  } else {
    return distance(begin(tokens), it);
  }
}

[[nodiscard]] auto get_file_handlers(const string_view& input, const string_view& output) {
  ifstream in_file{input.data(), ios::in};
  if (!in_file.is_open()) {
    throw runtime_error("Unable to open input file");
  }
  ofstream out_file{output.data(), ios::out | ios::trunc};
  if (!out_file.is_open()) {
    throw runtime_error("Unable to open output file");
  }
  // template argument deduction for class templates (no make_pair)
  return pair(move(in_file), move(out_file));
}

void do_work(ifstream& input, ofstream& output, int target_index, const string_view& new_value, const char delimiter) {
  string buffer;
  getline(input, buffer); // for the header line
  output << buffer << endl;
  while (getline(input, buffer)) {
    auto tokens = split_string(buffer, delimiter);
    tokens[target_index] = new_value.data();
    for (auto& i: tokens) {
      output << i;
      output << (i == tokens.back() ? 'n':delimiter);
    }
  }
}

[[noreturn]] void usage_terminate(const string_view& progname) noexcept {
  cout << "Usage: " << progname << " [IN_FILE] [COLUMN] [NEW_VALUE] [OUT_FILE]" << endl;
  abort();
}

int main(int argc, char* argv[]) {
  try {
    if (argc != 5) {
      throw runtime_error("Bad arguments");
    }
    auto [in_file, out_file] = get_file_handlers(argv[1], argv[4]);
    string_view new_value = argv[3];
    auto target_index = get_target_column(in_file, argv[2], ',');
    if (target_index) {
        do_work(in_file, out_file, *target_index, new_value, ',');
    } else {
        throw runtime_error("Column name doesn’t exist in the input file");
    }
  } catch (runtime_error& e) {
    cout << e.what() << endl;
    usage_terminate(argv[0]);
  }
  return 0;
}

Hell is a multi-threaded C++ Program | Mark Bessey

tl;dr → he doesn’t like pthreads. The pthreads abstraction is too low level, being as it delivers merely threads (and not scoped memory management).
and → later he writes about JavaScript futures; he’s from WebOS culture.
and → there was no Rust back in that day and age; he cites Occam & Erlang as exemplary. Later on he cites Haskell as salutary.

Mentioned

  • Tony Hoare, Communicating Sequential Processes (CSP), circa 1985.

Nostrums

  • Deadlock avoidance plan
  • Short lock spans
  • Each threads must have a purpose.
  • A purpose cannot be defined by the occurrence of an external event.

Patterns

  • Producer-Consumer
  • Barriers
  • BackgroundWorker, google.
  • Pipe-and-Filter.

Referenced

Previously

in His Blog

Actualities


Via: Herb Sutter; The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software; In His Blog; 2008

A Tale of Two Industries: How Programming Languages Differ Between Wealthy and Developing Countries | Stack Overflow

David Robinson (Stack Overflow); A Tale of Two Industries: How Programming Languages Differ Between Wealthy and Developing Countries; In Their Blog; 2017-08-29.

Promotions

Previously

In Their Blog

Actualities

Trip report: Summer ISO C++ standards meeting (Toronto) | Sutter’s Mill

Herb Sutter; Trip report: Summer ISO C++ standards meeting (Toronto); In His Blog entitled Sutter’s Mill; 2017-07-15.

Mentions

  • Draft C++20
  • C++17

Separately noted.

libasync (everyone has one) and asio

An Architecture for Internet Data Transfer | Tolia, Kaminsky, Andersen, Patil

Niraj Tolia, Michael Kaminsky, David G. Andersen, Swapnil Patil; An Architecture for Internet Data Transfer; In Proceedings of the Symposium on Networked Systems Design and Implementation (NSDI), in the USENIX sphere; 2006.

tl;dr → A “content-centric networking” concept with cryptographic hashes on blobs of data, which can be transferred out of order and across time & space. Hard to get that out of the paper though.

Abstract

This paper presents the design and implementation of DOT, a flexible architecture for data transfer. This architecture separates content negotiation from the data transfer itself. Applications determine what data they need to send and then use a new transfer service to send it. This transfer service acts as a common interface between applications and the lower-level network layers, facilitating innovation both above and below. The transfer service frees developers from re-inventing transfer mechanisms in each new application. New transfer mechanisms, in turn, can be easily deployed without modifying existing applications.

We discuss the benefits that arise from separating data transfer into a service and the challenges this service must overcome. The paper then examines the implementation of DOT and its plugin framework for creating new data transfer mechanisms. A set of microbenchmarks shows that the DOT prototype performs well, and that the overhead it imposes is unnoticeable in the wide-area. End-to-end experiments using more complex configurations demonstrate DOT’s ability to implement effective, new data delivery mechanisms underneath existing services. Finally, we evaluate a production mail server modified to use DOT using trace data gathered from a live email server. Converting the mail server required only 184 lines-of-code changes to the server, and the resulting system reduces the bandwidth needed to send email by up to 20%.

Mentions

  • No code (this was before the era of githubbery.
    • Only a protocol proposal; no reference implementation.
    • Perhaps there was an experimental implementation, but it is not available.
  • David Mazières, Frank Dabek, Eric Peterson, Thomer M. Gil. Using libasync; Technical Report; PDOS, CSAIL, MIT; 2004.12 pages; pdf; followup separately filled.

SEI CERT C++ Coding Standard

Aaron Ballman; SEI CERT C++ Coding Standard, 2016 Edition; Software Engineering Institute (SEI), Carnegie Mellon University (CMU); 2017; 435 pages; paywall (pay with PII).
Teaser: Rules for Developing Safe, Reliable and Secure Systems in C++

tl;dr → some strictures are actual style and “good code” concepts; others are of the flavor of: your code will crash if you do this (so don’t do it).

Table of Contents

Introduction

  • Scope
  • Audience
  • Usage
  • How this Coding Standard Is Organized
  • Relation to the CERT C Coding Standard 1.6 Rules Versus Recommendations
  • Tool Selection and Validation
  • Conformance Testing
  • Development Process
  • System Qualities
  • Automatically Generated Code
  • Government Regulations
  • Acknowledgments

Declarations and Initialization (DCL)

  • DCL50-CPP. Do not define a C-style variadic function
  • DCL51-CPP. Do not declare or define a reserved identifier
  • DCL52-CPP. Never qualify a reference type with const or volatile
  • DCL53-CPP. Do not write syntactically ambiguous declarations
  • DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope
  • DCL55-CPP. Avoid information leakage when passing a class object across a trust boundary
  • DCL56-CPP. Avoid cycles during initialization of static objects
  • DCL57-CPP. Do not let exceptions escape from destructors or deallocation functions
  • DCL58-CPP. Do not modify the standard namespaces
  • DCL59-CPP. Do not define an unnamed namespace in a header file
  • DCL60-CPP. Obey the one-definition rule

Expressions (EXP)

  • EXP50-CPP. Do not depend on the order of evaluation for side effects
  • EXP51-CPP. Do not delete an array through a pointer of the incorrect type
  • EXP52-CPP. Do not rely on side effects in unevaluated operands
  • EXP53-CPP. Do not read uninitialized memory
  • EXP54-CPP. Do not access an object outside of its lifetime
  • EXP55-CPP. Do not access a cv-qualified object through a cv-unqualified type
  • EXP56-CPP. Do not call a function with a mismatched language linkage
  • EXP57-CPP. Do not cast or delete pointers to incomplete classes
  • EXP58-CPP. Pass an object of the correct type to va_start
  • EXP59-CPP. Use offsetof() on valid types and members
  • EXP60-CPP. Do not pass a nonstandard-layout type object across execution boundaries
  • EXP61-CPP. A lambda object must not outlive any of its reference captured objects
  • EXP62-CPP. Do not access the bits of an object representation that are not part of the object’s value representation
  • EXP63-CPP. Do not rely on the value of a moved-from object

Integers (INT)

  • INT50-CPP. Do not cast to an out-of-range enumeration value

Containers (CTR)

  • CTR50-CPP. Guarantee that container indices and iterators are within the valid range
  • CTR51-CPP. Use valid references, pointers, and iterators to reference elements of a container
  • CTR52-CPP. Guarantee that library functions do not overflow
  • CTR53-CPP. Use valid iterator ranges
  • CTR54-CPP. Do not subtract iterators that do not refer to the same container
  • CTR55-CPP. Do not use an additive operator on an iterator if the result would overflow
  • CTR56-CPP. Do not use pointer arithmetic on polymorphic objects
  • CTR57-CPP. Provide a valid ordering predicate
  • CTR58-CPP. Predicate function objects should not be mutable

Characters and Strings (STR)

  • STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator
  • STR51-CPP. Do not attempt to create a std::string from a null pointer
  • STR52-CPP. Use valid references, pointers, and iterators to reference elements of a basic_string
  • STR53-CPP. Range check element access

Memory Management (MEM)

  • MEM50-CPP. Do not access freed memory
  • MEM51-CPP. Properly deallocate dynamically allocated resources
  • MEM52-CPP. Detect and handle memory allocation errors
  • MEM53-CPP. Explicitly construct and destruct objects when manually managing object lifetime
  • MEM54-CPP. Provide placement new with properly aligned pointers to sufficient storage capacity
  • MEM55-CPP. Honor replacement dynamic storage management requirements
  • MEM56-CPP. Do not store an already-owned pointer value in an unrelated smart pointer
  • MEM57-CPP. Avoid using default operator new for over-aligned types

Input Output (FIO)

  • FIO50-CPP. Do not alternately input and output from a file stream without an intervening positioning call
  • FIO51-CPP. Close files when they are no longer needed

Exceptions and Error Handling (ERR)

  • ERR50-CPP. Do not abruptly terminate the program
  • ERR51-CPP. Handle all exceptions
  • ERR52-CPP. Do not use setjmp() or longjmp()
  • ERR53-CPP. Do not reference base classes or class data members in a constructor or destructor function-try-block handler
  • ERR54-CPP. Catch handlers should order their parameter types from most derived to least derived
  • ERR55-CPP. Honor exception specifications
  • ERR56-CPP. Guarantee exception safety
  • ERR57-CPP. Do not leak resources when handling exceptions
  • ERR58-CPP. Handle all exceptions thrown before main() begins executing
  • ERR59-CPP. Do not throw an exception across execution boundaries
  • ERR60-CPP. Exception objects must be nothrow copy constructible
  • ERR61-CPP. Catch exceptions by lvalue reference
  • ERR62-CPP. Detect errors when converting a string to a number

Object Oriented Programming (OOP)

  • OOP50-CPP. Do not invoke virtual functions from constructors or destructors
  • OOP51-CPP. Do not slice derived objects
  • OOP52-CPP. Do not delete a polymorphic object without a virtual destructor
  • OOP53-CPP. Write constructor member initializers in the canonical order
  • OOP54-CPP. Gracefully handle self-copy assignment
  • OOP55-CPP. Do not use pointer-to-member operators to access nonexistent members
  • OOP56-CPP. Honor replacement handler requirements
  • OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions
  • OOP58-CPP. Copy operations must not mutate the source object

Concurrency (CON)

  • CON50-CPP. Do not destroy a mutex while it is locked
  • CON51-CPP. Ensure actively held locks are released on exceptional conditions
  • CON52-CPP. Prevent data races when accessing bit-fields from multiple threads
  • CON53-CPP. Avoid deadlock by locking in a predefined order
  • CON54-CPP. Wrap functions that can spuriously wake up in a loop
  • CON55-CPP. Preserve thread safety and liveness when using condition variables
  • CON56-CPP. Do not speculatively lock a non-recursive mutex that is already owned by the calling thread

Miscellaneous (MSC)

  • MSC50-CPP. Do not use std::rand() for generating pseudorandom numbers
  • MSC51-CPP. Ensure your random number generator is properly seeded
  • MSC52-CPP. Value-returning functions must return a value from all exit paths
  • MSC53-CPP. Do not return from a function declared [[noreturn]]
  • MSC54-CPP. A signal handler must be a plain old function

Appendix A: Bibliography

Appendix B: Definitions

Appendix C: Related Guidelines

Appendix D: Risk Assessments