// Copyright 2017 Google Inc. All Rights Reserved. | |
// | |
// 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. | |
// | |
#ifndef NB_REWINDABLE_VECTOR_CAST_H_ | |
#define NB_REWINDABLE_VECTOR_CAST_H_ | |
#include <vector> | |
#include "starboard/common/log.h" | |
namespace nb { | |
// Like an std::vector, but supports an additional rewind operation. rewind() | |
// is like a light-weight clear() operation which does not destroy contained | |
// objects. | |
// This is important for performance where the same elements need to be | |
// re-used. For example, a vector of structs which contain std::strings in | |
// which it's more desirable for the strings are re-assigned rather than | |
// destroyed and then re-constructed through rewind() / grow(). | |
// | |
// Object destruction occurs on clear() or container destruction. | |
// | |
// Example: | |
// RewindableVector<std::string> values; | |
// values.push_back("ABCDEF"); | |
// values.rewindAll(); // string at [0] is unchanged. | |
// EXPECT_EQ(0, values.size()); | |
// values.expand(1); // string at [0] is unchanged. | |
// values[0].assign("ABC"); // string is re-assigned, no memory allocated. | |
template <typename T, typename VectorT = std::vector<T> > | |
class RewindableVector { | |
public: | |
RewindableVector() : size_(0) {} | |
const T& operator[](size_t i) const { return at(i); } | |
T& operator[](size_t i) { return at(i); } | |
const T& at(size_t i) const { | |
SB_DCHECK(i < size_); | |
return vector_[i]; | |
} | |
T& at(size_t i) { | |
SB_DCHECK(i < size_); | |
return vector_[i]; | |
} | |
bool empty() const { return size() == 0; } | |
size_t size() const { return size_; } | |
void clear() { | |
vector_.clear(); | |
size_ = 0; | |
} | |
void rewindAll() { size_ = 0; } | |
void rewind(size_t i) { | |
if (i <= size_) { | |
size_ -= i; | |
} else { | |
SB_NOTREACHED() << "underflow condition."; | |
rewindAll(); | |
} | |
} | |
// Grows the array by n values. The new last element is returned. | |
T& grow(size_t n) { | |
size_ += n; | |
if (size_ > vector_.size()) { | |
vector_.resize(size_); | |
} | |
return back(); | |
} | |
T& back() { return vector_[size_ - 1]; } | |
void pop_back() { rewind(1); } | |
void push_back(const T& v) { | |
if (size_ == vector_.size()) { | |
vector_.push_back(v); | |
} else { | |
vector_[size_] = v; | |
} | |
++size_; | |
} | |
VectorT& InternalData() { return vector_; } | |
private: | |
VectorT vector_; | |
size_t size_; | |
}; | |
} // namespace nb | |
#endif // NB_REWINDABLE_VECTOR_CAST_H_ |