diff --git a/.gitignore b/.gitignore index e899e11..dbfc4cf 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ *.asm *.o *.elf +build compile_commands.json diff --git a/Makefile b/Makefile index 0ea4232..9263e8f 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,18 @@ build: $(SUBDIRS) $(MAKE) -j$(nproc) -C $$dir; \ done +test: $(SUBDIRS) build + @for dir in $(SUBDIRS); do \ + $(MAKE) -j$(nproc) test -C $$dir; \ + done + clean: @for dir in $(SUBDIRS); do \ make -C $$dir clean; \ done -.PHONY: build clean +format: + find . -type f \( -name "*.cpp" -o -name "*.h" -o -name "*.c" \) -exec clang-format -i {} \; + + +.PHONY: build clean test format diff --git a/common/iassert.h b/common/iassert.h index 841a806..3e60e05 100644 --- a/common/iassert.h +++ b/common/iassert.h @@ -8,3 +8,24 @@ assert(cond); \ } \ } while (0) + +#define ASSERT_EQ(expected, actual) \ + do { \ + if ((expected) != (actual)) { \ + std::cerr << "Assertion failed: (" #expected " == " #actual ") " \ + << "Expected: " << (expected) \ + << ", Actual: " << (actual) << "\n"; \ + assert((expected) == (actual)); \ + } \ + } while (0) + +#define ASSERT_EQMSG(expected, actual, msg) \ + do { \ + if ((expected) != (actual)) { \ + std::cerr << "Assertion failed: " << msg << "\n" \ + << "(" #expected " == " #actual ") " \ + << "Expected: " << (expected) \ + << ", Actual: " << (actual) << "\n"; \ + assert((expected) == (actual)); \ + } \ + } while (0) diff --git a/config.mk b/config.mk index 70b49ee..4aef6e8 100644 --- a/config.mk +++ b/config.mk @@ -4,12 +4,22 @@ MAKEFLAGS += --no-print-directory .PRECIOUS: %.o .PRECIOUS: %.asm +TARGET ?= main.elf +SRCS ?= $(wildcard *.cc) +HDRS ?= $(wildcard *.h) + OBJS = $(SRCS:.cc=.o) ASMS = $(SRCS:.cc=.asm) all: $(TARGET) $(ASMS) $(TARGET): $(OBJS) +test: $(TARGET) + ./$(TARGET) + +check: $(SRCS) $(HDRS) + cppcheck --language=c++ $^ + asm: $(ASMS) %.o: %.cc @@ -27,4 +37,4 @@ asm: $(ASMS) clean: rm -f *.elf *.asm *.o -.PHONY: clean all asm +.PHONY: clean all asm check test diff --git a/demos/comma.cpp b/demos/comma.cpp new file mode 100644 index 0000000..4ad62c8 --- /dev/null +++ b/demos/comma.cpp @@ -0,0 +1,17 @@ +#include +using std::cin; +using std::cout; +using std::endl; + +int main() { + std::string s; + + while (cin >> s, s.length() > 5) { + cout << s << " is longer than 5\n"; + } + cout << s << " is too short\n"; + + for (int i = 0, j = 0; i != 5; ++i, ++j) { + cout << i << ", " << j << endl; + } +} diff --git a/demos/file_io_example.cpp b/demos/file_io_example.cpp new file mode 100644 index 0000000..5399738 --- /dev/null +++ b/demos/file_io_example.cpp @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +void print_bytes(std::string infile) { + std::ifstream in{infile}; + + int c; + while ((c = in.get()) != EOF) { + std::cout << "read: " << std::setw(3) << c << " [" << char(c) << "]" + << std::endl; + } +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " filename" << std::endl; + return 1; + } + + print_bytes(argv[1]); + return 0; +} diff --git a/demos/map_and_set.cpp b/demos/map_and_set.cpp new file mode 100644 index 0000000..c1377df --- /dev/null +++ b/demos/map_and_set.cpp @@ -0,0 +1,123 @@ +#include +using std::cin; +using std::cout; +using std::endl; +#include +#include + +void test_map() { + std::map msi; + + msi.insert(std::make_pair("Kalle", 1)); + msi.emplace("Lisa", 2); + msi["Kim"] = 3; + + for (const auto &a : msi) { + cout << a.first << " : " << a.second << endl; + } + + cout << "Kim --> " << msi.at("Kim") << endl; + cout << "Lisa --> " << msi["Lisa"] << endl; + cout << "Hans --> " << msi["Hans"] + << endl; // [] default-konstruerar ett värde + // för nycklar som inte finns + try { + cout << "Nisse --> " << msi.at("Nisse") << endl; + } catch (std::out_of_range &e) { + cout << "Nisse not found: " << e.what() << endl; + } + const auto &kim = msi.find("Kim"); + if (kim != msi.end()) { + cout << "Kim : " << kim->second << endl; + } else { + cout << "Kim not found\n"; + } + auto nisse = msi.find("Nisse"); + if (nisse != msi.end()) { + cout << "Nisse : " << nisse->second << endl; + } else { + cout << "Nisse not found\n"; + } +} + +void test_set() { + std::set ints{1, 3, 7}; + + ints.insert(5); + + for (auto x : ints) { + cout << x << " "; + } + cout << endl; + + auto has_one = ints.find(1); + + if (has_one != ints.end()) { + cout << "one is in the set\n"; + } else { + cout << "one is not in the set\n"; + } + + if (ints.count(1)) { + cout << "one is in the set\n"; + } else { + cout << "one is not in the set\n"; + } + + auto has_two = ints.find(2); + + if (has_two != ints.end()) { + cout << "two is in the set\n"; + } else { + cout << "two is not in the set\n"; + } + + if (ints.count(2)) { + cout << "two is in the set\n"; + } else { + cout << "two is not in the set\n"; + } + + auto has_five = ints.find(5); + + if (has_five != ints.end()) { + cout << "five is in the set\n"; + } else { + cout << "five is not in the set\n"; + } + + ints.erase(5); + + auto has_five_now = ints.find(5); + + if (has_five_now != ints.end()) { + cout << "five is in the set\n"; + } else { + cout << "five is not in the set\n"; + } +} + +void test_set_bounds() { + std::set ints{9, 1, 3, 7, 5}; + + auto lb3 = ints.lower_bound(3); + cout << "lb3: " << *lb3 << endl; + auto ub3 = ints.upper_bound(3); + cout << "ub3: " << *ub3 << endl; + auto lb4 = ints.lower_bound(4); + cout << "lb4: " << *lb4 << endl; + auto ub4 = ints.upper_bound(4); + cout << "ub4: " << *ub4 << endl; + auto er = ints.equal_range(7); + if (er.first == er.second) { + cout << "er.first == er.second"; + } + cout << ", er.first: " << *er.first << ", er.second: " << *er.second + << endl; +} + +int main() { + test_map(); + test_set(); + test_set_bounds(); +} diff --git a/demos/print_seq.h b/demos/print_seq.h new file mode 100644 index 0000000..c26ad6f --- /dev/null +++ b/demos/print_seq.h @@ -0,0 +1,14 @@ +#ifndef PRINT_SEQ_H +#define PRINT_SEQ_H + +#include + +template void print_seq(const C &c) { + using std::cout; + using std::endl; + + cout << "[length: " << c.size() << "] "; + for (const auto &x : c) std::cout << x << " "; + cout << endl; +} +#endif diff --git a/demos/typecast_int_float.cpp b/demos/typecast_int_float.cpp new file mode 100644 index 0000000..7de2f84 --- /dev/null +++ b/demos/typecast_int_float.cpp @@ -0,0 +1,15 @@ +#include + +int main() { + int a{1234}; + float f{1234.0}; + + std::cout << "sizeof(int): " << sizeof(int) + << ", sizeof(float): " << sizeof(float) << std::endl; + + std::cout << "static_cast: " << static_cast(a) << " " + << static_cast(f) << std::endl; + + std::cout << "reinterpret_cast: " << *reinterpret_cast(&a) << " " + << *reinterpret_cast(&f) << std::endl; +} diff --git a/takewhile/Makefile b/takewhile/Makefile index 367bb06..24fbd75 100644 --- a/takewhile/Makefile +++ b/takewhile/Makefile @@ -1,6 +1,4 @@ TARGET = takewhile.elf SRCS = takewhile.cc -all: $(TARGET) - include ../config.mk diff --git a/vector/main.cc b/vector/main.cc index 45717a2..7f63eb1 100644 --- a/vector/main.cc +++ b/vector/main.cc @@ -9,21 +9,26 @@ int main() { Vec v; v.push_back(10); - ASSERT_MSG(v[0] == 10, "10 should be present at index 0"); + int a = v[0]; + ASSERT_EQMSG(10, a, "10 should be present at index 0"); Vec v2{1, 2, 3}; - ASSERT_MSG(v2.size() == 3, "Size should be three"); + ASSERT_EQ(3, v2.size()); + ASSERT_EQMSG(v2.size(), 3, "Size should be three"); v2.pop_back(); + ASSERT_EQ(2, v2.size()); ASSERT_MSG(v2.size() == 2, "Size should be three"); // Triggers a reallocation (memcpy) Vec v3{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; ASSERT_MSG(v3[11] == 12, "Index 11 should hold 12"); - // ASSERT_MSG(v3[5] == 6, "Index 5 should hold 6"); // ??? - ASSERT_MSG(v3.size() == 12, "Size should be 12"); - ASSERT_MSG(v3.capacity() == 20, "Capacity should be 20"); + ASSERT_MSG(v3[5] == 6, "Index 5 should hold 6"); // ??? + ASSERT_EQ(12, v3.size()); + ASSERT_EQ(24, v3.capacity()); - for (const auto &a : v3) { - std::cout << a << std::endl; - } + Vec v_sized(40); + v_sized.push_back(0); + ASSERT_MSG(v_sized[0] == 0, "Well"); + + return 0; } diff --git a/vector/vec.cc b/vector/vec.cc index 2df75a8..18ed597 100644 --- a/vector/vec.cc +++ b/vector/vec.cc @@ -3,13 +3,14 @@ #include #include -Vec::Vec() : cap(INITIAL_LEN), w_idx(0), arr(nullptr) { - std::cout << "Allocating vector" << std::endl; - arr = new T[INITIAL_LEN]; +Vec::Vec() : Vec(INITIAL_LEN) {} + +Vec::Vec(std::size_t size) : cap(size), w_idx(0), arr(new T[size]) { + std::cout << "Allocating vector of size " << size << std::endl; } -Vec::Vec(std::initializer_list il) : Vec() { - for (auto &a : il) push_back(a); +Vec::Vec(std::initializer_list il) : Vec(il.size()) { + for (auto &elem : il) push_back(std::move(elem)); } Vec::~Vec() { @@ -26,12 +27,18 @@ T &Vec::operator[](std::size_t idx) const noexcept { exit(1); } -void Vec::push_back(const T &value) noexcept { +void Vec::push_back(const T &value) { arr[w_idx++] = value; - if (w_idx == cap) { + if (w_idx == cap) + resize(cap * 2); +} + +void Vec::push_back(T &&value) { + arr[w_idx++] = std::move(value); + + if (w_idx == cap) resize(cap * 2); - } } std::size_t Vec::size() const { return w_idx; } @@ -39,9 +46,10 @@ std::size_t Vec::size() const { return w_idx; } std::size_t Vec::capacity() const noexcept { return cap; } void Vec::resize(std::size_t newsize) { - std::cout << "Reallocating" << std::endl; + std::cout << "Reallocating: " << cap << " to " << newsize << std::endl; + T *newarr = new T[newsize]; - std::memcpy(newarr, arr, w_idx); + std::move(arr, arr + w_idx, newarr); delete[] arr; arr = newarr; cap = newsize; diff --git a/vector/vec.h b/vector/vec.h index 5154bc7..fd5b060 100644 --- a/vector/vec.h +++ b/vector/vec.h @@ -13,6 +13,7 @@ class Vec { public: Vec(); + explicit Vec(std::size_t); Vec(std::initializer_list); Vec(const Vec &other); // Copy Vec(Vec &&other) noexcept; // Move @@ -25,7 +26,8 @@ class Vec { std::size_t size() const; std::size_t capacity() const noexcept; - void push_back(const T &value) noexcept; + void push_back(const T &value); // May except + void push_back(T &&value); void pop_back() noexcept; void clear() noexcept;