Skip to content
This repository was archived by the owner on Apr 28, 2023. It is now read-only.

Commit 72f22d3

Browse files
author
Theodoros Theodoridis
committed
Implement TC_CHECK(_*) macros
The glog CHECK macros terminate on failure. Instead of termination the TC_CHECK macros throw exceptions.
1 parent 9fb6a37 commit 72f22d3

File tree

6 files changed

+346
-0
lines changed

6 files changed

+346
-0
lines changed

tc/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_library(
1010
SHARED
1111

1212
flags.cc
13+
check.cc
1314
mapping_options.cc
1415
mapping_options_cpp_printer.cc
1516
islpp.cc

tc/core/check.cc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include "tc/core/check.h"
2+
namespace tc {
3+
namespace detail {
4+
5+
Checker::Checker(bool condition, std::string location, std::string baseErrorMsg)
6+
: condition_(condition), location_(location), baseErrorMsg_(baseErrorMsg){};
7+
8+
Checker::~Checker() noexcept(false) {
9+
if (condition_) {
10+
return;
11+
}
12+
std::stringstream ss;
13+
ss << "Check failed [" << location_ << ']';
14+
15+
if (not baseErrorMsg_.empty()) {
16+
ss << ' ' << baseErrorMsg_;
17+
}
18+
19+
if (not additionalMsg_.empty()) {
20+
ss << ": " << additionalMsg_;
21+
}
22+
throw std::runtime_error(ss.str());
23+
}
24+
25+
Checker tc_check(bool condition, const char* filename, uint64_t lineno) {
26+
if (condition) {
27+
return Checker(condition, {}, {});
28+
}
29+
return Checker(condition, makeLocation(filename, lineno), {});
30+
}
31+
32+
std::string makeLocation(const char* filename, uint64_t lineno) {
33+
std::stringstream ss;
34+
ss << filename << ':' << lineno;
35+
return ss.str();
36+
}
37+
38+
} // namespace detail
39+
} // namespace tc

tc/core/check.h

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
#include <iosfwd>
5+
#include <sstream>
6+
#include <string>
7+
8+
#include "tc/core/utils/type_traits.h"
9+
10+
#define TC_CHECK(condition) \
11+
tc::detail::tc_check(static_cast<bool>(condition), __FILE__, __LINE__)
12+
#define TC_CHECK_EQ(x, y) tc::detail::tc_check_eq(x, y, __FILE__, __LINE__)
13+
#define TC_CHECK_NE(x, y) tc::detail::tc_check_ne(x, y, __FILE__, __LINE__)
14+
#define TC_CHECK_LT(x, y) tc::detail::tc_check_lt(x, y, __FILE__, __LINE__)
15+
#define TC_CHECK_GT(x, y) tc::detail::tc_check_gt(x, y, __FILE__, __LINE__)
16+
#define TC_CHECK_GE(x, y) tc::detail::tc_check_ge(x, y, __FILE__, __LINE__)
17+
#define TC_CHECK_LE(x, y) tc::detail::tc_check_le(x, y, __FILE__, __LINE__)
18+
19+
namespace tc {
20+
21+
namespace detail {
22+
class Checker {
23+
public:
24+
Checker(bool condition, std::string location, std::string baseErrorMsg);
25+
~Checker() noexcept(false);
26+
27+
template <typename T>
28+
typename std::enable_if<!tc::is_std_container<T>::value, Checker&>::type
29+
operator<<(const T& msg) {
30+
std::stringstream ss;
31+
ss << additionalMsg_ << msg;
32+
additionalMsg_ = ss.str();
33+
return *this;
34+
}
35+
36+
template <typename C>
37+
typename std::enable_if<tc::is_std_container<C>::value, Checker&>::type
38+
operator<<(const C& msg) {
39+
std::stringstream ss;
40+
ss << additionalMsg_;
41+
for (const auto& x : msg) {
42+
ss << x << ',';
43+
}
44+
additionalMsg_ = ss.str();
45+
if (msg.begin() != msg.end()) {
46+
additionalMsg_.pop_back();
47+
}
48+
return *this;
49+
}
50+
51+
private:
52+
bool condition_;
53+
std::string location_;
54+
std::string baseErrorMsg_;
55+
std::string additionalMsg_;
56+
}; // namespace detail
57+
58+
std::string makeLocation(const char* filename, uint64_t lineno);
59+
60+
Checker tc_check(bool condition, const char* filename, uint64_t lineno);
61+
62+
template <typename X, typename Y>
63+
Checker
64+
tc_check_eq(const X& x, const Y& y, const char* filename, uint64_t lineno) {
65+
std::stringstream ss;
66+
ss << x << " not equal to " << y;
67+
return Checker(x == y, makeLocation(filename, lineno), ss.str());
68+
}
69+
70+
template <typename X, typename Y>
71+
Checker
72+
tc_check_ne(const X& x, const Y& y, const char* filename, uint64_t lineno) {
73+
std::stringstream ss;
74+
ss << x << " equal to " << y;
75+
return Checker(x != y, makeLocation(filename, lineno), ss.str());
76+
}
77+
78+
template <typename X, typename Y>
79+
Checker
80+
tc_check_lt(const X& x, const Y& y, const char* filename, uint64_t lineno) {
81+
std::stringstream ss;
82+
ss << x << " not less than " << y;
83+
return Checker(x < y, makeLocation(filename, lineno), ss.str());
84+
}
85+
86+
template <typename X, typename Y>
87+
Checker
88+
tc_check_gt(const X& x, const Y& y, const char* filename, uint64_t lineno) {
89+
std::stringstream ss;
90+
ss << x << " not greater than " << y;
91+
return Checker(x > y, makeLocation(filename, lineno), ss.str());
92+
}
93+
94+
template <typename X, typename Y>
95+
Checker
96+
tc_check_le(const X& x, const Y& y, const char* filename, uint64_t lineno) {
97+
std::stringstream ss;
98+
ss << x << " not less than or equal to " << y;
99+
return Checker(x <= y, makeLocation(filename, lineno), ss.str());
100+
}
101+
102+
template <typename X, typename Y>
103+
Checker
104+
tc_check_ge(const X& x, const Y& y, const char* filename, uint64_t lineno) {
105+
std::stringstream ss;
106+
ss << x << " not greater than or equal to " << y;
107+
return Checker(x >= y, makeLocation(filename, lineno), ss.str());
108+
}
109+
110+
} // namespace detail
111+
} // namespace tc

tc/core/utils/type_traits.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <type_traits>
2+
3+
namespace tc {
4+
template <class...>
5+
using void_t = void;
6+
7+
template <typename T, typename = void>
8+
struct is_std_container : std::false_type {};
9+
10+
template <typename T>
11+
struct is_std_container<
12+
T,
13+
void_t<
14+
decltype(std::declval<T&>().begin()),
15+
decltype(std::declval<T&>().end()),
16+
typename T::value_type>> : std::true_type {};
17+
} // namespace tc

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ set(CORE_TEST_FILES
2929
test_core
3030
test_inference
3131
test_tc2halide
32+
test_check
3233
)
3334

3435
foreach(i ${CORE_TEST_FILES})

test/test_check.cc

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/**
2+
* Copyright (c) 2018-present, Facebook, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <sstream>
18+
#include <vector>
19+
20+
#include <glog/logging.h>
21+
#include <gtest/gtest.h>
22+
23+
#include "tc/core/check.h"
24+
25+
// XXX:gtest doesn't define a macro that inspects the contents of the exception
26+
#define ASSERT_THROW_WHAT(x, y) \
27+
try { \
28+
(x); \
29+
ASSERT_TRUE(false); \
30+
} catch (std::runtime_error & e) { \
31+
ASSERT_EQ(y, e.what()); \
32+
}
33+
34+
TEST(CHECK, Plain) {
35+
ASSERT_NO_THROW(TC_CHECK(true));
36+
{
37+
std::stringstream expected;
38+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 1 << ']';
39+
ASSERT_THROW_WHAT(TC_CHECK(false), expected.str());
40+
}
41+
42+
{
43+
std::stringstream expected;
44+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2 << ']'
45+
<< ": 1+1=3";
46+
ASSERT_THROW_WHAT(TC_CHECK(false) << "1+1=3", expected.str());
47+
}
48+
}
49+
50+
TEST(CHECK, Vector) {
51+
std::stringstream expected;
52+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 3 << ']'
53+
<< ": 1,2,3,4";
54+
ASSERT_THROW_WHAT(
55+
(TC_CHECK(false) << std::vector<int>{1, 2, 3, 4}), expected.str());
56+
}
57+
58+
TEST(CHECK, EQ) {
59+
ASSERT_NO_THROW(TC_CHECK_EQ(1, 1));
60+
ASSERT_NO_THROW(TC_CHECK_EQ(std::string("aaa"), std::string("aaa")));
61+
{
62+
std::stringstream expected;
63+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2 << "] "
64+
<< "1 not equal to 2";
65+
ASSERT_THROW_WHAT(TC_CHECK_EQ(1, 2), expected.str());
66+
}
67+
68+
{
69+
std::stringstream expected;
70+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 5
71+
<< "] 1 not equal to 2: 2+2=5";
72+
ASSERT_THROW_WHAT(
73+
TC_CHECK_EQ(1, 2) << "2+2"
74+
<< "=5",
75+
expected.str());
76+
}
77+
}
78+
79+
TEST(CHECK, NE) {
80+
ASSERT_NO_THROW(TC_CHECK_NE(1, 2));
81+
ASSERT_NO_THROW(TC_CHECK_NE(std::string("aaa"), std::string("baa")));
82+
{
83+
std::stringstream expected;
84+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
85+
<< "] 1 equal to 1";
86+
ASSERT_THROW_WHAT(TC_CHECK_NE(1, 1), expected.str());
87+
}
88+
89+
{
90+
std::stringstream expected;
91+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
92+
<< "] 1 equal to 1: 2+2=5";
93+
ASSERT_THROW_WHAT(TC_CHECK_NE(1, 1) << "2+2=5", expected.str());
94+
}
95+
}
96+
97+
TEST(CHECK, LT) {
98+
ASSERT_NO_THROW(TC_CHECK_LT(1, 2));
99+
ASSERT_NO_THROW(TC_CHECK_LT(std::string("aaa"), std::string("baa")));
100+
{
101+
std::stringstream expected;
102+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
103+
<< "] 1 not less than " << 1;
104+
ASSERT_THROW_WHAT(TC_CHECK_LT(1, 1), expected.str());
105+
}
106+
107+
{
108+
std::stringstream expected;
109+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
110+
<< "] 4 not less than " << 1 << ": 4+3=8";
111+
ASSERT_THROW_WHAT(TC_CHECK_LT(4, 1) << "4+3=8", expected.str());
112+
}
113+
}
114+
115+
TEST(CHECK, GT) {
116+
ASSERT_NO_THROW(TC_CHECK_GT(2, 1));
117+
ASSERT_NO_THROW(TC_CHECK_GT(std::string("ca"), std::string("baa")));
118+
{
119+
std::stringstream expected;
120+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
121+
<< "] 1 not greater than " << 1;
122+
ASSERT_THROW_WHAT(TC_CHECK_GT(1, 1), expected.str());
123+
}
124+
125+
{
126+
std::stringstream expected;
127+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
128+
<< "] 2 not greater than 4: 3+3=7";
129+
ASSERT_THROW_WHAT(TC_CHECK_GT(2, 4) << "3+3=7", expected.str());
130+
}
131+
}
132+
133+
TEST(CHECK, LE) {
134+
ASSERT_NO_THROW(TC_CHECK_LE(1, 2));
135+
ASSERT_NO_THROW(TC_CHECK_LE(1, 1));
136+
ASSERT_NO_THROW(TC_CHECK_LE(std::string("aaa"), std::string("baa")));
137+
ASSERT_NO_THROW(TC_CHECK_LE(std::string("aa"), std::string("aa")));
138+
{
139+
std::stringstream expected;
140+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
141+
<< "] 2 not less than or equal to 1";
142+
ASSERT_THROW_WHAT(TC_CHECK_LE(2, 1), expected.str());
143+
}
144+
145+
{
146+
std::stringstream expected;
147+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
148+
<< "] 4 not less than or equal to 1: 4+5=10";
149+
ASSERT_THROW_WHAT(TC_CHECK_LE(4, 1) << "4+5=10", expected.str());
150+
}
151+
}
152+
153+
TEST(CHECK, GE) {
154+
ASSERT_NO_THROW(TC_CHECK_GE(2, 1));
155+
ASSERT_NO_THROW(TC_CHECK_GE(2, 2));
156+
ASSERT_NO_THROW(TC_CHECK_GE(std::string("ca"), std::string("baa")));
157+
ASSERT_NO_THROW(TC_CHECK_GE(std::string("ba"), std::string("ba")));
158+
{
159+
std::stringstream expected;
160+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
161+
<< "] 7 not greater than or equal to 9";
162+
ASSERT_THROW_WHAT(TC_CHECK_GE(7, 9), expected.str());
163+
}
164+
165+
{
166+
std::stringstream expected;
167+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
168+
<< "] 2 not greater than or equal to 6: 9+3=13";
169+
ASSERT_THROW_WHAT(TC_CHECK_GE(2, 6) << "9+3=13", expected.str());
170+
}
171+
}
172+
173+
int main(int argc, char** argv) {
174+
::testing::InitGoogleTest(&argc, argv);
175+
::google::InitGoogleLogging(argv[0]);
176+
return RUN_ALL_TESTS();
177+
}

0 commit comments

Comments
 (0)