Modernes C++ programmieren

Okt 20, 2024

listings-Chap22-README-onepage.md

Listings of Chap22.docx

This is the list of listings on one page. You can also view a linked summary.

Listing 22.1: The “gzpack.cpp” program uses a C library. Here you see the section with the includes.

Book listing lst-0004-book.cpp:

// https://godbolt.org/z/9Trh8h8Mb 
#include <string>
#include <vector>
#include <span>      // C++20
#include <fstream>   // ifstream
#include <stdexcept> // runtime_error
#include <iostream>  // cerr
// C-Header:
#include <zlib.h>    // gzXyz; sudo aptitude install libz-dev
#include <cerrno>    // errno
#include <cstring>   // strerror
namespace {
using std::string; using std::span; using std::byte;

Godbolt Listing lst-0004-godb.cpp, https://godbolt.org/z/9Trh8h8Mb:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9Trh8h8Mb 
#include <string>
#include <vector>
#include <span>      // C++20
#include <fstream>   // ifstream
#include <stdexcept> // runtime_error
#include <iostream>  // cerr
// C-Header:
#include <zlib.h>    // gzXyz; sudo aptitude install libz-dev
#include <cerrno>    // errno
#include <cstring>   // strerror
namespace {
using std::string; using std::span; using std::byte;

Listing 22.2: This part of “gzpack.cpp” contains all the C functions used.

Book listing lst-0005-book.cpp:

// https://godbolt.org/z/Yh7j1WEGc 
class GzWriteStream {                         // RAII wrapper
public:
    gzFile gz_ ;                              // C struct from zlib.h
    explicit GzWriteStream(const string& filename)
        : gz_{gzopen(filename.c_str(),"wb9")} // 'w': write, 'b':binary, '9':level
    {
        if(gz_==NULL) throw std::runtime_error(std::strerror(errno));
    }
    ~GzWriteStream() {
        gzclose(gz_);
    }
    GzWriteStream& operator<<(const span<char> &data) {
        write(data);
        return *this;
    }
private:
    void write(span<char> data) {
        auto bytes = std::as_bytes(data);                    // C++20
        auto res = gzwrite(gz_, bytes.data(), size(bytes));
        if(res==0) throw std::runtime_error("Error writing");
    }
    GzWriteStream(const GzWriteStream&) = delete;            // no copy
    GzWriteStream& operator=(const GzWriteStream&) = delete; // no assignment
};

Godbolt Listing lst-0005-godb.cpp, https://godbolt.org/z/Yh7j1WEGc:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Yh7j1WEGc 
class GzWriteStream {                         // RAII wrapper
public:
    gzFile gz_ ;                              // C struct from zlib.h
    explicit GzWriteStream(const string& filename)
        : gz_{gzopen(filename.c_str(),"wb9")} // 'w': write, 'b':binary, '9':level
    {
        if(gz_==NULL) throw std::runtime_error(std::strerror(errno));
    }
    ~GzWriteStream() {
        gzclose(gz_);
    }
    GzWriteStream& operator<<(const span<char> &data) {
        write(data);
        return *this;
    }
private:
    void write(span<char> data) {
        auto bytes = std::as_bytes(data);                    // C++20
        auto res = gzwrite(gz_, bytes.data(), size(bytes));
        if(res==0) throw std::runtime_error("Error writing");
    }
    GzWriteStream(const GzWriteStream&) = delete;            // no copy
    GzWriteStream& operator=(const GzWriteStream&) = delete; // no assignment
};

Listing 22.3: This part of “gzpack.cpp” handles reading and writing the files.

Book listing lst-0007-book.cpp:

// https://godbolt.org/z/84TcTbWjj
std::vector<char> readFile(const string& fName) {
    std::ifstream file{ fName, std::ifstream::binary };
    if(!file) throw std::runtime_error("Error opening input");
    file.seekg(0, file.end);           // jump to the end of the file
    const auto length = file.tellg();  // current position is file size
    if(length > 1024*1024*1024)
        throw std::runtime_error("No more than 1 GB please");
    file.seekg(0, file.beg);           // back to the beginning
    std::vector<char> data(length);    // allocate space
    file.read(data.data(), length);    // read in one go
    return data;                       // not copied (keyword: RVO)
}
void pack(const string& fNameIn, const string& fNameOut) {
    auto data = readFile(fNameIn);     // read input
    GzWriteStream gz{fNameOut};        // initialize output
    gz << data;
}

Godbolt Listing lst-0007-godb.cpp, https://godbolt.org/z/84TcTbWjj:

//#(compile) c++; compiler:g141; options:-O1 -std=c++23 -Wall -Wextra; libs:-
// https://godbolt.org/z/84TcTbWjj
std::vector<char> readFile(const string& fName) {
    std::ifstream file{ fName, std::ifstream::binary };
    if(!file) throw std::runtime_error("Error opening input");
    file.seekg(0, file.end);           // jump to the end of the file
    const auto length = file.tellg();  // current position is file size
    if(length > 1024*1024*1024)
        throw std::runtime_error("No more than 1 GB please");
    file.seekg(0, file.beg);           // back to the beginning
    std::vector<char> data(length);    // allocate space
    file.read(data.data(), length);    // read in one go
    return data;                       // not copied (keyword: RVO)
}
void pack(const string& fNameIn, const string& fNameOut) {
    auto data = readFile(fNameIn);     // read input
    GzWriteStream gz{fNameOut};        // initialize output
    gz << data;
}

Listing 22.4: With “main” in “gzpack.cpp”, the example is complete.

Book listing lst-0008-book.cpp:

// https://godbolt.org/z/5bWx6PzdP
} // namespace
int main(int argc, const char* argv[]) {
    try {
        const std::vector<string> fNamen {argv+1, argv+argc};
        for(auto fName : fNamen) {
            std::cout << "packing " << fName << "... ";
            pack(fName, fName+".gz");
            std::cout << fName << ".gz"<< "\n";
        }
    } catch(std::runtime_error &exc) {
        std::cerr << "Error: " << exc.what() << "\n";
    }
}

Godbolt Listing lst-0008-godb.cpp, https://godbolt.org/z/5bWx6PzdP:

//#(compile) c++; compiler:g141; options:-O1 -std=c++23 -lz; libs:-
// https://godbolt.org/z/5bWx6PzdP
} // namespace
int main(int argc, const char* argv[]) {
    try {
        const std::vector<string> fNamen {argv+1, argv+argc};
        for(auto fName : fNamen) {
            std::cout << "packing " << fName << "... ";
            pack(fName, fName+".gz");
            std::cout << fName << ".gz"<< "\n";
        }
    } catch(std::runtime_error &exc) {
        std::cerr << "Error: " << exc.what() << "\n";
    }
}