Posts for the month of February 2014
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); }