Streamline configuration.h
[ep-engine.git] / src / configuration_impl.h
1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2017 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17
18 /*
19  * Contains implementations relating to configuration.h that are not needed in
20  * most places Configuration is. This can be included in a far smaller number
21  * of places, reducing the overhead of including configuration.h.
22  */
23
24 #pragma once
25
26 #include "configuration.h"
27
28 #include <boost/variant.hpp>
29
30 #include <set>
31 #include <string>
32 #include <vector>
33
34 using value_variant_t =
35         boost::variant<size_t, ssize_t, float, bool, std::string>;
36
37 class requirements_unsatisfied : public std::logic_error {
38 public:
39     requirements_unsatisfied(const std::string& msg) : std::logic_error(msg) {
40     }
41 };
42
43 /** A configuration input validator that ensures a numeric (size_t)
44  * value falls between a specified upper and lower limit.
45  */
46 class SizeRangeValidator : public ValueChangedValidator {
47 public:
48     SizeRangeValidator() : lower(0), upper(0) {}
49
50     SizeRangeValidator *min(size_t v) {
51         lower = v;
52         return this;
53     }
54
55     SizeRangeValidator *max(size_t v) {
56         upper = v;
57         return this;
58     }
59
60     virtual void validateSize(const std::string& key, size_t value) {
61         if (value < lower || value > upper) {
62             std::string error = "Validation Error, " + key +
63                                 " takes values between " +
64                                 std::to_string(lower) + " and " +
65                                 std::to_string(upper) + " (Got: " +
66                                 std::to_string(value) + ")";
67             throw std::range_error(error);
68         }
69     }
70
71     virtual void validateSSize(const std::string& key, ssize_t value) {
72         ssize_t s_lower = static_cast<ssize_t> (lower);
73         ssize_t s_upper = static_cast<ssize_t> (upper);
74
75         if (value < s_lower || value > s_upper) {
76             std::string error = "Validation Error, " + key +
77                                 " takes values between " +
78                                 std::to_string(s_lower) + " and " +
79                                 std::to_string(s_upper) + " (Got: " +
80                                 std::to_string(value) + ")";
81             throw std::range_error(error);
82         }
83     }
84 private:
85     size_t lower;
86     size_t upper;
87 };
88
89 /**
90  * A configuration input validator that ensures a signed numeric (ssize_t)
91  * value falls between a specified upper and lower limit.
92  */
93 class SSizeRangeValidator : public ValueChangedValidator {
94 public:
95     SSizeRangeValidator() : lower(0), upper(0) {}
96
97     SSizeRangeValidator* min(size_t v) {
98         lower = v;
99         return this;
100     }
101
102     SSizeRangeValidator* max(size_t v) {
103         upper = v;
104         return this;
105     }
106
107     virtual void validateSSize(const std::string& key, ssize_t value) {
108         if (value < lower || value > upper) {
109             std::string error = "Validation Error, " + key +
110                                 " takes values between " +
111                                 std::to_string(lower) + " and " +
112                                 std::to_string(upper) + " (Got: " +
113                                 std::to_string(value) + ")";
114             throw std::range_error(error);
115         }
116     }
117 private:
118     ssize_t lower;
119     ssize_t upper;
120 };
121
122 /**
123  * A configuration input validator that ensures that a numeric (float)
124  * value falls between a specified upper and lower limit.
125  */
126 class FloatRangeValidator : public ValueChangedValidator {
127 public:
128     FloatRangeValidator() : lower(0), upper(0) {}
129
130     FloatRangeValidator *min(float v) {
131         lower = v;
132         return this;
133     }
134
135     FloatRangeValidator *max(float v) {
136         upper = v;
137         return this;
138     }
139
140     virtual void validateFloat(const std::string& key, float value) {
141         if (value < lower || value > upper) {
142             std::string error = "Validation Error, " + key +
143                                 " takes values between " +
144                                 std::to_string(lower) + " and " +
145                                 std::to_string(upper) + " (Got: " +
146                                 std::to_string(value) + ")";
147             throw std::range_error(error);
148         }
149     }
150 private:
151     float lower;
152     float upper;
153 };
154
155 /**
156  * A configuration input validator that ensures that a value is one
157  * from a predefined set of acceptable values.
158  */
159 class EnumValidator : public ValueChangedValidator {
160 public:
161     EnumValidator() {}
162
163     EnumValidator *add(const char *s) {
164         acceptable.insert(std::string(s));
165         return this;
166     }
167
168     virtual void validateString(const std::string& key, const char* value) {
169         if (acceptable.find(std::string(value)) == acceptable.end()) {
170             std::string error = "Validation Error, " + key +
171                                 " takes one of [";
172             for (const auto& it : acceptable) {
173                 error += it + ", ";
174             }
175             if (acceptable.size() > 0) {
176                 error.pop_back();
177                 error.pop_back();
178             }
179
180             error += "] (Got: " + std::string(value) + ")";
181             throw std::range_error(error);
182         }
183     }
184
185 private:
186     std::set<std::string> acceptable;
187 };
188
189 class Requirement {
190 public:
191     Requirement* add(const std::string& key, value_variant_t value) {
192         requirements.emplace_back(key, value);
193         return this;
194     }
195
196     std::vector<std::pair<std::string, value_variant_t>> requirements;
197 };