• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

BlueBrain / MorphIO / 6533524408

16 Oct 2023 12:24PM UTC coverage: 76.051% (-0.02%) from 76.073%
6533524408

push

github

mgeplf
fix test_root_node_split

1972 of 2593 relevant lines covered (76.05%)

903.23 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.16
/src/collection.cpp
1
/* Copyright (c) 2013-2023, EPFL/Blue Brain Project
2
 *
3
 * SPDX-License-Identifier: Apache-2.0
4
 */
5
#include <morphio/collection.h>
6

7
#include "shared_utils.hpp"
8
#include <highfive/H5File.hpp>
9

10
#include "readers/morphologyHDF5.h"
11

12
namespace morphio {
13

14
class LoadUnorderedImpl
15
{
16
  public:
17
    virtual ~LoadUnorderedImpl() = default;
10✔
18

19
    virtual Morphology load(size_t k) const = 0;
20
    virtual mut::Morphology load_mut(size_t k) const = 0;
21

22
    virtual size_t size() const = 0;
23
};
24

25
namespace detail {
26

27
/**
28
 *  Load morphologies in the specified order.
29
 *
30
 *  Given access to the `collection`, the morphology names and an ordered
31
 *  vectors of loop indices, one can implement simple optimized access pattern
32
 *  by simply loading the morphologies in the order the loop indices prescribe.
33
 *
34
 *  The above approach is implemented by this class.
35
 */
36
class LoadUnorderedFromLoopIndices: public LoadUnorderedImpl
37
{
38
  public:
39
    LoadUnorderedFromLoopIndices(Collection collection,
10✔
40
                                 std::vector<size_t> loop_indices,
41
                                 std::vector<std::string> morphology_names,
42
                                 unsigned int options)
43
        : _collection(std::move(collection))
20✔
44
        , _loop_indices(std::move(loop_indices))
10✔
45
        , _morphology_names(std::move(morphology_names))
10✔
46
        , _options(options) {}
10✔
47

48
    size_t size() const override {
28✔
49
        return _morphology_names.size();
28✔
50
    }
51

52
    Morphology load(size_t k) const override {
68✔
53
        return load_impl<Morphology>(k);
68✔
54
    }
55

56
    mut::Morphology load_mut(size_t k) const override {
×
57
        return load_impl<mut::Morphology>(k);
×
58
    }
59

60
  protected:
61
    template <class M>
62
    M load_impl(size_t k) const {
68✔
63
        auto i = _loop_indices[k];
68✔
64
        return _collection.template load<M>(_morphology_names[i], _options);
68✔
65
    }
66

67
  private:
68
    Collection _collection;
69
    std::vector<size_t> _loop_indices;
70
    std::vector<std::string> _morphology_names;
71
    unsigned int _options;
72
};
73

74
}  // namespace detail
75

76

77
class CollectionImpl
78
{
79
  public:
80
    virtual ~CollectionImpl() = default;
60✔
81

82
    virtual Morphology load(const std::string& morph_name, unsigned int options) const = 0;
83

84
    virtual mut::Morphology load_mut(const std::string& morph_name, unsigned int options) const = 0;
85

86
    virtual std::shared_ptr<LoadUnorderedImpl> load_unordered(Collection collection,
87
                                                              std::vector<std::string> morph_name,
88
                                                              unsigned int options) const = 0;
89

90
    virtual std::vector<size_t> argsort(const std::vector<std::string>& morphology_names) const = 0;
91
};
92

93
namespace detail {
94
template <class Derived>
95
class CollectionImpl: public morphio::CollectionImpl
96
{
97
    // The purpose of this class is to implement the two separate
98
    // functions in terms of a single templated method `load_impl`.
99
  public:
100
    morphio::Morphology load(const std::string& morph_name, unsigned int options) const override {
94✔
101
        const auto& derived = static_cast<const Derived&>(*this);
94✔
102
        return derived.template load_impl<Morphology>(morph_name, options);
94✔
103
    }
104

105
    morphio::mut::Morphology load_mut(const std::string& morph_name,
20✔
106
                                      unsigned int options) const override {
107
        const auto& derived = static_cast<const Derived&>(*this);
20✔
108
        return derived.template load_impl<mut::Morphology>(morph_name, options);
20✔
109
    }
110

111
    std::shared_ptr<LoadUnorderedImpl> load_unordered(Collection collection,
10✔
112
                                                      std::vector<std::string> morphology_names,
113
                                                      unsigned int options) const override {
114
        auto loop_indices = argsort(morphology_names);
10✔
115
        return std::make_shared<detail::LoadUnorderedFromLoopIndices>(std::move(collection),
10✔
116
                                                                      std::move(loop_indices),
10✔
117
                                                                      std::move(morphology_names),
10✔
118
                                                                      options);
20✔
119
    }
120
};
121
}  // namespace detail
122

123
class DirectoryCollection: public morphio::detail::CollectionImpl<DirectoryCollection>
124
{
125
  public:
126
    DirectoryCollection(std::string collection_path, std::vector<std::string> extensions)
32✔
127
        : _dirname(std::move(collection_path))
64✔
128
        , _extensions(std::move(extensions)) {}
32✔
129

130
  protected:
131
    friend morphio::detail::CollectionImpl<DirectoryCollection>;
132

133
    template <class M>
134
    M load_impl(const std::string& morph_name, unsigned int options) const {
46✔
135
        return M(morphology_path(morph_name), options);
46✔
136
    }
137

138
    std::string morphology_path(const std::string& morph_name) const {
46✔
139
        for (const auto& ext : _extensions) {
62✔
140
            auto path = morphio::join_path(_dirname, morph_name + ext);
60✔
141
            if (morphio::is_regular_file(path)) {
60✔
142
                return path;
88✔
143
            }
144
        }
145

146
        throw MorphioError("Morphology '" + morph_name + "' not found in: " + _dirname);
2✔
147
    }
148

149
    std::vector<size_t> argsort(const std::vector<std::string>& morphology_names) const override {
6✔
150
        auto n_morphologies = morphology_names.size();
6✔
151
        std::vector<size_t> loop_indices(n_morphologies);
6✔
152
        for (size_t i = 0; i < n_morphologies; ++i) {
34✔
153
            loop_indices[i] = i;
28✔
154
        }
155

156
        return loop_indices;
6✔
157
    }
158

159
  private:
160
    std::string _dirname;
161
    std::vector<std::string> _extensions;
162
};
163

164
class HDF5ContainerCollection: public morphio::detail::CollectionImpl<HDF5ContainerCollection>
165
{
166
  public:
167
    /**
168
     * Create the collection from an HDF5 container.
169
     *
170
     * This provides a way for C++ applications to inject specifics about how
171
     * to open the container.
172
     */
173
    HDF5ContainerCollection(HighFive::File file)
28✔
174
        : _file(std::move(file)) {}
28✔
175

176
    /**
177
     * Create the collection from a path.
178
     */
179
    HDF5ContainerCollection(const std::string& collection_path)
28✔
180
        : HDF5ContainerCollection(default_open_file(collection_path)) {}
28✔
181

182
    HDF5ContainerCollection(HDF5ContainerCollection&&) = delete;
183
    HDF5ContainerCollection(const HDF5ContainerCollection&) = delete;
184

185
    HDF5ContainerCollection& operator=(const HDF5ContainerCollection&) = delete;
186
    HDF5ContainerCollection& operator=(HDF5ContainerCollection&&) = delete;
187

188
    std::vector<size_t> argsort(const std::vector<std::string>& morphology_names) const override {
8✔
189
        auto n_morphologies = morphology_names.size();
8✔
190
        std::vector<hsize_t> offsets(n_morphologies);
16✔
191
        std::vector<size_t> loop_indices(n_morphologies);
8✔
192

193
        for (size_t i = 0; i < n_morphologies; ++i) {
46✔
194
            loop_indices[i] = i;
38✔
195

196
            const auto& morph_name = morphology_names[i];
38✔
197

198
            auto morph = _file.getGroup(morph_name.data());
114✔
199
            auto points = morph.getDataSet("points");
114✔
200

201
            auto dcpl = points.getCreatePropertyList();
38✔
202
            auto layout = H5Pget_layout(dcpl.getId());
38✔
203
            offsets[i] = layout == H5D_CONTIGUOUS ? points.getOffset() : size_t(-1);
38✔
204
        }
205

206
        std::sort(loop_indices.begin(), loop_indices.end(), [&offsets](size_t i, size_t j) {
8✔
207
            return offsets[i] < offsets[j];
50✔
208
        });
209

210
        return loop_indices;
16✔
211
    }
212

213
  protected:
214
    friend morphio::detail::CollectionImpl<HDF5ContainerCollection>;
215

216
    template <class M>
217
    M load_impl(const std::string& morph_name, unsigned int options) const {
68✔
218
        std::lock_guard<std::recursive_mutex> lock(morphio::readers::h5::global_hdf5_mutex());
68✔
219
        return M(_file.getGroup(morph_name), options);
136✔
220
    }
221

222
  protected:
223
    static HighFive::File default_open_file(const std::string& container_path) {
28✔
224
        std::lock_guard<std::recursive_mutex> lock(morphio::readers::h5::global_hdf5_mutex());
56✔
225
        return HighFive::File(container_path, HighFive::File::ReadOnly);
56✔
226
    }
227

228
  private:
229
    HighFive::File _file;
230
};
231

232
namespace detail {
233
static std::shared_ptr<morphio::CollectionImpl> open_collection(
60✔
234
    std::string collection_path, std::vector<std::string> extensions) {
235
    if (morphio::is_directory(collection_path)) {
60✔
236
        // Triggers loading SWC, ASC, H5, etc. morphologies that are stored as
237
        // separate files in one directory.
238
        return std::make_shared<DirectoryCollection>(std::move(collection_path),
64✔
239
                                                     std::move(extensions));
64✔
240
    }
241

242
    if (morphio::is_regular_file(collection_path)) {
28✔
243
        // Prepare to load from containers.
244
        return std::make_shared<HDF5ContainerCollection>(std::move(collection_path));
28✔
245
    }
246

247
    throw std::invalid_argument("Invalid path: " + collection_path);
×
248
}
249

250
}  // namespace detail
251

252
Collection::Collection(std::shared_ptr<CollectionImpl> collection)
60✔
253
    : _collection(std::move(collection)) {
60✔
254
    if (_collection == nullptr) {
60✔
255
        throw std::invalid_argument("Can't construct a collection from a nullptr.");
×
256
    }
257
}
60✔
258

259
Collection::Collection(std::string collection_path, std::vector<std::string> extensions)
60✔
260
    : Collection(detail::open_collection(std::move(collection_path), std::move(extensions))) {}
60✔
261

262

263
template <class M>
264
typename enable_if_immutable<M, M>::type Collection::load(const std::string& morph_name,
94✔
265
                                                          unsigned int options) const {
266
    if (_collection != nullptr) {
94✔
267
        return _collection->load(morph_name, options);
94✔
268
    }
269

270
    throw std::runtime_error("The collection has been closed.");
×
271
}
272

273
template <class M>
274
typename enable_if_mutable<M, M>::type Collection::load(const std::string& morph_name,
20✔
275
                                                        unsigned int options) const {
276
    if (_collection != nullptr) {
20✔
277
        return _collection->load_mut(morph_name, options);
20✔
278
    }
279

280
    throw std::runtime_error("The collection has been closed.");
×
281
}
282

283
std::vector<size_t> Collection::argsort(const std::vector<std::string>& morphology_names) const {
4✔
284
    if (_collection != nullptr) {
4✔
285
        return _collection->argsort(morphology_names);
4✔
286
    }
287

288
    throw std::runtime_error("The collection has been closed.");
×
289
}
290

291
template mut::Morphology Collection::load<mut::Morphology>(const std::string& morph_name,
292
                                                           unsigned int options) const;
293

294
template Morphology Collection::load<Morphology>(const std::string& morph_name,
295
                                                 unsigned int options) const;
296

297

298
template <class M>
299
LoadUnordered<M> Collection::load_unordered(std::vector<std::string> morphology_names,
10✔
300
                                            unsigned int options) const {
301
    return LoadUnordered<M>(_collection->load_unordered(*this, morphology_names, options));
10✔
302
}
303

304
template LoadUnordered<mut::Morphology> Collection::load_unordered<mut::Morphology>(
305
    std::vector<std::string> morphology_names, unsigned int options) const;
306

307
template LoadUnordered<Morphology> Collection::load_unordered<Morphology>(
308
    std::vector<std::string> morphology_names, unsigned int options) const;
309

310

311
void Collection::close() {
×
312
    _collection = nullptr;
×
313
}
×
314

315

316
template <class M>
317
typename LoadUnordered<M>::Iterator LoadUnordered<M>::begin() const {
10✔
318
    return Iterator(_load_unordered_impl, 0);
10✔
319
}
320

321
template <class M>
322
typename LoadUnordered<M>::Iterator LoadUnordered<M>::end() const {
28✔
323
    return Iterator(_load_unordered_impl, _load_unordered_impl->size());
28✔
324
}
325

326
template <class M>
327
LoadUnordered<M>::LoadUnordered(std::shared_ptr<LoadUnorderedImpl> load_unordered_impl)
10✔
328
    : _load_unordered_impl(load_unordered_impl) {}
10✔
329

330
template <class M>
331
LoadUnordered<M>::Iterator::Iterator(std::shared_ptr<LoadUnorderedImpl> load_unordered_impl,
40✔
332
                                     size_t k)
333
    : _k(k)
334
    , _load_unordered_impl(std::move(load_unordered_impl)) {}
40✔
335

336
template <class M>
337
bool LoadUnordered<M>::Iterator::operator==(const LoadUnordered::Iterator& other) const {
48✔
338
    return (*this)._k == other._k;
48✔
339
}
340

341
template <class M>
342
bool LoadUnordered<M>::Iterator::operator!=(const LoadUnordered::Iterator& other) const {
48✔
343
    return !((*this) == other);
48✔
344
}
345

346
template <class M>
347
typename LoadUnordered<M>::Iterator& LoadUnordered<M>::Iterator::operator++() {
44✔
348
    ++_k;
44✔
349
    return *this;
44✔
350
}
351

352
template <class M>
353
typename LoadUnordered<M>::Iterator LoadUnordered<M>::Iterator::operator++(int) {
2✔
354
    return LoadUnordered<M>::Iterator(_load_unordered_impl, _k++);
2✔
355
}
356

357
template <class M>
358
template <class U>
359
typename enable_if_mutable<U, std::pair<size_t, M>>::type LoadUnordered<M>::Iterator::operator*()
×
360
    const {
361
    return {_k, std::move(_load_unordered_impl->load_mut(_k))};
×
362
}
363

364
template <class M>
365
template <class U>
366
typename enable_if_immutable<U, std::pair<size_t, M>>::type LoadUnordered<M>::Iterator::operator*()
68✔
367
    const {
368
    return {_k, std::move(_load_unordered_impl->load(_k))};
68✔
369
}
370

371

372
template LoadUnordered<Morphology>::Iterator::Iterator(
373
    std::shared_ptr<LoadUnorderedImpl> load_unordered_impl, size_t k);
374

375
template LoadUnordered<mut::Morphology>::Iterator::Iterator(
376
    std::shared_ptr<LoadUnorderedImpl> load_unordered_impl, size_t k);
377

378

379
template typename LoadUnordered<Morphology>::Iterator LoadUnordered<Morphology>::begin() const;
380

381
template typename LoadUnordered<mut::Morphology>::Iterator LoadUnordered<mut::Morphology>::begin()
382
    const;
383

384
template typename LoadUnordered<Morphology>::Iterator LoadUnordered<Morphology>::end() const;
385

386
template typename LoadUnordered<mut::Morphology>::Iterator LoadUnordered<mut::Morphology>::end()
387
    const;
388

389
template LoadUnordered<Morphology>::LoadUnordered(
390
    std::shared_ptr<LoadUnorderedImpl> load_unordered_impl);
391

392
template LoadUnordered<mut::Morphology>::LoadUnordered(
393
    std::shared_ptr<LoadUnorderedImpl> load_unordered_impl);
394

395

396
template bool LoadUnordered<Morphology>::Iterator::operator==(
397
    const LoadUnordered::Iterator& other) const;
398

399
template bool LoadUnordered<mut::Morphology>::Iterator::operator==(
400
    const LoadUnordered::Iterator& other) const;
401

402

403
template bool LoadUnordered<Morphology>::Iterator::operator!=(
404
    const LoadUnordered::Iterator& other) const;
405

406
template bool LoadUnordered<mut::Morphology>::Iterator::operator!=(
407
    const LoadUnordered::Iterator& other) const;
408

409
template typename LoadUnordered<Morphology>::Iterator&
410
LoadUnordered<Morphology>::Iterator::operator++();
411

412
template typename LoadUnordered<mut::Morphology>::Iterator&
413
LoadUnordered<mut::Morphology>::Iterator::operator++();
414

415
template typename LoadUnordered<Morphology>::Iterator
416
LoadUnordered<Morphology>::Iterator::operator++(int);
417

418
template typename LoadUnordered<mut::Morphology>::Iterator
419
LoadUnordered<mut::Morphology>::Iterator::operator++(int);
420

421
template typename enable_if_mutable<mut::Morphology, std::pair<size_t, mut::Morphology>>::type
422
    LoadUnordered<mut::Morphology>::Iterator::operator*<mut::Morphology>() const;
423

424
template typename enable_if_immutable<Morphology, std::pair<size_t, Morphology>>::type
425
    LoadUnordered<Morphology>::Iterator::operator*<Morphology>() const;
426

427

428
}  // namespace morphio
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc