1 /*
2 * Copyright (c) 2022, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 3-Clause Clear License
5 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6 * License was not distributed with this source code in the LICENSE file, you
7 * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
8 * Alliance for Open Media Patent License 1.0 was not distributed with this
9 * source code in the PATENTS file, you can obtain it at
10 * www.aomedia.org/license/patent.
11 */
12 #ifndef COMMON_UTILS_VALIDATION_UTILS_H_
13 #define COMMON_UTILS_VALIDATION_UTILS_H_
14
15 #include <optional>
16 #include <utility>
17
18 #include "absl/container/flat_hash_set.h"
19 #include "absl/log/check.h"
20 #include "absl/log/log.h"
21 #include "absl/status/status.h"
22 #include "absl/strings/str_cat.h"
23 #include "absl/strings/string_view.h"
24
25 namespace iamf_tools {
26
27 /*!\brief Returns an error if the size arguments are not equivalent.
28 *
29 * Intended to be used in OBUs to ensure the reported and actual size of
30 * containers are equivalent.
31 *
32 * \param field_name Field name of the container to insert into the error
33 * message.
34 * \param container Container to check the size of.
35 * \param reported_size Size reported by associated fields (e.g. "*_size" fields
36 * in the OBU).
37 * \return `absl::OkStatus()` if the size arguments are equivalent.
38 * `absl::InvalidArgumentError()` otherwise.
39 */
40 template <typename Container, typename ReportedSize>
ValidateContainerSizeEqual(absl::string_view field_name,const Container & container,ReportedSize reported_size)41 absl::Status ValidateContainerSizeEqual(absl::string_view field_name,
42 const Container& container,
43 ReportedSize reported_size) {
44 const auto actual_size = container.size();
45 if (actual_size == reported_size) [[likely]] {
46 return absl::OkStatus();
47 }
48 return absl::InvalidArgumentError(absl::StrCat(
49 "Found inconsistency with `", field_name, ".size()`= ", actual_size,
50 ". Expected a value of ", reported_size, "."));
51 }
52
53 /*!\brief Returns `absl::OkStatus()` if the arguments are equal.
54 *
55 * \param lhs First value to compare.
56 * \param rhs Second value to compare.
57 * \param context Context to insert into the error message for debugging
58 * purposes.
59 * \return `absl::OkStatus()` if the arguments are equal
60 * `absl::InvalidArgumentError()` if the arguments are not equal.
61 */
62 template <typename T>
ValidateEqual(const T & lhs,const T & rhs,absl::string_view context)63 absl::Status ValidateEqual(const T& lhs, const T& rhs,
64 absl::string_view context) {
65 if (lhs == rhs) [[likely]] {
66 return absl::OkStatus();
67 }
68
69 return absl::InvalidArgumentError(
70 absl::StrCat("Invalid ", context, ". Expected ", lhs, " == ", rhs, "."));
71 }
72
73 /*!\brief Returns `absl::OkStatus()` if the arguments are not equal.
74 *
75 * \param lhs First value to compare.
76 * \param rhs Second value to compare.
77 * \param context Context to insert into the error message for debugging
78 * purposes.
79 * \return `absl::OkStatus()` if the arguments are not equal
80 * `absl::InvalidArgumentError()` if the arguments are equal.
81 */
82 template <typename T>
ValidateNotEqual(const T & lhs,const T & rhs,absl::string_view context)83 absl::Status ValidateNotEqual(const T& lhs, const T& rhs,
84 absl::string_view context) {
85 if (lhs != rhs) [[likely]] {
86 return absl::OkStatus();
87 }
88
89 return absl::InvalidArgumentError(
90 absl::StrCat("Invalid ", context, ". Expected ", lhs, " != ", rhs, "."));
91 }
92
93 /*!\brief Returns `absl::OkStatus()` if the argument has a value.
94 *
95 * \param argument Argument to check.
96 * \param context Context to insert into the error message for debugging
97 * purposes.
98 * \return `absl::OkStatus()` if the arguments has a value.
99 * `absl::InvalidArgumentError()` if the argument does not have a value.
100 */
101 template <typename T>
ValidateHasValue(const std::optional<T> & argument,absl::string_view context)102 absl::Status ValidateHasValue(const std::optional<T>& argument,
103 absl::string_view context) {
104 if (argument.has_value()) [[likely]] {
105 return absl::OkStatus();
106 }
107
108 return absl::InvalidArgumentError(
109 absl::StrCat("Invalid ", context, ". Expected to have a value."));
110 }
111
112 /*!\brief Returns `absl::OkStatus()` if the argument is not NULL.
113 *
114 * \param argument Argument to check.
115 * \param context Context to insert into the error message for debugging
116 * purposes.
117 * \return `absl::OkStatus()` if the arguments is not NULL.
118 * `absl::InvalidArgumentError()` otherwise.
119 */
120 template <typename T>
ValidateNotNull(const T & pointer,absl::string_view context)121 absl::Status ValidateNotNull(const T& pointer, absl::string_view context) {
122 if (pointer != nullptr) [[likely]] {
123 return absl::OkStatus();
124 }
125
126 return absl::InvalidArgumentError(
127 absl::StrCat("Invalid pointer: ", context, ". Expected to be not NULL"));
128 }
129
130 /*!\brief Validates that all values in the range [first, last) are unique.
131 *
132 * \param first Iterator to start from.
133 * \param last Iterator to stop before.
134 * \param context Context to insert into the error message for debugging
135 * purposes.
136 * \return `absl::OkStatus()` if no duplicates are found while iterating.
137 * `absl::InvalidArgumentError()` if duplicates are found.
138 */
139 template <class InputIt>
ValidateUnique(InputIt first,InputIt last,absl::string_view context)140 absl::Status ValidateUnique(InputIt first, InputIt last,
141 absl::string_view context) {
142 absl::flat_hash_set<typename InputIt::value_type> seen_values;
143
144 for (auto iter = first; iter != last; ++iter) {
145 if (const auto& [unused_iter, inserted] = seen_values.insert(*iter);
146 !inserted) {
147 return absl::InvalidArgumentError(
148 absl::StrCat(context, " must be unique. Found duplicate: ", *iter));
149 }
150 }
151 return absl::OkStatus();
152 }
153
154 /*!\brief Returns `absl::OkStatus()` if `value` is in the range [min, max].
155 *
156 * \param value Value to check.
157 * \param min Minimum allowed value.
158 * \param max Maximum allowed value.
159 * \param context Context to insert into the error message for debugging
160 * purposes.
161 * \return `absl::OkStatus()` if the argument is in the range [min, max].
162 * `absl::InvalidArgumentError()` if the argument is not in the range
163 * [min, max].
164 */
165 template <typename T>
ValidateInRange(const T & value,std::pair<const T &,const T &> min_max,absl::string_view context)166 absl::Status ValidateInRange(const T& value,
167 std::pair<const T&, const T&> min_max,
168 absl::string_view context) {
169 const auto& [min, max] = min_max;
170 if (min <= max && value <= max && value >= min) [[likely]] {
171 return absl::OkStatus();
172 }
173 if (min > max) {
174 return absl::InvalidArgumentError(absl::StrCat(
175 "Invalid range: [", min, ", ", max, "]. Expected min <= max."));
176 }
177 return absl::InvalidArgumentError(
178 absl::StrCat("Invalid ", context, ". Expected ", value, " in range [",
179 min, ", ", max, "]."));
180 }
181
182 /*!\brief Returns `absl::OkStatus()` if `value` (comparison) `reference` is true
183 *
184 * Useful for arbitrary comparisons, e.g.
185 * RETURN_IF_NOT_OK(Validate(my_value, std::greater_equal{}, 0, "my_value >="))
186 *
187 * \param value Value to check.
188 * \param comparison A comparator like std::less.
189 * \param reference The value to compare against.
190 * \param context Context to insert into the error message for debugging
191 * purposes. For best results, include the operator, e.g. "my_value >=".
192 * \return `absl::OkStatus()` if the comparison is true.
193 * `absl::InvalidArgumentError()` otherwise.
194 */
195 template <typename T, typename C>
Validate(const T & value,const C & comparison,const T & reference,absl::string_view context)196 absl::Status Validate(const T& value, const C& comparison, const T& reference,
197 absl::string_view context) {
198 if (comparison(value, reference)) [[likely]] {
199 return absl::OkStatus();
200 }
201 return absl::InvalidArgumentError(absl::StrCat(
202 "Invalid value: ", value, ". Require ", context, reference, "."));
203 }
204
205 } // namespace iamf_tools
206
207 #endif // COMMON_UTILS_VALIDATION_UTILS_H_
208