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

Commit c6d1de5

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 c6d1de5

File tree

6 files changed

+340
-0
lines changed

6 files changed

+340
-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: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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+
return Checker(condition, makeLocation(filename, lineno), {});
27+
}
28+
29+
std::string makeLocation(const char* filename, uint64_t lineno) {
30+
std::stringstream ss;
31+
ss << filename << ':' << lineno;
32+
return ss.str();
33+
}
34+
35+
} // namespace detail
36+
} // 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: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
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+
auto v = std::vector<int>{1, 2, 3, 4};
53+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2 << ']'
54+
<< ": 1,2,3,4";
55+
ASSERT_THROW_WHAT((TC_CHECK(false) << v), 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__ + 2
71+
<< "] 1 not equal to 2: 2+2=5";
72+
ASSERT_THROW_WHAT(TC_CHECK_EQ(1, 2) << "2+2=5", expected.str());
73+
}
74+
}
75+
76+
TEST(CHECK, NE) {
77+
ASSERT_NO_THROW(TC_CHECK_NE(1, 2));
78+
ASSERT_NO_THROW(TC_CHECK_NE(std::string("aaa"), std::string("baa")));
79+
{
80+
std::stringstream expected;
81+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
82+
<< "] 1 equal to 1";
83+
ASSERT_THROW_WHAT(TC_CHECK_NE(1, 1), expected.str());
84+
}
85+
86+
{
87+
std::stringstream expected;
88+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
89+
<< "] 1 equal to 1: 2+2=5";
90+
ASSERT_THROW_WHAT(TC_CHECK_NE(1, 1) << "2+2=5", expected.str());
91+
}
92+
}
93+
94+
TEST(CHECK, LT) {
95+
ASSERT_NO_THROW(TC_CHECK_LT(1, 2));
96+
ASSERT_NO_THROW(TC_CHECK_LT(std::string("aaa"), std::string("baa")));
97+
{
98+
std::stringstream expected;
99+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
100+
<< "] 1 not less than 1";
101+
ASSERT_THROW_WHAT(TC_CHECK_LT(1, 1), expected.str());
102+
}
103+
104+
{
105+
std::stringstream expected;
106+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
107+
<< "] 4 not less than " << 1 << ": 4+3=8";
108+
ASSERT_THROW_WHAT(TC_CHECK_LT(4, 1) << "4+3=8", expected.str());
109+
}
110+
}
111+
112+
TEST(CHECK, GT) {
113+
ASSERT_NO_THROW(TC_CHECK_GT(2, 1));
114+
ASSERT_NO_THROW(TC_CHECK_GT(std::string("ca"), std::string("baa")));
115+
{
116+
std::stringstream expected;
117+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
118+
<< "] 1 not greater than " << 1;
119+
ASSERT_THROW_WHAT(TC_CHECK_GT(1, 1), expected.str());
120+
}
121+
122+
{
123+
std::stringstream expected;
124+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
125+
<< "] 2 not greater than 4: 3+3=7";
126+
ASSERT_THROW_WHAT(TC_CHECK_GT(2, 4) << "3+3=7", expected.str());
127+
}
128+
}
129+
130+
TEST(CHECK, LE) {
131+
ASSERT_NO_THROW(TC_CHECK_LE(1, 2));
132+
ASSERT_NO_THROW(TC_CHECK_LE(1, 1));
133+
ASSERT_NO_THROW(TC_CHECK_LE(std::string("aaa"), std::string("baa")));
134+
ASSERT_NO_THROW(TC_CHECK_LE(std::string("aa"), std::string("aa")));
135+
{
136+
std::stringstream expected;
137+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
138+
<< "] 2 not less than or equal to 1";
139+
ASSERT_THROW_WHAT(TC_CHECK_LE(2, 1), expected.str());
140+
}
141+
142+
{
143+
std::stringstream expected;
144+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
145+
<< "] 4 not less than or equal to 1: 4+5=10";
146+
ASSERT_THROW_WHAT(TC_CHECK_LE(4, 1) << "4+5=10", expected.str());
147+
}
148+
}
149+
150+
TEST(CHECK, GE) {
151+
ASSERT_NO_THROW(TC_CHECK_GE(2, 1));
152+
ASSERT_NO_THROW(TC_CHECK_GE(2, 2));
153+
ASSERT_NO_THROW(TC_CHECK_GE(std::string("ca"), std::string("baa")));
154+
ASSERT_NO_THROW(TC_CHECK_GE(std::string("ba"), std::string("ba")));
155+
{
156+
std::stringstream expected;
157+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
158+
<< "] 7 not greater than or equal to 9";
159+
ASSERT_THROW_WHAT(TC_CHECK_GE(7, 9), expected.str());
160+
}
161+
162+
{
163+
std::stringstream expected;
164+
expected << "Check failed [" << __FILE__ << ':' << __LINE__ + 2
165+
<< "] 2 not greater than or equal to 6: 9+3=13";
166+
ASSERT_THROW_WHAT(TC_CHECK_GE(2, 6) << "9+3=13", expected.str());
167+
}
168+
}
169+
170+
int main(int argc, char** argv) {
171+
::testing::InitGoogleTest(&argc, argv);
172+
::google::InitGoogleLogging(argv[0]);
173+
return RUN_ALL_TESTS();
174+
}

0 commit comments

Comments
 (0)