File: sparse.cpp

package info (click to toggle)
mrtrix3 3.0.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 13,712 kB
  • sloc: cpp: 129,776; python: 9,494; sh: 593; makefile: 234; xml: 47
file content (187 lines) | stat: -rw-r--r-- 6,788 bytes parent folder | download
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/* Copyright (c) 2008-2022 the MRtrix3 contributors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Covered Software is provided under this License on an "as is"
 * basis, without warranty of any kind, either expressed, implied, or
 * statutory, including, without limitation, warranties that the
 * Covered Software is free of defects, merchantable, fit for a
 * particular purpose or non-infringing.
 * See the Mozilla Public License v. 2.0 for more details.
 *
 * For more details, see http://www.mrtrix.org/.
 */

#include "header.h"
#include "image_io/sparse.h"



namespace MR
{
  namespace ImageIO
  {



    void SparseLegacy::load (const Header& header, size_t)
    {

      Default::load (header,0);

      std::fstream stream (file.name.c_str(), std::ios_base::in | std::ios_base::binary);
      stream.seekg (0, std::ios::end);
      const uint64_t file_size = stream.tellg();
      stream.close();
      const uint64_t current_sparse_data_size = file_size - file.start;

      if (current_sparse_data_size) {

        mmap.reset (new File::MMap (file, is_image_readwrite(), true, current_sparse_data_size));
        data_end = current_sparse_data_size;

      } else if (is_image_readwrite()) {

        //CONF option: SparseDataInitialSize
        //CONF default: 16777216
        //CONF Initial buffer size for data in MRtrix sparse image format file (in bytes).

        // Default = initialise 16MB, this is enough to store whole-brain fixel data at 2.5mm resolution
        const uint64_t init_sparse_data_size = File::Config::get_int ("SparseDataInitialSize", 16777216);
        const size_t new_file_size = file.start + init_sparse_data_size;
        DEBUG ("Initialising output sparse data file " + file.name + ": new file size " + str(new_file_size) 
            + " (" + str(init_sparse_data_size) + " of which is initial sparse data buffer)");
        File::resize (file.name, new_file_size);
        mmap.reset (new File::MMap (file, is_image_readwrite(), false, init_sparse_data_size));

        // Writes a single uint32_t(0) to the start of the sparse data region
        // Any voxel that has its value initialised to 0 will point here, and therefore dereferencing of any
        //   such voxel will yield a Fixel::Value with zero elements
        memset (off2mem (0), 0x00, sizeof (uint32_t));

        data_end = sizeof(uint32_t);

      }

      // If this is the formation of a new image, want to explicitly zero all of the
      //   raw image data - otherwise any random data could be misinterpreted as a large
      //   pointer offset from the start of the sparse image data
      if (is_image_new()) {
        for (auto& i : mmaps) 
          memset (i->address(), 0x00, i->size());
      }

    }



    void SparseLegacy::unload (const Header& header)
    {

      Default::unload (header);

      const uint64_t truncate_file_size = (data_end == size()) ? 0 : file.start + data_end;
      // Null the excess data before closing the memory map to prevent std::ofstream from giving an error
      //   (writing uninitialised values)
      memset (off2mem(data_end), 0x00, size() - data_end);
      mmap.reset();

      if (truncate_file_size) {
        DEBUG ("truncating sparse image data file " + file.name + " to " + str(truncate_file_size) + " bytes");
        File::resize (file.name, truncate_file_size);
      }

    }









    uint64_t SparseLegacy::set_numel (const uint64_t old_offset, const uint32_t numel)
    {
      assert (is_image_readwrite());

      // Before allocating new memory, verify that the current offset does not point to
      //   a voxel that has more elements than is required
      if (old_offset) {

        assert (old_offset < data_end);

        const uint32_t existing_numel = get_numel (old_offset);
        if (existing_numel >= numel) {

          // Set the new number of elements, clear the unwanted data, and return
          memcpy (off2mem(old_offset), &numel, sizeof(uint32_t));
          memset (off2mem(old_offset) + sizeof(uint32_t) + (numel * class_size), 0x00, ((existing_numel - numel) * class_size));
          // If this voxel is being cleared (i.e. no elements), rather than returning a pointer to a voxel with
          //   zero elements, instead return a pointer to the start of the sparse data, where there's a single
          //   uint32_t(0) which can be used for any and all voxels with zero elements
          return numel ? old_offset : 0;

        } else {

          // Existing memory allocation for this voxel is not sufficient; erase it
          // Note that the handler makes no attempt at re-using this memory later; new data is just concatenated
          //   to the end of the buffer
          memset (off2mem(old_offset), 0x00, sizeof(uint32_t) + (existing_numel * class_size));

        }
      }

      // Don't allocate memory for voxels with no sparse data; just point them all to the start of the
      //   sparse data where theres a single uint32_t(0)
      if (!numel)
        return 0;

      const int64_t requested_size = sizeof (uint32_t) + (numel * class_size);
      if (data_end + requested_size > size()) {

        // size() should never be empty if data is being written...
        assert (size());
        uint64_t new_sparse_data_size = 2 * size();

        // Cover rare case where a huge memory request occurs early
        while (new_sparse_data_size < data_end + requested_size)
          new_sparse_data_size *= 2;

        // Memory error arises due to the uninitialised data between the end of the sparse data and the end
        //   of the file at its current size being written using std::ofstream
        // Therefore, explicitly null all data that hasn't already been written
        //   (this does not prohibit the use of this memory for subsequent sparse data though)
        memset (off2mem(data_end), 0x00, size() - data_end);

        mmap.reset();

        const size_t new_file_size = file.start + new_sparse_data_size;
        DEBUG ("Resizing sparse data file " + file.name + ": new file size " + str(new_file_size) + " (" + str(new_sparse_data_size) + " of which is for sparse data)");
        File::resize (file.name, new_file_size);
        mmap.reset (new File::MMap (file, Base::writable, true, new_sparse_data_size));

      }

      // Write the uint32_t indicating the number of elements in this voxel
      memcpy (off2mem(data_end), &numel, sizeof(uint32_t));

      // The return value is the offset from the beginning of the sparse data
      const uint64_t ret = data_end;
      data_end += requested_size;

      return ret;
    }







  }
}