This commit is contained in:
Imbus 2025-01-10 08:15:31 +01:00
commit 5626d1eacb
24 changed files with 512 additions and 0 deletions

7
.clang-format Normal file
View file

@ -0,0 +1,7 @@
# Language: C
BasedOnStyle: LLVM
IndentWidth: 4 # Use 4 spaces for indentation
TabWidth: 4 # Tab width is also 4 spaces
UseTab: Never # Always use spaces instead of tabs
ColumnLimit: 80 # Wrap lines after 80 characters
AllowShortLoopsOnASingleLine: true

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
.cache
*.asm
*.o
*.elf
compile_commands.json

8
CMakeLists.txt Normal file
View file

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.16)
project(SuperProject)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(common)
add_subdirectory(vector)

15
Makefile Normal file
View file

@ -0,0 +1,15 @@
# SUBDIRS = dir1 dir2 dir3
SUBDIRS := $(shell find . -mindepth 1 -maxdepth 1 -type d -exec test -e "{}/Makefile" \; -print)
build: $(SUBDIRS)
@for dir in $(SUBDIRS); do \
$(MAKE) -j$(nproc) -C $$dir; \
done
clean:
@for dir in $(SUBDIRS); do \
make -C $$dir clean; \
done
.PHONY: build clean

8
common/CMakeLists.txt Normal file
View file

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.16)
project(Common)
add_library(common INTERFACE)
target_include_directories(common INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}
)

10
common/iassert.h Normal file
View file

@ -0,0 +1,10 @@
#include <cassert>
#include <iostream>
#define ASSERT_MSG(cond, msg) \
do { \
if (!(cond)) { \
std::cerr << "Assertion failed: " << msg << "\n"; \
assert(cond); \
} \
} while (0)

30
config.mk Normal file
View file

@ -0,0 +1,30 @@
CXXFLAGS ?= -Wall -Wextra -O2 -g0 -std=c++23 -I../common/
MAKEFLAGS += --no-print-directory
.PRECIOUS: %.o
.PRECIOUS: %.asm
OBJS = $(SRCS:.cc=.o)
ASMS = $(SRCS:.cc=.asm)
all: $(TARGET) $(ASMS)
$(TARGET): $(OBJS)
asm: $(ASMS)
%.o: %.cc
@echo CC $@
@g++ $(CXXFLAGS) -c $< -o $@
%.asm: %.o
@echo DEC $@
@objdump -d -M intel $< > $@
%.elf: %.o | %.asm
@echo CC/LD $@
@g++ $(CXXFLAGS) -o $@ $^
clean:
rm -f *.elf *.asm *.o
.PHONY: clean all asm

27
junk/1.5.cc Normal file
View file

@ -0,0 +1,27 @@
#include <iostream>
using std::cout;
struct A {
A() = default;
A(int x) { val = x; }
void print() { cout << "A(" << val << ")"; }
int val;
};
struct B {
// B(int x) { a = A(x); }
B(int x) : a(x) {}
void print() {
cout << "B(";
a.print();
cout << ")";
}
A a;
};
int main() {
B b(10);
b.print();
cout << "\n";
}

63
junk/1.cc Normal file
View file

@ -0,0 +1,63 @@
#include <iostream>
using std::cout;
// Rule of three:
// If a class requires a user-defined destructor, a user-defined copy
// constructor, or a user-defined copy assignment operator, it almost certainly
// requires all three.
//
// Rule of five:
// Because the presence of a user-defined (include = default or = delete
// declared) destructor, copy-constructor, or copy-assignment operator prevents
// implicit definition of the move constructor and the move assignment operator,
// any class for which move semantics are desirable, has to declare all five
// special member functions:
struct A {
A() = default;
/* Constructor */
A(const int &x) { val = x; }
/* Copy constructor */
A(A &other) { other.val = this->val; }
/* Move constructor */
A(A &&other) { other.val = this->val; }
/* Copy assignment operator */
A &operator=(const A &other) { return *this; }
~A() {}
void print() { cout << "A(" << val << ")"; }
int val;
};
struct B {
B(int x) { a = A(x); }
// B(int x) : a(x) {};
void print() {
cout << "B(";
a.print();
cout << ")";
}
A a;
};
int main() {
B b(10);
b.print();
cout << "\n";
}
struct K {
K() = default;
/* Constructor */
K(const int &x) { val = x; }
/* Copy constructor */
K(K &other) : K(other.val) {}
/* Move constructor */
K(K &&other) : K(other.val) {}
/* Copy assignment operator */
K &operator=(const K &other) { return *this; }
~K() {}
void print() { cout << "K(" << val << ")"; }
int val;
};

