Posts in category c++

C++ Move Semantics

I finally read this and wanted to keep it for posterity.

Awesome Stack Overflow answers (the top two).

Some BOOST examples

I've been trying to learn BOOST lately, and wrote a little program to convert 16-bit sampled data to 8-bit. In theory, you can do other things similar (scaling).

As always, any feedback is welcome. Especially a "proper" C++ way of creating a file of a given size.

// Templated function to convert from one size int to another with automatic scaling factors.
// Doesn't do so well with signed <=> unsigned!
// g++ 16_to_8.cc -o 16_to_8 -lboost_iostreams

// Boost concepts shown/used:
// integer traits (compile-time min/max of a type)
// memory mapped I/O
// (unused) make_iterator_range (converts C-style array into STL-compliant "Forward Range" concept)
// minmax_element (does 3N/2 compares instead of 2N)
// (unused) bind to create on-the-fly lambda-like function for std::transform
// lambda in std::transform
// replace_first for a string

#include <boost/integer_traits.hpp>
#include <iostream>
#include <algorithm>
//unused #include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/casts.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/algorithm/minmax_element.hpp>
#include <boost/algorithm/string/replace.hpp>

using namespace std;

// Generic read/writer
template <typename intype, typename outtype>
bool ReadWriteScale(const string &infilename, const string &outfilename) {
  using namespace boost;
  using namespace /*boost::*/iostreams;
  using namespace lambda;

  mapped_file_source infile;
  mapped_file_sink outfile;

  try {
        infile.open(infilename);
  } catch (boost::exception &err) {
        cerr << diagnostic_information(err);
        return false;
  };
  size_t insize = infile.size(); // bytes
  if (0 == insize) {
        cerr << "The input file seems empty." << endl;
        return false;
  };
  // Create a new file for output. We'll use old-school C to create the file, and then memory mapped to let the kernel handle paging.
  {
        FILE *outfile_raw = fopen(outfilename.c_str(), "w");
        fseek(outfile_raw, insize / sizeof(intype) * sizeof(outtype) - 1, SEEK_SET);
        const char nil = '\0';
        fwrite(&nil, 1, 1, outfile_raw);
        fclose(outfile_raw);
  }
  try {
        outfile.open(outfilename.c_str());
  } catch (boost::exception &err) {
        cerr << diagnostic_information(err);
        return false;
  };
  
  // Get min/max
  intype min = 0, max = 0;
  const intype *indata = reinterpret_cast<const intype *>(infile.data());
  cout << "Scanning " << insize << " bytes." << endl;
  insize /= sizeof(intype); // Change scale of insize from here on out
  //iterator_range<const intype*> iter = make_iterator_range(indata, indata+insize);
  //pair<const intype*, const intype*> result = minmax_element(iter.begin(), iter.end());
  pair<const intype*, const intype*> result = minmax_element(indata, indata+insize);
  
  // Figure out scaling. TODO: Handle unsigned properly (check const_min == 0)
  const int64_t min64 = static_cast<int64_t>(*result.first);
  const int64_t max64 = static_cast<int64_t>(*result.second);
  //cout << "Factors: " << static_cast<double>(integer_traits<outtype>::const_min) / min64 << ", " << static_cast<double>(integer_traits<outtype>::const_max) / max64 << endl;
  const double scaling_factor = std::min( static_cast<double>(integer_traits<outtype>::const_min) / min64, static_cast<double>(integer_traits<outtype>::const_max) / max64 );
  const double newmin = min64 * scaling_factor;
  const double newmax = max64 * scaling_factor;
  cout << "Scaling factor = " << scaling_factor << " = " << min64 << ":" << max64 << " => " << newmin << ":" << newmax <<
        " [" << static_cast<double>(static_cast<outtype>(newmax)) << "]" << endl;
 
  // Do the caling
  outtype *outdata = reinterpret_cast<outtype *>(outfile.data());
  // transform(indata, indata+insize, outdata, bind(multiplies<double>(), _1, scaling_factor));
  transform(indata, indata+insize, outdata, ll_static_cast<outtype>(_1 * scaling_factor));
  cout << "Processed " << insize << " data points." << endl;
  return true;
};

int main (int argc, char **argv) {
        if (argc != 2) {
                cout << "Usage: " << argv[0] << " filename.16data" << endl;
                exit(99);
        }
        
        // Change file name
        string outfilename(argv[1]);
        boost::replace_last(outfilename, ".16data", ".8data");
                
  // Return zero is success in Unix
  return !ReadWriteScale<int16_t, int8_t>(argv[1], outfilename);
}