<commit_before>/* This is free and unencumbered software released into the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "directory.h"
#include "error.h"
#include "mapped_file.h"
#include "pathname.h"

#include <algorithm>  /* for std::max(), std::min() */
#include <cassert>    /* for assert() */
#include <cerrno>     /* for errno */
#include <cstring>    /* for std::memmove() */
#include <fcntl.h>    /* for AT_FDCWD */
#include <unistd.h>   /* for _SC_PAGE_SIZE, sysconf() */
#include <utility>    /* for std::swap() */

#ifdef __linux__
#include <sys/mman.h> /* for MREMAP_MAYMOVE */
#endif

using namespace posix;

////////////////////////////////////////////////////////////////////////////////

mapped_file
mapped_file::open(const pathname& pathname,
                  const int flags,
                  const mode mode) {

  return mapped_file{AT_FDCWD, pathname.c_str(), flags, mode};
}

mapped_file
mapped_file::open(const directory& directory,
                  const pathname& pathname,
                  const int flags,
                  const mode mode) {

  return mapped_file{directory.fd(), pathname.c_str(), flags, mode};
}

////////////////////////////////////////////////////////////////////////////////

namespace {
  static std::size_t system_page_size() {
    return static_cast<std::size_t>(::sysconf(_SC_PAGE_SIZE));
  }
}

mapped_file::mapped_file(const int dirfd,
                         const char* const pathname,
                         int flags,
                         const mode mode)
  : file{dirfd, pathname, flags, mode},
    _size{file::size()},
    _offset{file::seek(0, SEEK_CUR)},
    _mapping{*this, std::max(_size, system_page_size())} {

  assert(_mapping.data());
}

mapped_file::mapped_file(mapped_file&& other) noexcept
  : mapped_file{} {

  std::swap(_fd, other._fd);
  std::swap(_size, other._size);
  std::swap(_offset, other._offset);
  std::swap(_mapping, other._mapping);
}

mapped_file&
mapped_file::operator=(mapped_file&& other) noexcept {
  if (this != &other) {
    std::swap(_fd, other._fd);
    std::swap(_size, other._size);
    std::swap(_offset, other._offset);
    std::swap(_mapping, other._mapping);
  }
  return *this;
}

////////////////////////////////////////////////////////////////////////////////

void
mapped_file::sync() {
  if (_mapping.writable()) {
    file::sync();
  }

  std::size_t new_size = file::size();
  if (new_size != _size) {
    new_size = std::max(_size, system_page_size());
#ifdef __linux__
    _mapping.remap(new_size, MREMAP_MAYMOVE);
#else
    throw_error(ENOSYS); // TODO: _mapping = ...
#endif
  }
}

std::size_t
mapped_file::seek(const off_t offset,
                  const int whence) {

  switch (whence) {
    case SEEK_CUR: {
      _offset += offset; // TODO: error handling
      break;
    }
    case SEEK_SET: {
      _offset = file::seek(offset, whence);
      break;
    }
    case SEEK_END:
    default: {
      _offset = file::seek(offset, whence);
      if (_offset > _mapping.size()) {
        // TODO: _mapping.extend();
      }<commit_msg>Fixed a bug in posix::mapped_file#sync().<commit_after>/* This is free and unencumbered software released into the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "directory.h"
#include "error.h"
#include "mapped_file.h"
#include "pathname.h"

#include <algorithm>  /* for std::max(), std::min() */
#include <cassert>    /* for assert() */
#include <cerrno>     /* for errno */
#include <cstring>    /* for std::memmove() */
#include <fcntl.h>    /* for AT_FDCWD */
#include <unistd.h>   /* for _SC_PAGE_SIZE, sysconf() */
#include <utility>    /* for std::swap() */

#ifdef __linux__
#include <sys/mman.h> /* for MREMAP_MAYMOVE */
#endif

using namespace posix;

////////////////////////////////////////////////////////////////////////////////

mapped_file
mapped_file::open(const pathname& pathname,
                  const int flags,
                  const mode mode) {

  return mapped_file{AT_FDCWD, pathname.c_str(), flags, mode};
}

mapped_file
mapped_file::open(const directory& directory,
                  const pathname& pathname,
                  const int flags,
                  const mode mode) {

  return mapped_file{directory.fd(), pathname.c_str(), flags, mode};
}

////////////////////////////////////////////////////////////////////////////////

namespace {
  static std::size_t system_page_size() {
    return static_cast<std::size_t>(::sysconf(_SC_PAGE_SIZE));
  }
}

mapped_file::mapped_file(const int dirfd,
                         const char* const pathname,
                         int flags,
                         const mode mode)
  : file{dirfd, pathname, flags, mode},
    _size{file::size()},
    _offset{file::seek(0, SEEK_CUR)},
    _mapping{*this, std::max(_size, system_page_size())} {

  assert(_mapping.data());
}

mapped_file::mapped_file(mapped_file&& other) noexcept
  : mapped_file{} {

  std::swap(_fd, other._fd);
  std::swap(_size, other._size);
  std::swap(_offset, other._offset);
  std::swap(_mapping, other._mapping);
}

mapped_file&
mapped_file::operator=(mapped_file&& other) noexcept {
  if (this != &other) {
    std::swap(_fd, other._fd);
    std::swap(_size, other._size);
    std::swap(_offset, other._offset);
    std::swap(_mapping, other._mapping);
  }
  return *this;
}

////////////////////////////////////////////////////////////////////////////////

void
mapped_file::sync() {
  if (_mapping.writable()) {
    file::sync();
  }

  std::size_t new_size = file::size();
  if (new_size != _size) {
    _size = new_size;
    new_size = std::max(_size, system_page_size());
#ifdef __linux__
    _mapping.remap(new_size, MREMAP_MAYMOVE);
#else
    throw_error(ENOSYS); // TODO: _mapping = ...
#endif
  }
}

std::size_t
mapped_file::seek(const off_t offset,
                  const int whence) {

  switch (whence) {
    case SEEK_CUR: {
      _offset += offset; // TODO: error handling
      break;
    }
    case SEEK_SET: {
      _offset = file::seek(offset, whence);
      break;
    }
    case SEEK_END:
    default: {
      _offset = file::seek(offset, whence);
      if (_offset > _mapping.size()) {
        // TODO: _mapping.extend();
      }
{'fraction_non_alphanumeric': 0.21495027269810715, 'fraction_numerical': 0.0003208213025344883, 'mean_word_length': 2.2355993772703684, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4121113', 'n_tokens_mistral': 2023, 'n_tokens_neox': 1971, 'n_words': 432}