19
junk/2.cc Normal file
View file

@ -0,0 +1,19 @@
#include <cstdlib>
#include <iostream>
void consume_number(int *p) {
std::cout << "Consuming: " << *p << std::endl;
delete p;
}
void random_int(int &out) { out = rand(); }
void use2() {
int i;
random_int(i);
consume_number(&i);
}
int main(int argc, char *argv[]) {
use2();
}

45
junk/3.cc Normal file
View file

@ -0,0 +1,45 @@
#include <cstddef>
#include <iostream>
// In C we need a length in bytes to check for equality
void compareObject(void *a, void *b, size_t len) {
if (a == b)
std::cout << "Same address" << std::endl;
// Being explicit about pointer type allows pointer arithmetic
unsigned char *i1 = (unsigned char *)a;
unsigned char *i2 = (unsigned char *)b;
for (size_t i = 0; i < len; i++) {
if (i1[i] != i2[i]) {
std::cout << "Different value" << std::endl;
return;
}
}
std::cout << "Same value" << std::endl;
}
template <typename T> void cmp(T &a, T &b) {
if (&a == &b)
std::cout << "Same object" << std::endl;
if (a == b)
std::cout << "Same value" << std::endl;
else
std::cout << "Different value" << std::endl;
}
int main() {
int a = 10, b = 10, c = 12;
std::cout << "Checking template version" << std::endl;
cmp(a, b);
cmp(a, c);
std::cout << "Checking C version" << std::endl;
compareObject(&a, &b, sizeof(int));
compareObject(&a, &c, sizeof(int));
}

38
junk/4.cc Normal file
View file

@ -0,0 +1,38 @@
#include <iostream>
#include <vector>
#include <ranges>
template <typename InputIt, typename OutputIt, typename Pred>
std::pair<InputIt, OutputIt> copy_while(InputIt first, InputIt last,
OutputIt out, Pred p);
std::vector<int> take_while_sum_less_than(std::vector<int> &v, int n) {
std::vector<int> out;
int acc = 0;
while (true) {
if (v.back() + acc > n) {
int next = v.back();
out.push_back(n);
v.pop_back();
}
}
}
#if __cplusplus > 202002L
// #include <ranges>
// #include <numeric>
std::vector<int> take_while_sum_less_than(const std::vector<int> &v, int n) {
int sum = 0;
auto result = v | std::ranges::views::take_while([&sum, n](int x) {
if (sum + x < n) {
sum += x;
return true;
}
return false;
});
return std::vector<int>(result.begin(), result.end());
}
#endif

12
junk/class.cc Normal file
View file

@ -0,0 +1,12 @@
#include <cstdint>
template <typename T> class User {
T id;
public:
explicit User(T n) : id(n) {}
};
int main() {
User<int> user1{1};
User<uint8_t> user2(0xFF);
}

6
takewhile/Makefile Normal file
View file

@ -0,0 +1,6 @@
TARGET = takewhile.elf
SRCS = takewhile.cc
all: $(TARGET)
include ../config.mk

54
takewhile/takewhile.cc Normal file
View file

@ -0,0 +1,54 @@
#include <cassert>
#include <iostream>
#include <iterator>
#include <vector>
template <typename InputIt, typename OutputIt, typename Pred>
std::pair<InputIt, OutputIt> copy_while(InputIt first, InputIt last,
OutputIt out, Pred p) {
// Iterate through the input range
while (first != last && p(*first)) {
*out = *first; // Copy the value to the output
++first; // Move to the next input element
++out; // Move to the next output element
}
// Return the pair of iterators
return {first, out};
}
std::vector<int> take_while_sum_less_than(std::vector<int> &invec, int n) {
std::vector<int> out;
int sum = 0;
copy_while(invec.begin(), invec.end(), std::back_inserter(out),
[&](int &x) -> bool { return (sum += x) < n; });
return out;
}
int main() {
// Sample data
std::vector<int> input = {1, 2, 3, 6,
7, 8}; // We will stop copying when we encounter 6
std::vector<int> output;
// Define the predicate: copy while the value is <= 5
auto pred = [](int n) { return n <= 5; };
// Call copy_while with the test data
auto [new_first, new_out] = copy_while(input.begin(), input.end(),
std::back_inserter(output), pred);
// Assert that the copied elements are correct (only the first three
// elements)
std::vector<int> test = std::vector<int>{1, 2, 3};
assert(output == test);
// Assert that the iterator returned points to the element that did not
// match the predicate (6)
assert(*new_first == 6);
std::vector<int> v{1, 2, 3};
auto w = take_while_sum_less_than(v, 10);
std::cout << "Hello" << std::endl;
std::for_each(w.begin(), w.end(),
[](int &a) { std::cout << a << " " << std::endl; });
}

