File: utils_summarized_experiment.hpp

package info (click to toggle)
r-bioc-alabaster.base 1.6.1%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 1,652 kB
  • sloc: cpp: 11,377; sh: 29; makefile: 2
file content (95 lines) | stat: -rw-r--r-- 3,076 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
#ifndef TAKANE_UTILS_SUMMARIZED_EXPERIMENT_HPP
#define TAKANE_UTILS_SUMMARIZED_EXPERIMENT_HPP

#include "millijson/millijson.hpp"
#include "utils_json.hpp"

#include <unordered_set>
#include <string>
#include <stdexcept>
#include <filesystem>
#include <cmath>

namespace takane {

namespace internal_summarized_experiment {

inline std::pair<size_t, size_t> extract_dimensions_json(const internal_json::JsonObjectMap& semap, const std::string& type) {
    size_t num_rows = 0, num_cols = 0;

    auto dIt = semap.find("dimensions");
    if (dIt == semap.end()) {
        throw std::runtime_error("expected a '" + type + ".dimensions' property");
    }
    const auto& dims = dIt->second;
    if (dims->type() != millijson::ARRAY) {
        throw std::runtime_error("expected '" + type + ".dimensions' to be an array");
    }

    auto dptr = reinterpret_cast<const millijson::Array*>(dims.get());
    if (dptr->values.size() != 2) {
        throw std::runtime_error("expected '" + type + ".dimensions' to be an array of length 2");
    }

    size_t counter = 0;
    for (const auto& x : dptr->values) {
        if (x->type() != millijson::NUMBER) {
            throw std::runtime_error("expected '" + type + ".dimensions' to be an array of numbers");
        }
        auto val = reinterpret_cast<const millijson::Number*>(x.get())->value;
        if (val < 0 || std::floor(val) != val) {
            throw std::runtime_error("expected '" + type + ".dimensions' to contain non-negative integers");
        }
        if (counter == 0) {
            num_rows = val;
        } else {
            num_cols = val;
        }
        ++counter;
    }

    return std::make_pair(num_rows, num_cols);
}

inline void check_names_json(const std::filesystem::path& dir, std::unordered_set<std::string>& present) try {
    auto parsed = internal_json::parse_file(dir / "names.json");
    if (parsed->type() != millijson::ARRAY) {
        throw std::runtime_error("expected an array");
    }

    auto aptr = reinterpret_cast<const millijson::Array*>(parsed.get());
    size_t number = aptr->values.size();
    present.reserve(number);

    for (size_t i = 0; i < number; ++i) {
        auto eptr = aptr->values[i];
        if (eptr->type() != millijson::STRING) {
            throw std::runtime_error("expected an array of strings");
        }

        auto nptr = reinterpret_cast<const millijson::String*>(eptr.get());
        auto name = nptr->value;
        if (name.empty()) {
            throw std::runtime_error("name should not be an empty string");
        }
        if (present.find(name) != present.end()) {
            throw std::runtime_error("detected duplicated name '" + name + "'");
        }
        present.insert(std::move(name));
    }

} catch (std::exception& e) {
    throw std::runtime_error("invalid '" + dir.string() + "/names.json' file; " + std::string(e.what()));
}

inline size_t check_names_json(const std::filesystem::path& dir) {
    std::unordered_set<std::string> present;
    check_names_json(dir, present);
    return present.size();
}

}

}

#endif