::fast_io::vector

1. What is a vector?

A ::fast_io::vector<T> stores a sequence of elements of type T. It grows automatically when you add more items, and all elements stay together in one continuous block of memory.

You can think of it as a “growing list of values” that keeps everything tightly packed.

2. Creating a vector

You can create an empty vector or one with an initial size:


#include <fast_io.h>
#include <fast_io_dsal/vector.h>

int main() {
    using namespace ::fast_io::iomnp;

    ::fast_io::vector<std::size_t> a;            // empty
    ::fast_io::vector<std::size_t> b(5zu);       // 5 default-initialized elements
    ::fast_io::vector<std::size_t> c(3zu, 42zu); // 3 copies of value 42

    println("b size = ", b.size());
    println("c[0] = ", c[0]);
}

3. Adding elements

The most common way to add elements is push_back():


#include <fast_io.h>
#include <fast_io_dsal/vector.h>

int main() {
    using namespace ::fast_io::iomnp;

    ::fast_io::vector<std::size_t> v;

    v.push_back(10zu);
    v.push_back(20zu);
    v.push_back(30zu);

    println("Size: ", v.size()); // 3
}

When the vector runs out of space, it automatically allocates more memory.

4. Accessing elements safely

You can access elements using front(), back(), or operator[]:


#include <fast_io.h>
#include <fast_io_dsal/vector.h>

int main() {
    using namespace ::fast_io::iomnp;

    ::fast_io::vector<std::size_t> v{1zu, 2zu, 3zu, 4zu};

    println("Front: ", v.front()); // 1
    println("Back: ",  v.back());  // 4
    println("Index 2: ", v[2]);    // 3
}

⚠️ Safety note: If you access an element that does not exist (for example, calling v.front() on an empty vector or using an out-of-range index), fast_io performs a boundary check. If the check fails, the program stops immediately using __builtin_trap().

Safe usage


if(!v.is_empty()) {
    println("Front: ", v.front());
}

std::size_t i = 2zu;
if(i < v.size()) {
    println("v[2] = ", v[i]);
}

5. Iterating through elements

Preferred: Range‑based for loop

This is the simplest way to go through all elements:


#include <fast_io.h>
#include <fast_io_dsal/vector.h>

int main() {
    using namespace ::fast_io::iomnp;

    ::fast_io::vector<std::size_t> v{10zu, 20zu, 30zu};

    for(std::size_t x : v) {
        println(x);
    }
}

Alternative: Index loop

Useful when you need the position:


for(std::size_t i{}, n{v.size()}; i != n; ++i) {
    println("Index ", i, ": ", v[i]);
}

Advanced: Iterators

In Section 3.1 (string iterators), we introduced the idea that an iterator behaves like a pointer into a container’s memory. A ::fast_io::vector<T> uses the same iterator model as ::fast_io::string.

This means:

Example:


#include <fast_io.h>
#include <fast_io_dsal/vector.h>

int main() {
    using namespace ::fast_io::iomnp;

    ::fast_io::vector<std::size_t> v{10zu, 20zu, 30zu};

    for(auto it = v.begin(), ed = v.end(); it != ed; ++it) {
        println(*it);
    }
}

Iterator arithmetic

Just like with strings, vector iterators allow random‑access operations:


auto it = v.begin();        // first element
println(*(it + 1));         // move forward
println((it + 2)[0]);       // same as v[2]
println((it + 2)[-1]);      // move backward from a valid position

These operations are fast, but they do not check bounds.

Iterator invalidation

Any operation that causes the vector to grow may reallocate its storage. When this happens, all existing iterators become invalid.


auto it2 = v.begin();
v.push_back(999zu);  // may reallocate

// ⚠️ it2 may now point to old memory
// println(*it2);   // undefined behavior

If you need to keep positions across reallocation, store an index instead of an iterator.

6. Removing elements

pop_back()

Removes the last element:


v.pop_back();

⚠️ Calling pop_back() on an empty vector stops the program immediately.

7. Clearing and releasing memory

clear()

Removes all elements but keeps the allocated memory. This is useful when you plan to reuse the vector soon.


v.clear();
println(v.size()); // 0

clear_destroy()

Removes all elements and releases the memory back to the allocator. After this call, the vector becomes completely empty with no storage.


v.clear_destroy(); // memory returned to allocator
println(v.size()); // 0

Use clear_destroy() when you are done with the vector and want to free its memory.

Key takeaways