6
tent1/Makefile Normal file
View file

@ -0,0 +1,6 @@
TARGET = main.elf
SRCS = main.cc
all: $(TARGET)
include ../config.mk

5
tent1/main.cc Normal file
View file

@ -0,0 +1,5 @@
#include <iostream>
int main() {
std::cout << "Hola" << std::endl;
}

6
tent2/Makefile Normal file
View file

@ -0,0 +1,6 @@
TARGET = main.elf
SRCS = main.cc
all: $(TARGET)
include ../config.mk

5
tent2/main.cc Normal file
View file

@ -0,0 +1,5 @@
#include <iostream>
int main() {
std::cout << "Hola" << std::endl;
}

7
vector/CMakeLists.txt Normal file
View file

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.16)
project(vec)
add_executable(main main.cc vec.cc)
# Link the common library
target_link_libraries(main PRIVATE common)

4
vector/Makefile Normal file
View file

@ -0,0 +1,4 @@
TARGET = main.elf
SRCS = vec.cc main.cc
include ../config.mk

29
vector/main.cc Normal file
View file

@ -0,0 +1,29 @@
#include "iassert.h"
#include "vec.h"
int main() {
{
Vec *v = new Vec();
delete v;
}
Vec v;
v.push_back(10);
ASSERT_MSG(v[0] == 10, "10 should be present at index 0");
Vec v2{1, 2, 3};
ASSERT_MSG(v2.size() == 3, "Size should be three");
v2.pop_back();
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");
for (const auto &a : v3) {
std::cout << a << std::endl;
}
}

60
vector/vec.cc Normal file
View file

@ -0,0 +1,60 @@
#include "vec.h"
#include <cstddef>
#include <cstring>
#include <iostream>
Vec::Vec() : cap(INITIAL_LEN), w_idx(0), arr(nullptr) {
std::cout << "Allocating vector" << std::endl;
arr = new T[INITIAL_LEN];
}
Vec::Vec(std::initializer_list<T> il) : Vec() {
for (auto &a : il) push_back(a);
}
Vec::~Vec() {
std::cout << "De-allocating vector" << std::endl;
if (arr)
delete[] arr;
}
T &Vec::operator[](std::size_t idx) const noexcept {
if (idx < w_idx)
return arr[idx];
exit(1);
}
void Vec::push_back(const T &value) noexcept {
arr[w_idx++] = value;
if (w_idx == cap) {
resize(cap * 2);
}
}
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;
T *newarr = new T[newsize];
std::memcpy(newarr, arr, w_idx);
delete[] arr;
arr = newarr;
cap = newsize;
}
void Vec::pop_back() noexcept { --w_idx; }
void Vec::clear() noexcept {
#ifdef REALCLEAR
delete[] arr;
arr = new T[INITIAL_LEN];
cap = INITIAL_LEN;
#endif
w_idx = 0;
}

43
vector/vec.h Normal file
View file

@ -0,0 +1,43 @@
#include <initializer_list>
#include <iterator>
typedef int T;
constexpr int INITIAL_LEN = 10;
class Vec {
std::size_t cap;
std::size_t w_idx;
T *arr = nullptr;
void resize(std::size_t newsize);
public:
Vec();
Vec(std::initializer_list<T>);
Vec(const Vec &other); // Copy
Vec(Vec &&other) noexcept; // Move
Vec &operator=(const Vec &other); // CopyAssign
Vec &operator=(Vec &&other) noexcept; // MoveAssign
~Vec(); // Destructor
T &operator[](std::size_t) const noexcept;
std::size_t size() const;
std::size_t capacity() const noexcept;
void push_back(const T &value) noexcept;
void pop_back() noexcept;
void clear() noexcept;
using iterator = T *;
using const_iterator = const T *;
iterator begin() noexcept { return arr; }
iterator end() noexcept { return arr + w_idx; }
const_iterator begin() const noexcept { return arr; }
const_iterator end() const noexcept { return arr + w_idx; }
};
// std::iterator<Vec> end() const noexcept;
// std::iterator begin() const noexcept;