summaryrefslogtreecommitdiff
path: root/cpp/pom.hpp
blob: 69a979d0716469a664b8d6f0c1a202dc25c7372a (plain)
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
#ifndef POM_HPP_
#define POM_HPP_

#include <exception>
#include <cstdint>
#include <string_view>
#include <string>
#include <vector>
#include <memory>
#include <optional>

namespace pom {

class Error: public std::exception {
public:
	~Error();
	Error(Error &other) = delete;
	std::string_view file() const noexcept;
	uint64_t line() const noexcept;
	std::string_view message() const noexcept;
	inline const Error *next() const noexcept { return m_next.get(); }
	std::string_view to_string() noexcept;
	/// You should only call this on the first error in an error list.
	/// (This can't be enforced with constness because it needs to
	/// override `std::exception::what`.)
	virtual const char *what() const noexcept override;
private:
	friend class Configuration;
	friend class Parser;
	Error() = delete;
	Error(void *C_error);
	Error(const void *C_error);
	void *C;
	bool m_is_original;
	std::unique_ptr<const Error> m_next;
};
std::ostream &operator<<(std::ostream &, Error &);

class Allocator {
public:
	inline virtual ~Allocator() {};
	virtual void *calloc(size_t, size_t) = 0;
	virtual void *realloc(void *, size_t) = 0;
	virtual void free(void *) = 0;
};

class Settings {
public:
	inline Settings() {};
	/// Set allocator.
	inline void set_allocator(std::shared_ptr<Allocator> allocator) {
		m_allocator = allocator;
	}
	void set_error_language(std::string_view lang);
private:
	void check_version() const;
	void to_C(void *C) const;
	friend class Configuration;
	char m_error_lang[16] = {};
	std::shared_ptr<Allocator> m_allocator;
	// to allow for future extensions without breaking backwards compatibility
	const uint32_t version = 1;
};

class Reader {
public:
	virtual size_t read(char *buf, size_t count) = 0;
};

/// An item in a configuration
///
/// This is an abstract class so that items can be given
/// more members in the future.
class Item {
public:
	inline virtual ~Item() {};
	virtual std::string_view key() const noexcept = 0;
	virtual std::string_view value() const noexcept = 0;
	virtual std::string_view file() const noexcept = 0;
	virtual uint64_t line() const noexcept = 0;
};

class Location {
public:
	inline std::string_view file() const { return m_file; }
	inline uint64_t line() const { return m_line; }
private:
	inline Location(std::string file, uint64_t line):
		m_file(file), m_line(line) {}
	friend class Configuration;
	std::string m_file;
	uint64_t m_line;
	void *_reserved[4] = {};
};
std::ostream &operator<<(std::ostream &, const Location &);

class Configuration {
public:
	Configuration();
	Configuration &operator=(const Configuration &other);
	inline Configuration(const Configuration &other) { *this = other; };
	Configuration(std::string_view filename, Reader &source, const Settings *settings = nullptr);
	Configuration(std::string_view filename, std::istream &stream, const Settings *settings = nullptr);
	Configuration(std::string_view path, const Settings *settings = nullptr);
	Configuration(std::string_view filename, std::string_view string, const Settings *settings = nullptr);
	~Configuration();
	std::optional<Location> location(std::string_view key) const;
	std::optional<std::string> get(std::string_view key) const;
	std::string get_or_default(std::string_view key, std::string_view dflt) const;
	std::optional<int64_t> get_int(std::string_view key) const;
	int64_t get_int_or_default(std::string_view key, int64_t dflt) const;
	std::optional<uint64_t> get_uint(std::string_view key) const;
	uint64_t get_uint_or_default(std::string_view key, uint64_t dflt) const;
	std::optional<double> get_float(std::string_view key) const;
	double get_float_or_default(std::string_view key, double dflt) const;
	std::optional<bool> get_bool(std::string_view key) const;
	bool get_bool_or_default(std::string_view key, bool dflt) const;
	std::optional<std::vector<std::string>> get_list(std::string_view key) const;
	std::vector<std::string> get_list_or_default(std::string_view key, const std::vector<std::string> &dflt) const;
	Configuration section(std::string_view name) const;
	std::vector<std::string> unread_keys() const;
	std::vector<std::string> keys() const;
	std::vector<std::shared_ptr<Item>> items() const;
	void merge(const Configuration &other);
private:
	void load(std::string_view filename, Reader &source, const Settings *settings);
	explicit Configuration(void *c): C(c) {}
	void *C;
};
std::ostream &operator<<(std::ostream &, const Configuration &);




} // namespace pom

#endif // POM_HPP_