add Chapter01 examples
This commit is contained in:
19
Chapter01/README.md
Normal file
19
Chapter01/README.md
Normal file
@@ -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
|
||||||
107
Chapter01/bloat.cpp
Normal file
107
Chapter01/bloat.cpp
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
#include <array>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#if USE_TEMPLATES
|
||||||
|
template <class T, std::size_t N> struct ring_buffer {
|
||||||
|
std::array<T, N> 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<int, N> 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<float, N> 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<int, 10> buffer1;
|
||||||
|
ring_buffer<float, 10> 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;
|
||||||
|
}
|
||||||
10
Chapter01/compile_time_const.c
Normal file
10
Chapter01/compile_time_const.c
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define VOLTAGE 3300
|
||||||
|
#define CURRENT 1000
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
const float resistance = VOLTAGE / CURRENT;
|
||||||
|
printf("resistance = %.2f\r\n", resistance);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
10
Chapter01/compile_time_const.cpp
Normal file
10
Chapter01/compile_time_const.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
constexpr float voltage = 3300;
|
||||||
|
constexpr float current = 1000;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
const float resistance = voltage / current;
|
||||||
|
printf("resistance = %.2f\r\n", resistance);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
8
Chapter01/compile_time_square_func.cpp
Normal file
8
Chapter01/compile_time_square_func.cpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
constexpr int square(int a) {
|
||||||
|
return a*a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
constexpr int ret = square(2);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
31
Chapter01/exceptions.cpp
Normal file
31
Chapter01/exceptions.cpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
50
Chapter01/ring_buffer.c
Normal file
50
Chapter01/ring_buffer.c
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
48
Chapter01/ring_buffer.cpp
Normal file
48
Chapter01/ring_buffer.cpp
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#include <array>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
template <class T, std::size_t N> struct ring_buffer {
|
||||||
|
|
||||||
|
std::array<T, N> 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<int, 5> rb;
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
rb.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!rb.is_empty()) {
|
||||||
|
printf("%d\n", rb.pop());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
53
Chapter01/ring_buffer_compile_time_generic.c
Normal file
53
Chapter01/ring_buffer_compile_time_generic.c
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
54
Chapter01/ring_buffer_type_erasure.c
Normal file
54
Chapter01/ring_buffer_type_erasure.c
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
29
Chapter01/rtti.cpp
Normal file
29
Chapter01/rtti.cpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
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<Derived*>(&base); derived!=nullptr) {
|
||||||
|
printf("We found Base using RTTI!\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Base base;
|
||||||
|
Derived derived;
|
||||||
|
printer(base);
|
||||||
|
printer(derived);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
16
Chapter01/undefined_behavior.cpp
Normal file
16
Chapter01/undefined_behavior.cpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
int foo(int x) {
|
||||||
|
int y = x + 1;
|
||||||
|
return y > x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
if (foo(std::numeric_limits<int>::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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user