Skip to content

Commit

Permalink
Add expanding_vector.h
Browse files Browse the repository at this point in the history
  • Loading branch information
KerstinKeller committed Sep 24, 2024
1 parent 2f0d570 commit 2c2dca8
Showing 1 changed file with 223 additions and 0 deletions.
223 changes: 223 additions & 0 deletions ecal/core/src/util/expanding_vector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/* ========================= eCAL LICENSE =================================
*
* Copyright (C) 2016 - 2024 Continental Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ========================= eCAL LICENSE =================================
*/

/**
* @brief std::vector wrapper, that never deallocates element, just clears them
**/

#pragma once

#include <vector>

namespace eCAL
{
namespace Util
{
/**
* @brief A vector that never destructs its elements, but only calls clear on them.
*
* @tparam T The type of the values. Must provide a `.clear()` function
*
* This class is *not* threadsafe and needs to be protected by locks / mutexes in multithreaded environments.
*
* From the outside / for the user, this class acts as a regular std::vector.
* However, when calling clear(), a regular vector will destroy the elements which are stored in this vector.
* This class, will instead call the `clear()` functions on all members.
*/
#include <iostream>
#include <vector>
#include <iterator>

// Templated class CExpandingVector
template <class T>
class CExpandingVector {
public:
using value_type = typename std::vector<T>::value_type;
using allocator_type = typename std::vector<T>::allocator_type;
using size_type = typename std::vector<T>::size_type;
using difference_type = typename std::vector<T>::difference_type;
using reference = typename std::vector<T>::reference;
using const_reference = typename std::vector<T>::const_reference;
using pointer = typename std::vector<T>::pointer;
using const_pointer = typename std::vector<T>::const_pointer;
using iterator = typename std::vector<T>::iterator;
using const_iterator = typename std::vector<T>::const_iterator;
using reverse_iterator = typename std::vector<T>::reverse_iterator;
using const_reverse_iterator = typename std::vector<T>::const_reverse_iterator;

private:
std::vector<T> data;
size_t internal_size; // Track size separately

public:
// Constructor
CExpandingVector() : internal_size(0) {}

// Access to the internal size
size_t size() const {
return internal_size;
}

// Clear the content but not the underlying vector
void clear() {
for (auto& elem : data) {
elem.clear(); // Call the clear() function on individual elements
}
// We don't modify the size of the underlying vector but keep the internal size consistent.
internal_size = 0;
}

// Add new element to the vector
void push_back(const T& value) {
if (internal_size < data.size()) {
data[internal_size] = value; // Reuse space
} else {
data.push_back(value); // Expand the vector if needed
}
++internal_size;
}

void push_back()
{
if (internal_size == data.size()) {
data.push_back(T{}); // Expand the vector if needed, else do nothing
}
++internal_size;
}

// Access the first element
T& front() {
if (internal_size == 0) {
throw std::out_of_range("CExpandingVector is empty");
}
return data.front(); // Return the first element
}

const T& front() const {
if (internal_size == 0) {
throw std::out_of_range("CExpandingVector is empty");
}
return data.front(); // Return the first element
}

// Access the last element
T& back() {
if (internal_size == 0) {
throw std::out_of_range("CExpandingVector is empty");
}
return data[internal_size - 1]; // Return the last element
}

const T& back() const {
if (internal_size == 0) {
throw std::out_of_range("CExpandingVector is empty");
}
return data[internal_size - 1]; // Return the last element
}


// Resize the vector
void resize(size_t new_size) {
if (new_size > data.size()) {
data.resize(new_size);
}
internal_size = new_size;
}

// Access element with bounds checking
T& at(size_t index) {
if (index >= internal_size) {
throw std::out_of_range("Index out of bounds");
}
return data.at(index);
}

// Const access element with bounds checking
const T& at(size_t index) const {
if (index >= internal_size) {
throw std::out_of_range("Index out of bounds");
}
return data.at(index);
}

// Iterator functions
iterator begin() {
return data.begin();
}

const_iterator begin() const {
return data.begin();
}

iterator end() {
return data.begin() + internal_size;
}

const_iterator end() const {
return data.begin() + internal_size;
}

// Access the underlying capacity
size_t capacity() const {
return data.capacity();
}

// Operator[] overload
T& operator[](size_t index) {
return data[index];
}

const T& operator[](size_t index) const {
return data[index];
}

// Check if vector is empty
bool empty() const {
return internal_size == 0;
}

// Get underlying vector's full size (not just the internal size)
size_t full_size() const {
return data.size();
}

// Equality operator (compares size and elements)
bool operator==(const CExpandingVector<T>& other) const {
// Check if sizes are equal
if (internal_size != other.internal_size) {
return false;
}

// Compare elements
for (size_t i = 0; i < internal_size; ++i) {
if (!(data[i] == other.data[i])) {
return false;
}
}

return true; // Sizes are equal and all elements are the same
}

bool operator!=(const CExpandingVector<T>& other) const {
return !(*this == other); // Use the equality operator to implement inequality
}
};

}
}

0 comments on commit 2c2dca8

Please sign in to comment.