xref: /aosp_15_r20/external/stg/error.h (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- mode: C++ -*-
3 //
4 // Copyright 2021-2024 Google LLC
5 //
6 // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7 // "License"); you may not use this file except in compliance with the
8 // License.  You may obtain a copy of the License at
9 //
10 //     https://llvm.org/LICENSE.txt
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 //
18 // Author: Giuliano Procida
19 
20 #ifndef STG_ERROR_H_
21 #define STG_ERROR_H_
22 
23 #include <exception>
24 #include <iostream>
25 #include <optional>
26 #include <ostream>
27 #include <sstream>
28 #include <string>
29 #include <system_error>
30 
31 namespace stg {
32 
33 class Exception : public std::exception {
34  public:
Exception(const std::string & message)35   explicit Exception(const std::string& message) {
36     Add(message);
37   }
38 
what()39   const char* what() const noexcept(true) final {
40     return message_.c_str();
41   }
42 
Add(const std::string & message)43   void Add(const std::string& message) {
44     (message_ += message) += '\n';
45   }
46 
47  private:
48   std::string message_;
49 };
50 
51 // Coded to give compilers a chance of making `Check(ok) << foo;` as efficient
52 // as `if (!ok) { Die() << foo; }`.
53 class Check {
54  public:
55   // These functions are all small and inlinable.
Check(bool ok)56   explicit Check(bool ok)
57       : os_(ok ? std::optional<std::ostringstream>()
58                : std::make_optional<std::ostringstream>()) {}
noexcept(false)59   ~Check() noexcept(false) {
60     if (os_) {
61       Throw(*os_);
62     }
63   }
64 
65   template <typename T>
66   Check& operator<<(const T& t) {
67     if (os_) {
68       *os_ << t;
69     }
70     return *this;
71   }
72 
73  private:
74   std::optional<std::ostringstream> os_;
75 
76   // This helper is too large to inline.
Throw(const std::ostringstream & os)77   [[noreturn]] static void Throw(const std::ostringstream& os) {
78     throw Exception(os.str());
79   }
80 };
81 
82 class Die {
83  public:
~Die()84   [[noreturn]] ~Die() noexcept(false) {
85     throw Exception(os_.str());
86   }
87 
88   template <typename T>
89   Die& operator<<(const T& t) {
90     os_ << t;
91     return *this;
92   }
93 
94  private:
95   std::ostringstream os_;
96 };
97 
98 class Warn {
99  public:
~Warn()100   ~Warn() {
101     std::cerr << "warning: " << os_.str() << '\n';
102   }
103 
104   template <typename T>
105   Warn& operator<<(const T& t) {
106     os_ << t;
107     return *this;
108   }
109 
110  private:
111   std::ostringstream os_;
112 };
113 
114 struct Error {
ErrorError115   explicit Error(int number) : number(number) {}
116   int number;
117 };
118 
119 inline std::ostream& operator<<(std::ostream& os, Error error) {
120   return os << std::system_error(error.number, std::generic_category()).what();
121 }
122 
123 }  // namespace stg
124 
125 #endif  // STG_ERROR_H_
126