3030
3131namespace iceberg {
3232
33- #define BUILDER_RETURN_IF_ERROR (result ) \
33+ #define ICEBERG_BUILDER_RETURN_IF_ERROR (result ) \
3434 if (auto && result_name = result; !result_name) [[unlikely]] { \
3535 errors_.emplace_back (std::move (result_name.error ())); \
3636 return *this ; \
3737 }
3838
39- #define BUILDER_ASSIGN_OR_RETURN_IMPL (result_name, lhs, rexpr ) \
40- auto && result_name = (rexpr); \
41- BUILDER_RETURN_IF_ERROR (result_name) \
39+ #define ICEBERG_BUILDER_ASSIGN_OR_RETURN_IMPL (result_name, lhs, rexpr ) \
40+ auto && result_name = (rexpr); \
41+ ICEBERG_BUILDER_RETURN_IF_ERROR (result_name) \
4242 lhs = std::move(result_name.value());
4343
44- #define BUILDER_ASSIGN_OR_RETURN (lhs, rexpr ) \
45- BUILDER_ASSIGN_OR_RETURN_IMPL (ICEBERG_ASSIGN_OR_RAISE_NAME(result_, __COUNTER__), lhs, \
46- rexpr)
44+ #define ICEBERG_BUILDER_ASSIGN_OR_RETURN (lhs, rexpr ) \
45+ ICEBERG_BUILDER_ASSIGN_OR_RETURN_IMPL ( \
46+ ICEBERG_ASSIGN_OR_RAISE_NAME (result_, __COUNTER__), lhs, rexpr)
4747
48- // / \brief Base class for collecting validation errors in builder patterns
48+ #define ICEBERG_BUILDER_CHECK (expr, ...) \
49+ do { \
50+ if (!(expr)) [[unlikely]] { \
51+ return AddError (ErrorKind::kInvalidArgument , __VA_ARGS__); \
52+ } \
53+ } while (false )
54+
55+ // / \brief Base class for collecting errors in the builder pattern.
4956// /
50- // / This class provides error accumulation functionality for builders that
51- // / cannot throw exceptions . Builder methods can call AddError() to accumulate
52- // / validation errors, and CheckErrors() returns all errors at once .
57+ // / This class equips builders with error accumulation capabilities to make it easy
58+ // / for method chaining . Builder methods should call AddError() to accumulate errors
59+ // / and call CheckErrors() before completing the build process .
5360// /
5461// / Example usage:
5562// / \code
56- // / class MyBuilder : public ErrorCollectorBase {
63+ // / class MyBuilder : public ErrorCollector {
5764// / public:
5865// / MyBuilder& SetValue(int val) {
5966// / if (val < 0) {
@@ -87,10 +94,13 @@ class ICEBERG_EXPORT ErrorCollector {
8794 // /
8895 // / \param self Deduced reference to the derived class instance
8996 // / \param kind The kind of error
90- // / \param message The error message
97+ // / \param fmt The format string
98+ // / \param args The arguments to format the message
9199 // / \return Reference to the derived class for method chaining
92- auto & AddError (this auto & self, ErrorKind kind, std::string message) {
93- self.errors_ .emplace_back (kind, std::move (message));
100+ template <typename ... Args>
101+ auto & AddError (this auto & self, ErrorKind kind, const std::format_string<Args...> fmt,
102+ Args&&... args) {
103+ self.errors_ .emplace_back (kind, std::format (fmt, std::forward<Args>(args)...));
94104 return self;
95105 }
96106
@@ -107,15 +117,30 @@ class ICEBERG_EXPORT ErrorCollector {
107117 return self;
108118 }
109119
120+ // / \brief Add an unexpected result's error and return reference to derived class
121+ // /
122+ // / Useful for cases like below:
123+ // / \code
124+ // / return AddError(InvalidArgument("Invalid value: {}", value));
125+ // / \endcode
126+ // /
127+ // / \param self Deduced reference to the derived class instance
128+ // / \param err The unexpected result containing the error to add
129+ // / \return Reference to the derived class for method chaining
130+ auto & AddError (this auto & self, std::unexpected<Error> err) {
131+ self.errors_ .push_back (std::move (err.error ()));
132+ return self;
133+ }
134+
110135 // / \brief Check if any errors have been collected
111136 // /
112137 // / \return true if there are accumulated errors
113- [[nodiscard]] bool HasErrors () const { return !errors_.empty (); }
138+ [[nodiscard]] bool has_errors () const { return !errors_.empty (); }
114139
115140 // / \brief Get the number of errors collected
116141 // /
117142 // / \return The count of accumulated errors
118- [[nodiscard]] size_t ErrorCount () const { return errors_.size (); }
143+ [[nodiscard]] size_t error_count () const { return errors_.size (); }
119144
120145 // / \brief Check for accumulated errors and return them if any exist
121146 // /
@@ -143,9 +168,7 @@ class ICEBERG_EXPORT ErrorCollector {
143168 void ClearErrors () { errors_.clear (); }
144169
145170 // / \brief Get read-only access to all collected errors
146- // /
147- // / \return A const reference to the vector of errors
148- [[nodiscard]] const std::vector<Error>& Errors () const { return errors_; }
171+ [[nodiscard]] const std::vector<Error>& errors () const { return errors_; }
149172
150173 protected:
151174 std::vector<Error> errors_;
0 commit comments