tdesktop/Telegram/SourceFiles/core/vector_of_moveable.h

154 lines
4.0 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
// some minimal implementation of std::vector() for moveable (but not copiable) types.
namespace std_ {
template <typename T>
class vector_of_moveable {
typedef vector_of_moveable<T> Self;
int _size = 0, _capacity = 0;
void *_plaindata = nullptr;
public:
inline T *data() {
return reinterpret_cast<T*>(_plaindata);
}
inline const T *data() const {
return reinterpret_cast<const T*>(_plaindata);
}
inline bool operator==(const Self &other) const {
if (this == &other) return true;
if (_size != other._size) return false;
for (int i = 0; i < _size; ++i) {
if (data()[i] != other.data()[i]) {
return false;
}
}
return true;
}
inline bool operator!=(const Self &other) const { return !(*this == other); }
inline int size() const { return _size; }
inline bool isEmpty() const { return _size == 0; }
inline void clear() {
for (int i = 0; i < _size; ++i) {
data()[i].~T();
}
_size = 0;
operator delete[](_plaindata);
_plaindata = nullptr;
_capacity = 0;
}
typedef T *iterator;
typedef const T *const_iterator;
// STL style
inline iterator begin() { return data(); }
inline const_iterator begin() const { return data(); }
inline const_iterator cbegin() const { return data(); }
inline iterator end() { return data() + _size; }
inline const_iterator end() const { return data() + _size; }
inline const_iterator cend() const { return data() + _size; }
inline iterator erase(iterator it) {
T tmp = std_::move(*it);
for (auto next = it + 1, e = end(); next != e; ++next) {
auto prev = next - 1;
*prev = std_::move(*next);
}
--_size;
return it;
}
inline iterator insert(const_iterator pos, T &&value) {
int insertAtIndex = pos - begin();
if (_size + 1 > _capacity) {
reallocate(_capacity + (_capacity > 1 ? _capacity / 2 : 1));
}
auto insertAt = begin() + insertAtIndex, e = end();
if (insertAt == e) {
new (&(*insertAt)) T(std_::move(value));
} else {
auto prev = e - 1;
new (&(*e)) T(std_::move(*prev));
for (auto it = prev; it != insertAt; --it) {
*it = std_::move(*--prev);
}
*insertAt = std_::move(value);
}
++_size;
return insertAt;
}
inline void push_back(T &&value) {
insert(end(), std_::forward<T>(value));
}
inline void pop_back() {
erase(end() - 1);
}
inline T &front() {
return *begin();
}
inline const T &front() const {
return *begin();
}
inline T &back() {
return *(end() - 1);
}
inline const T &back() const {
return *(end() - 1);
}
inline bool empty() const { return _size == 0; }
inline T &operator[](int index) {
return data()[index];
}
inline const T &operator[](int index) const {
return data()[index];
}
inline const T &at(int index) const {
if (index < 0 || index >= _size) {
throw std::out_of_range("");
}
return data()[index];
}
inline ~vector_of_moveable() {
clear();
}
private:
void reallocate(int newCapacity) {
auto newPlainData = operator new[](newCapacity * sizeof(T));
for (int i = 0; i < _size; ++i) {
*(reinterpret_cast<T*>(newPlainData) + i) = std_::move(*(data() + i));
}
std::swap(_plaindata, newPlainData);
_capacity = newCapacity;
operator delete[](newPlainData);
}
};
} // namespace std_