File: MemoryMappedFileReader.cpp

package info (click to toggle)
rdkit 202503.1-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 220,160 kB
  • sloc: cpp: 399,240; python: 77,453; ansic: 25,517; java: 8,173; javascript: 4,005; sql: 2,389; yacc: 1,565; lex: 1,263; cs: 1,081; makefile: 580; xml: 229; fortran: 183; sh: 105
file content (130 lines) | stat: -rw-r--r-- 3,835 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//
// Copyright (C) David Cosgrove 2025.
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//

#include <GraphMol/SynthonSpaceSearch/MemoryMappedFileReader.h>
#include <GraphMol/SynthonSpaceSearch/SynthonSpaceSearch_details.h>

#include <iostream>
#include <string>

#include <RDGeneral/RDLog.h>

#ifdef _WIN32
#include <windows.h>
#else
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#endif

namespace RDKit::SynthonSpaceSearch::details {
// This code is a lightly modified version of something provided by
// ChatGPT in response to the prompt:
// "in c++ can I use the same code for mmap on windows and linux?"
// ChatGPT assures me there are no license implications in using it.
// Accessed 26/2/2025.
MemoryMappedFileReader::MemoryMappedFileReader(const std::string &filePath) {
#ifdef _WIN32
  HANDLE hFile = CreateFile(filePath.c_str(), GENERIC_READ, 0, NULL,
                            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hFile == INVALID_HANDLE_VALUE) {
    throw(std::runtime_error("Error opening file " + filePath + "."));
  }

  // Get file size
  LARGE_INTEGER fileSize;
  if (!GetFileSizeEx(hFile, &fileSize)) {
    CloseHandle(hFile);
    throw(std::runtime_error("Error reading file " + filePath + "."));
  }
  d_size = static_cast<size_t>(fileSize.QuadPart);

  // Create a file mapping
  HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  if (hMapping == NULL) {
    CloseHandle(hFile);
    throw(std::runtime_error("Error reading file " + filePath + "."));
  }

  // Map the file into memory
  d_mappedMemory =
      static_cast<char *>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
  if (d_mappedMemory == NULL) {
    CloseHandle(hMapping);
    CloseHandle(hFile);
    throw(std::runtime_error("Error reading file " + filePath + "."));
  }

  CloseHandle(hMapping);  // Handle is no longer needed once mapped
  CloseHandle(hFile);     // File handle is no longer needed
#else
  int fd = open(filePath.c_str(), O_RDWR);
  if (fd == -1) {
    BOOST_LOG(rdErrorLog) << "Error opening file.\n";
    throw(std::runtime_error("Error opening file " + filePath + "."));
  }

  // Get file size
  struct stat fileStat;
  if (fstat(fd, &fileStat) == -1) {
    close(fd);
    throw(std::runtime_error("Error reading file " + filePath + "."));
  }
  d_size = static_cast<size_t>(fileStat.st_size);

  // Memory map the file
  d_mappedMemory =
      static_cast<char *>(mmap(NULL, d_size, PROT_READ, MAP_SHARED, fd, 0));
  if (d_mappedMemory == MAP_FAILED) {
    BOOST_LOG(rdErrorLog) << "Error mapping file.\n";
    close(fd);
    throw(std::runtime_error("Error reading file " + filePath + "."));
  }

  close(fd); // File descriptor is no longer needed
#endif
}

MemoryMappedFileReader::MemoryMappedFileReader(MemoryMappedFileReader &&other) {
  d_mappedMemory = other.d_mappedMemory;
  other.d_mappedMemory = nullptr;
  d_size = other.d_size;
  other.d_size = 0;
}

MemoryMappedFileReader::~MemoryMappedFileReader() {
#ifdef _WIN32
  // Windows-specific unmapping
  UnmapViewOfFile(d_mappedMemory);
#else
  // Linux-specific unmapping
  munmap(d_mappedMemory, d_size);
#endif
}

MemoryMappedFileReader &MemoryMappedFileReader::operator=(
  MemoryMappedFileReader &&other) {
  if (this != &other) {
#ifdef _WIN32
    // Windows-specific unmapping
    UnmapViewOfFile(d_mappedMemory);
#else
    // Linux-specific unmapping
    munmap(d_mappedMemory, d_size);
#endif
    d_mappedMemory = other.d_mappedMemory;
    d_size = other.d_size;
    other.d_mappedMemory = nullptr;
    other.d_size = 0;
  }
  return *this;
}
}; // namespace RDKit::SynthonSpaceSearch::details