diff --git a/Chapter01/README.md b/Chapter01/README.md new file mode 100644 index 0000000..a9f4822 --- /dev/null +++ b/Chapter01/README.md @@ -0,0 +1,19 @@ +# Chapter01 +This folder contains examples in C and C++ from first chapter. + +These are standalone examples that can be compiled by most compilers for x86_64 architecture. + +You can explore the examples online in [Compiler Explorer](https://godbolt.org/). + +The folder contains following examples: +- ring_buffer.c +- ring_buffer_type_erasure.c +- ring_buffer_compile_time_generic.c +- ring_buffer.cpp +- compile_time_const.c +- compile_time_const.cpp +- compile_time_square_func.cpp +- undefined_behavior.cpp +- bloat.cpp +- rtti.cpp +- exceptions.cpp diff --git a/Chapter01/bloat.cpp b/Chapter01/bloat.cpp new file mode 100644 index 0000000..73c8ad5 --- /dev/null +++ b/Chapter01/bloat.cpp @@ -0,0 +1,107 @@ +#include +#include + +#if USE_TEMPLATES +template struct ring_buffer { + std::array arr; + std::size_t write_idx = 0; // Index of the next element to write (push) + std::size_t read_idx = 0; // Index of the next element to read (pop) + std::size_t count = 0; // Number of elements in the buffer + + void push(T t) { + arr.at(write_idx) = t; + write_idx = (write_idx + 1) % N; + if (count < N) { + count++; + } else { + // buffer is full, move forward read_idx + read_idx = (read_idx + 1) % N; + } + } + + T pop() { + if (count == 0) { + // Buffer is empty, return a default-constructed T. + return T{}; + } + T value = arr.at(read_idx); + read_idx = (read_idx + 1) % N; + --count; + return value; + } + + bool is_empty() const { return count == 0; } +}; + +#else + +#define N 10 + +struct ring_buffer_int { + std::array arr; + std::size_t write_idx = 0; // Index of the next element to write (push) + std::size_t read_idx = 0; // Index of the next element to read (pop) + std::size_t count = 0; // Number of elements in the buffer + + void push(int t) { + arr.at(write_idx) = t; + write_idx = (write_idx + 1) % N; + ++count; + } + + int pop() { + if (count == 0) { + // Buffer is empty, return a default-constructed T. + return int{}; + } + int value = arr.at(read_idx); + read_idx = (read_idx + 1) % N; + --count; + return value; + } +}; + +struct ring_buffer_float { + std::array arr; + std::size_t write_idx = 0; // Index of the next element to write (push) + std::size_t read_idx = 0; // Index of the next element to read (pop) + std::size_t count = 0; // Number of elements in the buffer + + void push(float t) { + arr.at(write_idx) = t; + write_idx = (write_idx + 1) % N; + ++count; + } + + float pop() { + if (count == 0) { + // Buffer is empty, return a default-constructed T. + return float{}; + } + float value = arr.at(read_idx); + read_idx = (read_idx + 1) % N; + --count; + return value; + } +}; +#endif + +int main() { +#ifdef USE_TEMPLATES + ring_buffer buffer1; + ring_buffer buffer2; +#else + ring_buffer_int buffer1; + ring_buffer_float buffer2; +#endif + for (int i = 0; i < 20; i++) { + buffer1.push(i); + buffer2.push(i + 0.2f); + } + + for (int i = 0; i < 10; i++) { + printf("%d, %.2f\r\n", buffer1.pop(), buffer2.pop()); + } + + return 0; +} diff --git a/Chapter01/compile_time_const.c b/Chapter01/compile_time_const.c new file mode 100644 index 0000000..4aeae00 --- /dev/null +++ b/Chapter01/compile_time_const.c @@ -0,0 +1,10 @@ +#include + +#define VOLTAGE 3300 +#define CURRENT 1000 + +int main() { + const float resistance = VOLTAGE / CURRENT; + printf("resistance = %.2f\r\n", resistance); + return 0; +} diff --git a/Chapter01/compile_time_const.cpp b/Chapter01/compile_time_const.cpp new file mode 100644 index 0000000..b5d6043 --- /dev/null +++ b/Chapter01/compile_time_const.cpp @@ -0,0 +1,10 @@ +#include + +constexpr float voltage = 3300; +constexpr float current = 1000; + +int main() { + const float resistance = voltage / current; + printf("resistance = %.2f\r\n", resistance); + return 0; +} diff --git a/Chapter01/compile_time_square_func.cpp b/Chapter01/compile_time_square_func.cpp new file mode 100644 index 0000000..05477bf --- /dev/null +++ b/Chapter01/compile_time_square_func.cpp @@ -0,0 +1,8 @@ +constexpr int square(int a) { + return a*a; +} + +int main() { + constexpr int ret = square(2); + return ret; +} diff --git a/Chapter01/exceptions.cpp b/Chapter01/exceptions.cpp new file mode 100644 index 0000000..6ccb93d --- /dev/null +++ b/Chapter01/exceptions.cpp @@ -0,0 +1,31 @@ +#include + +struct A { + A() { printf("A is created!\r\n"); } + ~A() { printf("A is destroyed!\r\n"); } +}; + +struct B { + B() { printf("B is created!\r\n"); } + ~B() { printf("B is destroyed!\r\n"); } +}; + +void bar() { + B b; + throw 0; +} + +void foo() { + A a; + bar(); + A a1; +} + +int main() { + try { + foo(); + } catch (int &p) { + printf("Catching an exception!\r\n"); + } + return 0; +} diff --git a/Chapter01/ring_buffer.c b/Chapter01/ring_buffer.c new file mode 100644 index 0000000..5f772a9 --- /dev/null +++ b/Chapter01/ring_buffer.c @@ -0,0 +1,50 @@ +#include + +#define BUFFER_SIZE 5 + +typedef struct { + int arr[BUFFER_SIZE]; // Array to store int values directly + size_t write_idx; // Index of the next element to write (push) + size_t read_idx; // Index of the next element to read (pop) + size_t count; // Number of elements in the buffer +} int_ring_buffer; + +void int_ring_buffer_init(int_ring_buffer *rb) { + rb->write_idx = 0; + rb->read_idx = 0; + rb->count = 0; +} + +void int_ring_buffer_push(int_ring_buffer *rb, int value) { + rb->arr[rb->write_idx] = value; + rb->write_idx = (rb->write_idx + 1) % BUFFER_SIZE; + if (rb->count < BUFFER_SIZE) { + rb->count++; + } else { + // Buffer is full, move read_idx forward + rb->read_idx = (rb->read_idx + 1) % BUFFER_SIZE; + } +} + +int int_ring_buffer_pop(int_ring_buffer *rb) { + if (rb->count == 0) { + return 0; + } + int value = rb->arr[rb->read_idx]; + rb->read_idx = (rb->read_idx + 1) % BUFFER_SIZE; + rb->count--; + return value; +} + +int main() { + int_ring_buffer rb; + int_ring_buffer_init(&rb); + for (int i = 0; i < 10; i++) { + int_ring_buffer_push(&rb, i); + } + while (rb.count > 0) { + int value = int_ring_buffer_pop(&rb); + printf("%d\n", value); + } + return 0; +} diff --git a/Chapter01/ring_buffer.cpp b/Chapter01/ring_buffer.cpp new file mode 100644 index 0000000..ff77243 --- /dev/null +++ b/Chapter01/ring_buffer.cpp @@ -0,0 +1,48 @@ +#include +#include + +template struct ring_buffer { + + std::array arr; + std::size_t write_idx = 0; // Index of the next element to write (push) + std::size_t read_idx = 0; // Index of the next element to read (pop) + std::size_t count = 0; // Number of elements in the buffer + // + void push(T t) { + arr.at(write_idx) = t; + write_idx = (write_idx + 1) % N; + if (count < N) { + count++; + } else { + // buffer is full, move forward read_idx + read_idx = (read_idx + 1) % N; + } + } + + T pop() { + if (count == 0) { + // Buffer is empty, return a default-constructed T. + return T{}; + } + T value = arr.at(read_idx); + read_idx = (read_idx + 1) % N; + --count; + return value; + } + + bool is_empty() const { return count == 0; } +}; + +int main() { + ring_buffer rb; + + for (int i = 0; i < 10; ++i) { + rb.push(i); + } + + while (!rb.is_empty()) { + printf("%d\n", rb.pop()); + } + + return 0; +} diff --git a/Chapter01/ring_buffer_compile_time_generic.c b/Chapter01/ring_buffer_compile_time_generic.c new file mode 100644 index 0000000..4b084e6 --- /dev/null +++ b/Chapter01/ring_buffer_compile_time_generic.c @@ -0,0 +1,53 @@ +#include +#include +// Macro to declare ring buffer type and functions for a specific type and size +#define DECLARE_RING_BUFFER(TYPE, SIZE) \ + typedef struct { \ + TYPE data[SIZE]; \ + size_t write_idx; \ + size_t read_idx; \ + size_t count; \ + } ring_buffer_##TYPE##_##SIZE; \ + void ring_buffer_init_##TYPE##_##SIZE(ring_buffer_##TYPE##_##SIZE *rb) { \ + rb->write_idx = 0; \ + rb->read_idx = 0; \ + rb->count = 0; \ + } \ + void ring_buffer_push_##TYPE##_##SIZE(ring_buffer_##TYPE##_##SIZE *rb, \ + TYPE value) { \ + rb->data[rb->write_idx] = value; \ + rb->write_idx = (rb->write_idx + 1) % SIZE; \ + if (rb->count < SIZE) { \ + rb->count++; \ + } else { \ + rb->read_idx = (rb->read_idx + 1) % SIZE; \ + } \ + } \ + int ring_buffer_pop_##TYPE##_##SIZE(ring_buffer_##TYPE##_##SIZE *rb, \ + TYPE *value) { \ + if (rb->count == 0) { \ + return 0; /* Buffer is empty */ \ + } \ + *value = rb->data[rb->read_idx]; \ + rb->read_idx = (rb->read_idx + 1) % SIZE; \ + rb->count--; \ + return 1; /* Success */ \ + } \ + +// Example usage with int type and size 5 +DECLARE_RING_BUFFER(int, 5) // Declare the ring buffer type and functions for ints + // +int main() { + ring_buffer_int_5 rb; + ring_buffer_init_int_5(&rb); // Initialize the ring buffer + // Push values into the ring buffer + for (int i = 0; i < 10; ++i) { + ring_buffer_push_int_5(&rb, i); + } + // Pop values from the ring buffer and print them + int value; + while (ring_buffer_pop_int_5(&rb, &value)) { + printf("%d\n", value); + } + return 0; +} diff --git a/Chapter01/ring_buffer_type_erasure.c b/Chapter01/ring_buffer_type_erasure.c new file mode 100644 index 0000000..d19c11e --- /dev/null +++ b/Chapter01/ring_buffer_type_erasure.c @@ -0,0 +1,54 @@ +#include +#include + +#define BUFFER_SIZE 20 // Total bytes available in the buffer + // +typedef struct { + unsigned char data[BUFFER_SIZE]; // Array to store byte values + size_t write_idx; // Index of the next byte to write + size_t read_idx; // Index of the next byte to read + size_t count; // Number of bytes currently used in the buffer + size_t elem_size; // Size of each element in bytes +} ring_buffer; + +void ring_buffer_init(ring_buffer *rb, size_t elem_size) { + rb->write_idx = 0; + rb->read_idx = 0; + rb->count = 0; + rb->elem_size = elem_size; +} + +void ring_buffer_push(ring_buffer *rb, void *value) { + if (rb->count + rb->elem_size <= BUFFER_SIZE) { + rb->count += rb->elem_size; + } else { + rb->read_idx = (rb->read_idx + rb->elem_size) % BUFFER_SIZE; + } + memcpy(&rb->data[rb->write_idx], value, rb->elem_size); + rb->write_idx = (rb->write_idx + rb->elem_size) % BUFFER_SIZE; +} + +int ring_buffer_pop(ring_buffer *rb, void *value) { + if (rb->count < rb->elem_size) { + // Not enough data to pop + return 0; + } + memcpy(value, &rb->data[rb->read_idx], rb->elem_size); + rb->read_idx = (rb->read_idx + rb->elem_size) % BUFFER_SIZE; + rb->count -= rb->elem_size; + return 1; // Success +} + +int main() { + ring_buffer rb; + ring_buffer_init(&rb, sizeof(int)); // Initialize buffer for int values + for (int i = 0; i < 10; i++) { + int val = i; + ring_buffer_push(&rb, &val); + } + int pop_value; + while (ring_buffer_pop(&rb, &pop_value)) { + printf("%d\n", pop_value); + } + return 0; +} diff --git a/Chapter01/rtti.cpp b/Chapter01/rtti.cpp new file mode 100644 index 0000000..e569e4e --- /dev/null +++ b/Chapter01/rtti.cpp @@ -0,0 +1,29 @@ +#include + +struct Base { + virtual void print() { + printf("Base\r\n"); + } +}; + +struct Derived : public Base { + void print() override { + printf("Derived\r\n"); + } +}; + +void printer(Base &base) { + base.print(); + + if(Derived *derived = dynamic_cast(&base); derived!=nullptr) { + printf("We found Base using RTTI!\r\n"); + } +} + +int main() { + Base base; + Derived derived; + printer(base); + printer(derived); + return 0; +} diff --git a/Chapter01/undefined_behavior.cpp b/Chapter01/undefined_behavior.cpp new file mode 100644 index 0000000..fffc52e --- /dev/null +++ b/Chapter01/undefined_behavior.cpp @@ -0,0 +1,16 @@ +#include +#include + +int foo(int x) { + int y = x + 1; + return y > x; +} + +int main() { + if (foo(std::numeric_limits::max())) { + printf("X is larger than X + 1\r\n"); + } else { + printf("X is NOT larger than X + 1. Oh nooo !\r\n"); + } + return 0; +}