diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 4e85f74..4827ed3 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -set(ALL_EXAMPLES fibonacci) +set(ALL_EXAMPLES capacity comparison fallible fibonacci) message("Examples to be built: ${ALL_EXAMPLES}") diff --git a/examples/capacity.cpp b/examples/capacity.cpp new file mode 100644 index 0000000..6686897 --- /dev/null +++ b/examples/capacity.cpp @@ -0,0 +1,85 @@ +#include + +#include + +using namespace beman::inplace_vector; + +/* + * Helper function to print the contents of an inplace_vector. + */ +template +void print_vector(const inplace_vector &vec, + const std::string_view name) { + std::cout << name << " [size=" << vec.size() + << ", capacity=" << vec.capacity() << "]: "; + + for (const auto &value : vec) { + std::cout << value << ' '; + } + + std::cout << '\n'; +} + +/* + * Example struct to demonstrate inplace_vector with non-trivial types. + */ +struct Point { + int x; + int y; +}; + +std::ostream &operator<<(std::ostream &os, const Point &p) { + return os << '(' << p.x << ", " << p.y << ')'; +} + +int main() { + /* + * inplace_vector behaves similarly to std::vector, + * but stores elements inline with a fixed maximum capacity. + */ + std::cout << "----- inplace_vector -----\n"; + + inplace_vector points; + + points.push_back({1, 2}); + points.emplace_back(3, 4); + + /* + * insert() shifts existing elements to make room. + */ + points.insert(points.begin() + 1, Point{10, 20}); + + print_vector(points, "points"); + + /* + * Once size() == capacity(), checked modifying operations + * such as push_back(), emplace_back(), and insert() + * cannot grow the container further. + * + * In exception-enabled environments: + * - std::bad_alloc is thrown. + * + * In non-exception environments: + * - the implementation asserts. + */ + std::cout << "\n----- Behavior at Capacity -----\n"; + try { + points.push_back({5, 6}); + } catch (const std::bad_alloc &) { + std::cout << "push_back failed: vector is at capacity\n"; + } + + try { + points.emplace_back(7, 8); + } catch (const std::bad_alloc &) { + std::cout << "emplace_back failed: vector is at capacity\n"; + } + + try { + points.insert(points.begin(), Point{0, 0}); + } catch (const std::bad_alloc &) { + std::cout << "insert failed: vector is at capacity\n"; + } + + return 0; +} diff --git a/examples/comparison.cpp b/examples/comparison.cpp new file mode 100644 index 0000000..41872f0 --- /dev/null +++ b/examples/comparison.cpp @@ -0,0 +1,89 @@ +#include +#include + +#include + +using namespace beman::inplace_vector; + +/* + * Helper function to print the contents of an inplace_vector. + */ +template +void print_vector(const inplace_vector &vec, + const std::string_view name) { + std::cout << name << " [size=" << vec.size() + << ", capacity=" << vec.capacity() << "]: "; + + for (const auto &value : vec) { + std::cout << value << ' '; + } + + std::cout << '\n'; +} + +/* + * Helper function to print the contents of an array. + */ +template +void print_array(const std::array &array, + const std::string_view name) { + std::cout << name << " [size=" << array.size() << "]: "; + + for (const auto &value : array) { + std::cout << value << ' '; + } + + std::cout << '\n'; +} + +int main() { + /* + * std::array + * + * Fixed-size container: + * - Size is always known at compile time. + * - Elements always exist. + * - No push_back / emplace_back support. + */ + std::cout << "----- std::array -----\n"; + + std::array arr{1, 2}; + + // arr.push_back(3); // ERROR: no push_back in std::array + + arr[2] = 3; + arr[3] = 4; + + print_array(arr, "std::array"); + + /* + * inplace_vector + * + * Fixed-capacity container: + * - Capacity is fixed at compile time. + * - Size changes dynamically at runtime. + * - Supports push_back / emplace_back APIs. + */ + std::cout << "\n----- inplace_vector -----\n"; + + inplace_vector vec; + + vec.unchecked_push_back(1); + vec.unchecked_push_back(2); + + if (vec.try_push_back(3)) { + std::cout << "Inserted 3\n"; + } + + if (vec.try_push_back(4)) { + std::cout << "Inserted 4\n"; + } + + if (!vec.try_push_back(5)) { + std::cout << "Failed to insert 5: vector is full\n"; + } + + print_vector(vec, "inplace_vector"); + + return 0; +} diff --git a/examples/fallible.cpp b/examples/fallible.cpp new file mode 100644 index 0000000..b7034c0 --- /dev/null +++ b/examples/fallible.cpp @@ -0,0 +1,80 @@ +#include + +#include + +using namespace beman::inplace_vector; + +/* + * Helper function to print the contents of an inplace_vector. + */ +template +void print_vector(const inplace_vector &vec, + const std::string_view name) { + std::cout << name << " [size=" << vec.size() + << ", capacity=" << vec.capacity() << "]: "; + + for (const auto &value : vec) { + std::cout << value << ' '; + } + + std::cout << '\n'; +} + +/* + * Example struct to demonstrate inplace_vector with non-trivial types. + */ +struct Point { + int x; + int y; +}; + +std::ostream &operator<<(std::ostream &os, const Point &p) { + return os << '(' << p.x << ", " << p.y << ')'; +} + +int main() { + /* + * Checked API + * + * try_* operations fail gracefully instead of overflowing capacity. + */ + std::cout << "----- Checked API -----\n"; + + inplace_vector checked; + + if (checked.try_push_back(10)) { + std::cout << "Inserted 10\n"; + } + + if (checked.try_push_back(20)) { + std::cout << "Inserted 20\n"; + } + + if (!checked.try_push_back(30)) { + std::cout << "Failed to insert 30: vector is full\n"; + } + + print_vector(checked, "checked"); + + /* + * Unchecked API + * + * unchecked_* operations skip capacity checks and require that + * the caller guarantees enough remaining space. + */ + std::cout << "\n----- Unchecked API -----\n"; + + inplace_vector unchecked; + + unchecked.unchecked_emplace_back(1, 2); + unchecked.unchecked_emplace_back(3, 4); + + print_vector(unchecked, "unchecked"); + + /* + * unchecked.unchecked_emplace_back(5, 6); + * Undefined behavior: capacity exceeded. + */ + + return 0; +}