git remote remove origin && git remote add origin https://github.com/cs6771/comp6771.git
cc_library(
name = "factorial",
srcs = ["factorial.cpp"],
hdrs = ["factorial.h"],
)
cc_test(
name = "factorial_test",
srcs = ["factorial_test.cpp"],
deps = [
":factorial",
"//:catch",
],
)
Or in other words
SCENARIO("scenario") {
GIVEN("Some starting condition") {
// Initialise the variables
WHEN("My function is called") {
// Call my function
THEN("something should have happened") {
// Check that the thing happened as expected
}
}
}
}
// Feel free to remove the string if there's
// only one GIVEN in this scenario.
SCENARIO("vectors can be sized and resized") {
GIVEN("A vector with some items") {
std::vector<int> v(5);
REQUIRE(v.size() == 5);
REQUIRE(v.capacity() >= 5);
WHEN("the size is increased") {
v.resize(10);
THEN("the size and capacity change") {
REQUIRE(v.size() == 10);
REQUIRE(v.capacity() >= 10);
}
}
WHEN("the size is reduced") {
v.resize(0);
THEN("the size changes but not capacity") {
REQUIRE(v.size() == 0);
REQUIRE(v.capacity() >= 5);
}
}
}
}
const auto hasAbc = Catch::Matchers::Contains(
"aBC", Catch::CaseSensitive::No);
SCENARIO("Do that thing with the thing", "[Tags]") {
GIVEN("This stuff exists") {
// make stuff exist
AND_GIVEN("And some assumption") {
// Validate assumption
WHEN("I do this") {
// do this
THEN("it should do this") {
REQUIRE(itDoesThis());
AND_THEN("do that") {
REQUIRE(itDoesThat());
REQUIRE_THAT(
getResultOfThat(), hasAbc);
}
}
}
}
}
}
std::vector<int> nums;
int sum = 0;
for (int i = 0; i <= nums.size(); ++i) {
sum += i;
}
std::vector<int> nums;
int sum = 0;
for (auto it = nums.begin(); i != nums.end(); ++i) {
sum += *i;
}
std::vector<int> nums;
int sum = 0;
// Internally, this uses begin and end,
// but it abstracts it away.
for (const auto& i : nums) {
sum += i;
}
template <typename T>
T sum(iterable<T> cont) {
T total;
for (auto it = std::begin(cont); std::end(cont); ++i) {
total += *it;
}
return total
}
// What type of iterator is required here?
template <typename T, typename Container>
T sum(iterator_t<Container> first, iterator_t<Container> last) {
T total;
for (; first != last; ++first) {
total += *first;
}
return total
}
std::vector<int> v{1, 2, 3};
int sum = std::accumulate(v.begin(), v.end(), 0);
What if we want the product instead of the sum?
What if we want to only sum up the first half of the numbers?
// What is the type of std::multiplies<int>()
int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());
auto midpoint = v.begin() + (v.size() / 2);
// This looks a lot harder to read. Why might it be better?
auto midpoint = std::next(v.begin(), std::distance(v.begin(), v.end()) / 2);
int sum = std::accumulate(v.begin(), midpoint, 0);
// Lower bound does a binary search, and returns the first value >= the argument.
std::vector<int> sortedVec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::lower_bound(sortedVec.begin(), sortedVec.end(), 5);
std::list<int> sortedLinkedList{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::lower_bound(sortedLinkedList.begin(), sortedLinkedList.end(), 5);
Why doesn't the second one work?
char to_upper(char value) {
return std::toupper(static_cast<unsigned char>(value));
}
std::string s = "hello world";
// std::for_each modifies each element
std::for_each(s.begin(), s.end(), to_upper);
std::string upper;
// Algorithms like transform, which have output iterators,
// use the other iterator as an output.
std::transform(s.begin(), s.end(), upper.end(), to_upper);
Gives you an output iterator for a container that adds to the end of it
char to_upper(char value) {
return std::toupper(value);
}
std::string s = "hello world";
// std::for_each modifies each element
std::for_each(s.begin(), s.end(), toupper);
std::string upper;
// std::transform adds to third iterator.
std::transform(s.begin(), s.end(), std::back_inserter(upper), to_upper);
std::string s = "hello world";
// std::for_each modifies each element
std::for_each(s.begin(), s.end(), [] (char& value) { value = std::toupper(value); });
void AddN(std::vector<int>& v, int n) {
std::for_each(v.begin(), v.end(), [] (int& val) { val = val + n; });
}
// Works great.
void AddN(std::vector<int> vec, int n) {
std::for_each(vec.begin(), vec.end(),
[=] (int& item) { item += n; });
}
// Even worse. This compiles successfully.
std::map<std::string, int> m;
auto emplace = [=] (const auto& key, const auto& value) { m.emplace(key, value); };
emplace("hello", 5);
// Not so great. Fails to compile.
void PrintList(const std::vector<int>& nums,
std::ostream& os) {
auto printer = [=] (int value) { os << value << '\n'; };
std::for_each(nums.begin(), nums.end(), printer);
}
std::map<std::string, int> m;
auto emplace = [&] (
const auto& key,
const auto& value) {
m.emplace(key, value);
};
// What happens here?
emplace("hello", 5);
auto GetGenerator() {
int upto = 0;
return [&] () { return upto++; }
}
// What happens here?
auto fn = GetGenerator();
std::cout << fn() << fn() << '\n';
std::vector<int> vec{1, 2, 3};
int n = 10;
auto fn = [vec{std::move(vec)}, y=n + 1] () {
std::cout << vec.size() << '\n' << y;
};
// Should be 0
std::cout << vec.size() << '\n';
fn();