• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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