Listing 2: Unix implementation of class ro_file

#include "ro_file.h"
#include <algorithm>
#include <stdexcept>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

namespace {
  std::pair<char*, std::size_t> initialize(const std::string& name)
  {
    int fd = open(name.c_str(), O_RDONLY);
    if (fd == -1)
      throw std::runtime_error("Can't open " + name + ": " 
                               + strerror(errno));

    off_t n = lseek(fd, 0, SEEK_END);
    void* p = MAP_FAILED;
    if (n != off_t(-1))
      p = mmap(0, (std::size_t) n, PROT_READ, MAP_PRIVATE, fd, 0);

    close(fd);

    if (p == MAP_FAILED)
      throw std::runtime_error("Can't map " + name + ": " 
                               + strerror(errno));

    return std::make_pair(static_cast<char*>(p),
                          static_cast<std::size_t>(n));
  }
}

ro_file::ro_file(const std::string& name)
  : file(name), base(0), length(0)
{
  std::pair<char*, std::size_t> p = initialize(file);
  base = p.first;
  length = p.second;
}

ro_file::ro_file(const ro_file& C)
  : file(C.file), base(0), length(0)
{
  std::pair<char*, std::size_t> p = initialize(file);
  base = p.first;
  length = p.second;
}

ro_file& ro_file::operator=(const ro_file& C)
{
  if (C != *this) {
    std::string tmp = C.file;
    std::pair<char*, std::size_t> p = initialize(C.file);

    munmap(base, length);
    file.swap(tmp);
    base = p.first;
    length = p.second;
  }

  return *this;
}

ro_file::~ro_file() 
{
  munmap(base, length);
}

void ro_file::swap(ro_file& C)
{
  std::swap(file, C.file);
  std::swap(base, C.base);
  std::swap(length, C.length);
}

bool operator==(const ro_file& x, const ro_file& y) {
  return x.size() == y.size() &&
    std::equal(x.begin(), x.end(), y.begin());
}

bool operator<(const ro_file& x, const ro_file& y) {
  return std::lexicographical_compare(x.begin(), x.end(),
                                      y.begin(), y.end());
}
— End of Listing —