diff --git a/CMakeLists.txt b/CMakeLists.txt index c19d3c9..9948b84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,6 +120,10 @@ set(APP_SOURCES "src/patterns/creational/AbstractFactory.cpp" "src/patterns/creational/Builder.cpp" "src/patterns/creational/Prototype.cpp" + ## Container + "src/core/datatypes/container/sequence/Array.cpp" + "src/core/datatypes/container/sequence/Vector.cpp" + "src/core/datatypes/container/unordered/UnorderedMap.cpp" ) # Test files diff --git a/src/core/basics/InitializeVariable.cpp b/src/core/basics/InitializeVariable.cpp index 2ca9726..af15399 100644 --- a/src/core/basics/InitializeVariable.cpp +++ b/src/core/basics/InitializeVariable.cpp @@ -28,12 +28,24 @@ struct Foo { void initialize_variable() { cout << "\n--- Variable Initialization Examples ---\n"; // There are there common ways to intialize a variable - // * Default + // * 1) Default-initialization [[maybe_unused]] int initDefaultVar; [[maybe_unused]] Foo initDefaultObj; - // * Traditional initialization - // * Copy-init: Type var = value; + [[maybe_unused]] unsigned char* c = new unsigned char; + *c = 0xF; // actual init at this point for c + delete c; + + // * 2) Value-initialization + [[maybe_unused]] int initValueVar1(); + [[maybe_unused]] int initValueVar2{}; + + // * 3) direct-init: Type var(value); + [[maybe_unused]] Foo directInitObj(4); // call Foo(int) + [[maybe_unused]] Foo directInitObj2( + 4.3); // look for constructor -> implicit 4.3(float) -> 4(int) -> call Foo(int) -> + + // * 4) Copy-init: Type var = other; // 1. Compiler tries to convert the value to a temporary Foo. // 2. If the constructor is explicit, implicit conversion is blocked -> compilation error. // 3. Otherwise, a temporary Foo is created and then copied/moved into the variable. @@ -43,13 +55,10 @@ void initialize_variable() { // Foo copyInitObjError = 2.3; // ERROR: implicit conversion blocked by explicit constructor // We can explicitly prevent certain conversions using = delete or using {} - // * direct-init: Type var(value); - [[maybe_unused]] Foo directInitObj(4); // call Foo(int) - [[maybe_unused]] Foo directInitObj2( - 4.3); // look for constructor -> implicit 4.3(float) -> 4(int) -> call Foo(int) -> - - // * Brace init + // * 5) List-initialization (Brace init) // calls the constructor directly without allowing implicit conversions. [[maybe_unused]] Foo braceInit{3}; // Foo braceInit2{3.3}; // ERORR => Prefer this way + [[maybe_unused]] int ar[] = {1, 2, 3}; // aggregate init + [[maybe_unused]] int ar2[]{1, 2, 3}; } \ No newline at end of file diff --git a/src/core/basics/README.md b/src/core/basics/README.md new file mode 100644 index 0000000..aab72de --- /dev/null +++ b/src/core/basics/README.md @@ -0,0 +1,135 @@ +# Theory + +## 1. Initialization in C++ + +C++ provides several ways to initialize objects. Each form has different semantics and use cases. + +--- + +### 1.1 Default Initialization + +Performed when an object is created **without any initializer**. + +```cpp +T object; +new T; +``` + +- Built-in types: uninitialized +- Class types: default constructor is called + +--- + +### 1.2 Value Initialization + +Performed when an object is created with an **empty initializer**. + +```cpp +T(); +new T(); +T object{}; +T{}; +new T{}; +``` + +Also used in constructors: + +```cpp +Class::Class() : member() {} +Class::Class() : member{} {} +``` + +- Built-in types: zero-initialized +- Class types: default constructor is called + +--- + +### 1.3 Direct Initialization + +Initializes an object using **explicit constructor arguments**. + +```cpp +T object(arg); +T object(arg1, arg2); + +T object{arg}; // since C++11 +new T(args...); +static_cast(other); +``` + +Used in constructors and lambdas: + +```cpp +Class::Class() : member(args...) {} +[arg]() {}; +``` + +--- + +### 1.4 Copy Initialization + +Initializes an object **from another object or expression**. + +```cpp +T object = other; +f(other); +return other; +throw object; +catch (T object); +``` + +Also used for arrays: + +```cpp +T array[N] = { /* values */ }; +``` + +--- + +### 1.5 List Initialization (since C++11) + +Initializes objects using **brace-enclosed initializer lists**. + +#### Direct List Initialization + +```cpp +T object{arg1, arg2}; +new T{arg1, arg2}; + +Class::Class() : member{arg1, arg2} {} +``` + +#### Copy List Initialization + +```cpp +T object = {arg1, arg2}; +return {arg1, arg2}; +function({arg1, arg2}); +``` + +#### Designated Initializers (since C++20) + +```cpp +T object{ .des1 = arg1, .des2 = arg2 }; +T object = { .des1 = arg1, .des2 = arg2 }; +``` + +--- + +### 1.6 Aggregate Initialization + +Initializes **aggregate types** (no user-defined constructors). + +```cpp +T object = {arg1, arg2}; +T object{arg1, arg2}; // since C++11 +``` + +Designated initializers for aggregates (since C++20): + +```cpp +T object = { .des1 = arg1, .des2 = arg2 }; +T object{ .des1 = arg1, .des2 = arg2 }; +``` + +- A specialized form of list-initialization \ No newline at end of file diff --git a/src/core/datatypes/container/README.md b/src/core/datatypes/container/README.md new file mode 100644 index 0000000..414bc8e --- /dev/null +++ b/src/core/datatypes/container/README.md @@ -0,0 +1,22 @@ +# Containers library +- The Containers library is a generic collection of class templates and algorithms that allow programmers to easilly implement common data structures. +- All container functions can be called concurrently by different threads on different containers +## 1. Sequence Containers +Sequence containers implement data structures which can be accessed sequentially. + +|name|description| +|---|---| +|array|fixed-sized inplace contiguous array| +|vector|resizeable contiguous array| +|dequeue|double-ended queue| +|forward_list|singly-linked list| +|list|doubly-linked list| + +## 2. Unordered Containers +Unordered associative containers implement unsorted (hashed) data structures that can be quickly searched (O(1) average, O(n) worst-case complexity). +|name|description| +|---|---| +|unordered_map|collection of key-value pairs, hashed by keys, keys are unique| +|unordered_set|collection of unique keys, hashed by keys| + +TBD \ No newline at end of file diff --git a/src/core/datatypes/container/sequence/Array.cpp b/src/core/datatypes/container/sequence/Array.cpp new file mode 100644 index 0000000..a267444 --- /dev/null +++ b/src/core/datatypes/container/sequence/Array.cpp @@ -0,0 +1,81 @@ +// cppcheck-suppress-file [unreadVariable,unusedVariable] + +/** + * std::array + * + * + * template< class T, std::size_t N > struct array; + */ +#include // for std::array +#include + +namespace { +void example() { + std::cout << "\n--- std::array Example ---\n"; + // 1) Init + std::array m_array = {9, 100, 0}; + // m_array = {1,2,3,5,6}; // ERROR + + std::array a2{3, 4, 5}; + std::array a3; // garbage values for a3[0]-> a4[] + std::array a4{}; // all elements have value 0 + std::array a5{1}; // a5[0] = 0, others elements have value 0 + + // 2) Element access + std::cout << m_array.front() << std::endl; + std::cout << m_array.back() << std::endl; + + int* ptr_arr = m_array.data(); + std::cout << *(ptr_arr++) << " "; + std::cout << *(ptr_arr++) << " "; + std::cout << *(ptr_arr++) << " "; + std::cout << std::endl; + + for (std::size_t i = 0; i < m_array.size(); ++i) { + std::cout << m_array.at(i) << " "; + } + std::cout << std::endl; + + for (const int& e : m_array) { + std::cout << e << " "; + } + std::cout << std::endl; + + // 3) Iterators + std::array::iterator it = m_array.begin(); + std::array::iterator itEnd = m_array.end(); + for (; it != itEnd; ++it) { + std::cout << *it << " "; + } + std::cout << std::endl; + + auto rIt = m_array.rbegin(); + auto rItEnd = m_array.rend(); + for (; rIt != rItEnd; rIt++) { + std::cout << *rIt << " "; + } + std::cout << std::endl; + + // 4) Capacity + std::cout << m_array.max_size() + << std::endl; // fixed-size => max_size = size + std::cout << m_array.size() << std::endl; + bool isEmpty = m_array.empty(); + + // 5) Operation + constexpr std::size_t xy = 4; + using Cell = std::array; + std::array board; + board.fill({0xE2, 0x96, 0x84, 0xE2, 0x96, 0x80, 0, + 0}); // "▄▀"; // fill means fill all 16 Cell with "▄▀" + // board = {Cell{0xE2, 0x96, 0x84, 0xE2, 0x96, 0x80, 0, 0},Cell{0xE2, 0x96, 0x84, 0xE2, 0x96, 0x80, 0, 0}}; + for (std::size_t count{}; Cell c : board) + std::cout << c.data() << ((++count % xy) ? "" : "\n"); +} +} // namespace + +struct ArrayRunner { + ArrayRunner() { example(); } +}; + +static ArrayRunner autoRunner; \ No newline at end of file diff --git a/src/core/datatypes/container/sequence/Vector.cpp b/src/core/datatypes/container/sequence/Vector.cpp new file mode 100644 index 0000000..deb663f --- /dev/null +++ b/src/core/datatypes/container/sequence/Vector.cpp @@ -0,0 +1,54 @@ +// cppcheck-suppress-file [unreadVariable,unusedVariable,redundantInitialization] + +// ArrayList +/** + * std::vector + * + * + */ +#include +#include // for std::vector + +namespace { +void example() { + std::cout << "\n--- std::vector Example ---\n"; + // 1) Init + std::vector m_vec = {9, 100, 0}; + m_vec = {1, 2, 3, 5, 6}; // OK + + std::vector m_vec1{9, 100, 0}; + std::vector m_vec2; + std::vector m_vec3{}; + std::vector m_vec4(); + + m_vec.assign({1, 1, 3}); + + // 2) Modifiers + m_vec.clear(); + + auto pos = m_vec.begin(); + m_vec.insert(pos, 99); + pos = m_vec.begin(); // pos may be no longer valid, get a new one + m_vec.insert(pos, 9); + pos = m_vec.begin(); + m_vec.erase(pos); + + m_vec.push_back(1); + m_vec.push_back(2); + m_vec.push_back(3); + m_vec.push_back(4); + + m_vec.pop_back(); + + for (const auto& e : m_vec) { + std::cout << e << " "; + } + std::cout << std::endl; +} +} // namespace + +struct VectorRunner { + VectorRunner() { example(); } +}; + +static VectorRunner autoRunner; \ No newline at end of file diff --git a/src/core/datatypes/container/unordered/UnorderedMap.cpp b/src/core/datatypes/container/unordered/UnorderedMap.cpp new file mode 100644 index 0000000..8e9b975 --- /dev/null +++ b/src/core/datatypes/container/unordered/UnorderedMap.cpp @@ -0,0 +1,76 @@ +// cppcheck-suppress-file [unreadVariable,unusedVariable,redundantInitialization] + +// HashMap: Collection of key-value pairs that are hashed by their keys where no two pairs have same keys. +/** + * std::unordered_map + * + * + */ +#include +#include +#include +#include + +namespace { +void example() { + std::cout << "\n--- std::unordered_map Example ---\n"; + // 1) Init + std::unordered_map m_map{ + {"k_1", 1}, {"k_2", 2}, {"k_3", 3}}; + + // 2) Modifiers + m_map.insert({"k_4", 4}); + + std::pair newElem1 = {"k_5", 0}; + m_map.insert(newElem1); + + std::string m_key = "k_6"; + int m_value = 99; + auto newElem2 = std::make_pair(m_key, m_value); + m_map.insert(newElem2); + + auto m_map2 = m_map; + for (auto it = m_map.begin(); it != m_map.end();) { + it = m_map.erase(it); + } + for (const std::pair& e : m_map) { + std::cout << "[" << e.first << "," << e.second << "]" << " "; + } + std::cout << std::endl; + + m_map2.insert_or_assign("k_6", 8888); // WORK + + auto pos = m_map2.find("k_6"); + if (pos != nullptr) { + m_map2.insert(std::make_pair( + "k_6", 9999)); // cannot reassign if this pair already existed + } + + // 3) Lookup + pos = m_map.find("k_1"); + std::cout << (pos != nullptr ? "true" : "false") << std::endl; + + for (auto const& [k, v] : m_map2) { + std::cout << "[" << k << "," << v << "]" << " "; + } + std::cout << std::endl; + + // 4) Make fun + std::vector keys{}; + for (auto const& [k, v] : m_map2) { + keys.push_back(k); + } + + std::cout << "Keys: " << std::endl; + for (auto const& k : keys) { + std::cout << k << " "; + } + std::cout << std::endl; +} +} // namespace + +struct UnorderedMap { + UnorderedMap() { example(); } +}; + +static UnorderedMap autoRunner; \ No newline at end of file diff --git a/src/core/string/CString.cpp b/src/core/string/CString.cpp index a5f0de3..4b315e3 100644 --- a/src/core/string/CString.cpp +++ b/src/core/string/CString.cpp @@ -36,6 +36,7 @@ void run() { std::cout << strArray << "\n"; // 2. As a a pointer to a string literal const (read-only) + // Literal is const char* char* strPtr = "this is a strPtr literal"; std::cout << strPtr << " - size " << sizeof(strPtr) << " - length " << strlen(strPtr) << "\n"; @@ -102,6 +103,10 @@ namespace CompareString { void run() { const char str1[] = "abc"; const char str2[] = "abcde"; + // 0. Compare memory + // int memcmp ( const void * ptr1, const void * ptr2, size_t num ); + int result0 = memcmp(str1, str2, sizeof(str1)); + std::cout << "strcmp(str1, \"abcde\") = " << result0 << "\n"; // 1. Compare full str int result1 = strcmp(str1, "abc");