initial version

This commit is contained in:
2024-02-25 15:35:43 +00:00
parent e391c66fc7
commit 728819033f
4 changed files with 471 additions and 209 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/.vscode
/.devcontainer
/.github
/build
/.cache
.clang-format

5
CMakeLists.txt Normal file
View File

@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.10)
Project(STLite-ACM-2024)
include(CTest)
add_subdirectory(vector)
enable_testing()

4
vector/CMakeLists.txt Normal file
View File

@ -0,0 +1,4 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
add_executable(one ${CMAKE_CURRENT_SOURCE_DIR}/data/one/code.cpp)
add_test(NAME vector_one COMMAND one >/tmp/one_out.txt
&& diff -u ${CMAKE_CURRENT_SOURCE_DIR}/data/one/answer.txt /tmp/one_out.txt>/tmp/one_diff.txt)

View File

@ -5,28 +5,28 @@
#include <climits> #include <climits>
#include <cstddef> #include <cstddef>
#include <exception>
namespace sjtu #include <iterator>
{ #include <memory>
#include <vector>
namespace sjtu {
/** /**
* a data container like std::vector * a data container like std::vector
* store data in a successive memory and support random access. * store data in a successive memory and support random access.
*/ */
template <typename T> template <typename T>
class vector class vector {
{ std::allocator<T> alloc;
size_t allocated_length;
size_t current_length;
T *raw_beg, *raw_end;
public: public:
/**
* TODO
* a type for actions of the elements of a vector, and you should write
* a class named const_iterator with same interfaces.
*/
/** /**
* you can see RandomAccessIterator at CppReference for help. * you can see RandomAccessIterator at CppReference for help.
*/ */
class const_iterator; class const_iterator;
class iterator class iterator {
{
// The following code is written for the C++ type_traits library. // The following code is written for the C++ type_traits library.
// Type traits is a C++ feature for describing certain properties of a type. // Type traits is a C++ feature for describing certain properties of a type.
// For instance, for an iterator, iterator::value_type is the type that the // For instance, for an iterator, iterator::value_type is the type that the
@ -38,189 +38,436 @@ public:
// https://en.cppreference.com/w/cpp/header/type_traits // https://en.cppreference.com/w/cpp/header/type_traits
// About value_type: https://blog.csdn.net/u014299153/article/details/72419713 // About value_type: https://blog.csdn.net/u014299153/article/details/72419713
// About iterator_category: https://en.cppreference.com/w/cpp/iterator // About iterator_category: https://en.cppreference.com/w/cpp/iterator
friend class vector<T>;
public: public:
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
using value_type = T; using value_type = T;
using pointer = T *; using pointer = T *;
using reference = T &; using reference = T &;
using iterator_category = std::output_iterator_tag; using iterator_category = std::random_access_iterator_tag;
private: private:
/** vector<T> *domain;
* TODO add data members T *raw_pointer;
* just add whatever you want. iterator(vector<T> *domain, T *raw_pointer) : domain(domain), raw_pointer(raw_pointer) {}
*/
public: public:
/** /**
* return a new iterator which pointer n-next elements * return a new iterator which pointer n-next elements
* as well as operator- * as well as operator-
*/ */
iterator operator+(const int &n) const iterator operator+(const int &n) const {
{ iterator temp = *this;
//TODO temp.raw_pointer += n;
return temp;
} }
iterator operator-(const int &n) const iterator operator-(const int &n) const {
{ iterator temp = *this;
//TODO temp.raw_pointer -= n;
return temp;
} }
// return the distance between two iterators, // return the distance between two iterators,
// if these two iterators point to different vectors, throw invaild_iterator. // if these two iterators point to different vectors, throw invaild_iterator.
int operator-(const iterator &rhs) const int operator-(const iterator &rhs) const {
{ if (domain != rhs.domain) throw invalid_iterator();
//TODO return raw_pointer - rhs.raw_pointer;
} }
iterator& operator+=(const int &n) iterator &operator+=(const int &n) {
{ raw_pointer += n;
//TODO return *this;
} }
iterator& operator-=(const int &n) iterator &operator-=(const int &n) {
{ raw_pointer -= n;
//TODO return *this;
} }
/** /**
* TODO iter++ * TODO iter++
*/ */
iterator operator++(int) {} iterator operator++(int) {
iterator temp = *this;
raw_pointer++;
return temp;
}
/** /**
* TODO ++iter * TODO ++iter
*/ */
iterator& operator++() {} iterator &operator++() {
raw_pointer++;
return *this;
}
/** /**
* TODO iter-- * TODO iter--
*/ */
iterator operator--(int) {} iterator operator--(int) {
iterator temp = *this;
raw_pointer--;
return temp;
}
/** /**
* TODO --iter * TODO --iter
*/ */
iterator& operator--() {} iterator &operator--() {
raw_pointer--;
return *this;
}
/** /**
* TODO *it * TODO *it
*/ */
T& operator*() const{} T &operator*() const { return *raw_pointer; }
/** /**
* a operator to check whether two iterators are same (pointing to the same memory address). * a operator to check whether two iterators are same (pointing to the same memory address).
*/ */
bool operator==(const iterator &rhs) const {} bool operator==(const iterator &rhs) const { return raw_pointer == rhs.raw_pointer; }
bool operator==(const const_iterator &rhs) const {} bool operator==(const const_iterator &rhs) const { return raw_pointer == rhs.raw_pointer; }
/** /**
* some other operator for iterator. * some other operator for iterator.
*/ */
bool operator!=(const iterator &rhs) const {} bool operator!=(const iterator &rhs) const { return raw_pointer != rhs.raw_pointer; }
bool operator!=(const const_iterator &rhs) const {} bool operator!=(const const_iterator &rhs) const { return raw_pointer != rhs.raw_pointer; }
}; };
/** /**
* TODO * TODO
* has same function as iterator, just for a const object. * has same function as iterator, just for a const object.
*/ */
class const_iterator class const_iterator {
{ friend class vector<T>;
public: public:
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
using value_type = T; using value_type = T;
using pointer = T *; using pointer = T *;
using reference = T &; using reference = T &;
using iterator_category = std::output_iterator_tag; using iterator_category = std::random_access_iterator_tag;
private: private:
/*TODO*/ const vector<T> *domain;
const T *raw_pointer;
const_iterator(const vector<T> *domain, const T *raw_pointer) : domain(domain), raw_pointer(raw_pointer) {}
public:
/**
* return a new iterator which pointer n-next elements
* as well as operator-
*/
const_iterator operator+(const int &n) const {
const_iterator temp = *this;
temp.raw_pointer += n;
return temp;
}
const_iterator operator-(const int &n) const {
const_iterator temp = *this;
temp.raw_pointer -= n;
return temp;
}
// return the distance between two iterators,
// if these two iterators point to different vectors, throw invaild_iterator.
int operator-(const const_iterator &rhs) const {
if (domain != rhs.domain) throw invalid_iterator();
return raw_pointer - rhs.raw_pointer;
}
const_iterator &operator+=(const int &n) {
raw_pointer += n;
return *this;
}
const_iterator &operator-=(const int &n) {
raw_pointer -= n;
return *this;
}
/**
* TODO iter++
*/
const_iterator operator++(int) {
const_iterator temp = *this;
raw_pointer++;
return temp;
}
/**
* TODO ++iter
*/
const_iterator &operator++() {
raw_pointer++;
return *this;
}
/**
* TODO iter--
*/
const_iterator operator--(int) {
const_iterator temp = *this;
raw_pointer--;
return temp;
}
/**
* TODO --iter
*/
const_iterator &operator--() {
raw_pointer--;
return *this;
}
/**
* TODO *it
*/
const T &operator*() const { return *raw_pointer; }
/**
* a operator to check whether two iterators are same (pointing to the same memory address).
*/
bool operator==(const iterator &rhs) const { return raw_pointer == rhs.raw_pointer; }
bool operator==(const const_iterator &rhs) const { return raw_pointer == rhs.raw_pointer; }
/**
* some other operator for iterator.
*/
bool operator!=(const iterator &rhs) const { return raw_pointer != rhs.raw_pointer; }
bool operator!=(const const_iterator &rhs) const { return raw_pointer != rhs.raw_pointer; }
}; };
/** /**
* TODO Constructs * TODO Constructs
* At least two: default constructor, copy constructor * At least two: default constructor, copy constructor
*/ */
vector() {} vector() {
vector(const vector &other) {} raw_beg = alloc.allocate(1);
/** raw_end = raw_beg;
* TODO Destructor allocated_length = 1;
*/ current_length = 0;
~vector() {} }
vector(const vector &other) {
raw_beg = alloc.allocate(other.allocated_length);
raw_end = raw_beg + other.current_length;
allocated_length = other.allocated_length;
current_length = other.current_length;
for (size_t i = 0; i < current_length; ++i) {
alloc.construct(raw_beg + i, other.raw_beg[i]);
}
}
vector(vector &&other) noexcept {
raw_beg = other.raw_beg;
raw_end = other.raw_end;
allocated_length = other.allocated_length;
current_length = other.current_length;
other.raw_beg = nullptr;
other.raw_end = nullptr;
other.allocated_length = 0;
other.current_length = 0;
}
~vector() {
if (raw_beg != nullptr) {
for (size_t i = 0; i < current_length; ++i) {
alloc.destroy(raw_beg + i);
}
alloc.deallocate(raw_beg, allocated_length);
}
}
/** /**
* TODO Assignment operator * TODO Assignment operator
*/ */
vector &operator=(const vector &other) {} vector &operator=(const vector &other) {
if (this == &other) return *this;
if (raw_beg != nullptr) {
for (size_t i = 0; i < current_length; ++i) {
alloc.destroy(raw_beg + i);
}
alloc.deallocate(raw_beg, allocated_length);
}
raw_beg = alloc.allocate(other.allocated_length);
raw_end = raw_beg + other.current_length;
allocated_length = other.allocated_length;
current_length = other.current_length;
for (size_t i = 0; i < current_length; ++i) {
alloc.construct(raw_beg + i, other.raw_beg[i]);
}
return *this;
}
/** /**
* assigns specified element with bounds checking * assigns specified element with bounds checking
* throw index_out_of_bound if pos is not in [0, size) * throw index_out_of_bound if pos is not in [0, size)
*/ */
T & at(const size_t &pos) {} T &at(const size_t &pos) {
const T & at(const size_t &pos) const {} if (pos < 0 || pos >= current_length) throw index_out_of_bound();
return raw_beg[pos];
}
const T &at(const size_t &pos) const {
if (pos < 0 || pos >= current_length) throw index_out_of_bound();
return raw_beg[pos];
}
/** /**
* assigns specified element with bounds checking * assigns specified element with bounds checking
* throw index_out_of_bound if pos is not in [0, size) * throw index_out_of_bound if pos is not in [0, size)
* !!! Pay attentions * !!! Pay attentions
* In STL this operator does not check the boundary but I want you to do. * In STL this operator does not check the boundary but I want you to do.
*/ */
T & operator[](const size_t &pos) {} T &operator[](const size_t &pos) {
const T & operator[](const size_t &pos) const {} if (pos < 0 || pos >= current_length) throw index_out_of_bound();
return raw_beg[pos];
}
const T &operator[](const size_t &pos) const {
if (pos < 0 || pos >= current_length) throw index_out_of_bound();
return raw_beg[pos];
}
/** /**
* access the first element. * access the first element.
* throw container_is_empty if size == 0 * throw container_is_empty if size == 0
*/ */
const T & front() const {} const T &front() const {
if (current_length == 0) throw container_is_empty();
return raw_beg[0];
}
/** /**
* access the last element. * access the last element.
* throw container_is_empty if size == 0 * throw container_is_empty if size == 0
*/ */
const T & back() const {} const T &back() const {
if (current_length == 0) throw container_is_empty();
return raw_end[-1];
}
/** /**
* returns an iterator to the beginning. * returns an iterator to the beginning.
*/ */
iterator begin() {} iterator begin() { return iterator(this, raw_beg); }
const_iterator cbegin() const {} const_iterator cbegin() const { return const_iterator(this, raw_beg); }
/** /**
* returns an iterator to the end. * returns an iterator to the end.
*/ */
iterator end() {} iterator end() { return iterator(this, raw_end); }
const_iterator cend() const {} const_iterator cend() const { return const_iterator(this, raw_end); }
/** /**
* checks whether the container is empty * checks whether the container is empty
*/ */
bool empty() const {} bool empty() const { return current_length == 0; }
/** /**
* returns the number of elements * returns the number of elements
*/ */
size_t size() const {} size_t size() const { return current_length; }
/** /**
* clears the contents * clears the contents
*/ */
void clear() {} void clear() {
for (size_t i = 0; i < current_length; ++i) {
alloc.destroy(raw_beg + i);
}
current_length = 0;
alloc.deallocate(raw_beg, allocated_length);
raw_beg = alloc.allocate(1);
raw_end = raw_beg;
allocated_length = 1;
}
/** /**
* inserts value before pos * inserts value before pos
* returns an iterator pointing to the inserted value. * returns an iterator pointing to the inserted value.
*/ */
iterator insert(iterator pos, const T &value) {} iterator insert(iterator pos, const T &value) {
if (pos.raw_pointer < raw_beg || pos.raw_pointer > raw_end) throw invalid_iterator();
if (current_length == allocated_length) {
size_t new_allocated_length = allocated_length * 2;
T *new_raw_beg = alloc.allocate(new_allocated_length);
for (size_t i = 0; i < current_length; ++i) {
alloc.construct(new_raw_beg + i, std::move(raw_beg[i]));
alloc.destroy(raw_beg + i);
}
alloc.deallocate(raw_beg, allocated_length);
raw_beg = new_raw_beg;
raw_end = raw_beg + current_length;
allocated_length = new_allocated_length;
}
for (T *i = raw_end; i != pos.raw_pointer; --i) {
alloc.construct(i, std::move(*(i - 1)));
alloc.destroy(i - 1);
}
alloc.construct(pos.raw_pointer, value);
raw_end++;
current_length++;
return pos;
}
/** /**
* inserts value at index ind. * inserts value at index ind.
* after inserting, this->at(ind) == value * after inserting, this->at(ind) == value
* returns an iterator pointing to the inserted value. * returns an iterator pointing to the inserted value.
* throw index_out_of_bound if ind > size (in this situation ind can be size because after inserting the size will increase 1.) * throw index_out_of_bound if ind > size (in this situation ind can be size because after inserting the size will
* increase 1.)
*/ */
iterator insert(const size_t &ind, const T &value) {} iterator insert(const size_t &ind, const T &value) {
if (ind < 0 || ind > current_length) throw index_out_of_bound();
if (current_length == allocated_length) {
size_t new_allocated_length = allocated_length * 2;
T *new_raw_beg = alloc.allocate(new_allocated_length);
for (size_t i = 0; i < current_length; ++i) {
alloc.construct(new_raw_beg + i, std::move(raw_beg[i]));
alloc.destroy(raw_beg + i);
}
alloc.deallocate(raw_beg, allocated_length);
raw_beg = new_raw_beg;
raw_end = raw_beg + current_length;
allocated_length = new_allocated_length;
}
for (T *i = raw_end; i != raw_beg + ind; --i) {
alloc.construct(i, std::move(*(i - 1)));
alloc.destroy(i - 1);
}
alloc.construct(raw_beg + ind, value);
raw_end++;
current_length++;
return iterator(this, raw_beg + ind);
}
/** /**
* removes the element at pos. * removes the element at pos.
* return an iterator pointing to the following element. * return an iterator pointing to the following element.
* If the iterator pos refers the last element, the end() iterator is returned. * If the iterator pos refers the last element, the end() iterator is returned.
*/ */
iterator erase(iterator pos) {} iterator erase(iterator pos) {
if (pos.raw_pointer < raw_beg || pos.raw_pointer >= raw_end) throw invalid_iterator();
for (T *i = pos.raw_pointer; i != raw_end - 1; ++i) {
alloc.construct(i, std::move(*(i + 1)));
alloc.destroy(i + 1);
}
raw_end--;
current_length--;
return pos;
}
/** /**
* removes the element with index ind. * removes the element with index ind.
* return an iterator pointing to the following element. * return an iterator pointing to the following element.
* throw index_out_of_bound if ind >= size * throw index_out_of_bound if ind >= size
*/ */
iterator erase(const size_t &ind) {} iterator erase(const size_t &ind) {
if (ind < 0 || ind >= current_length) throw index_out_of_bound();
for (T *i = raw_beg + ind; i != raw_end - 1; ++i) {
alloc.construct(i, std::move(*(i + 1)));
alloc.destroy(i + 1);
}
raw_end--;
current_length--;
return iterator(this, raw_beg + ind);
}
/** /**
* adds an element to the end. * adds an element to the end.
*/ */
void push_back(const T &value) {} void push_back(const T &value) {
if (current_length == allocated_length) {
size_t new_allocated_length = allocated_length * 2;
T *new_raw_beg = alloc.allocate(new_allocated_length);
for (size_t i = 0; i < current_length; ++i) {
alloc.construct(new_raw_beg + i, std::move(raw_beg[i]));
alloc.destroy(raw_beg + i);
}
alloc.deallocate(raw_beg, allocated_length);
raw_beg = new_raw_beg;
raw_end = raw_beg + current_length;
allocated_length = new_allocated_length;
}
alloc.construct(raw_end, value);
raw_end++;
current_length++;
}
/** /**
* remove the last element from the end. * remove the last element from the end.
* throw container_is_empty if size() == 0 * throw container_is_empty if size() == 0
*/ */
void pop_back() {} void pop_back() {
if (current_length == 0) throw container_is_empty();
alloc.destroy(raw_end - 1);
raw_end--;
current_length--;
}
}; };
} // namespace sjtu
}
#endif #endif