├── CMakeLists.txt ├── test ├── CMakeLists.txt ├── access-test.cpp ├── capacity-test.cpp ├── iterator-test.cpp ├── operator-equals-test.cpp ├── constructor-test.cpp └── modifiers-test.cpp ├── LICENSE ├── README.md ├── .gitignore └── include └── rdsl └── devector.hpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(devector) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | add_library(${PROJECT_NAME} INTERFACE) 7 | 8 | target_include_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include/) 9 | 10 | enable_testing() 11 | 12 | add_subdirectory(test) 13 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(FetchContent) 2 | FetchContent_Declare( 3 | googletest 4 | URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip 5 | ) 6 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 7 | FetchContent_MakeAvailable(googletest) 8 | 9 | set(TESTS 10 | constructor-test.cpp 11 | operator-equals-test.cpp 12 | iterator-test.cpp 13 | capacity-test.cpp 14 | access-test.cpp 15 | modifiers-test.cpp 16 | ) 17 | 18 | add_executable( 19 | testing 20 | ${TESTS} 21 | ) 22 | target_link_libraries( 23 | testing 24 | gtest_main 25 | ) 26 | 27 | target_include_directories( 28 | testing 29 | PRIVATE 30 | ../include/ 31 | ) 32 | 33 | include(GoogleTest) 34 | gtest_discover_tests(testing) 35 | -------------------------------------------------------------------------------- /test/access-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rdsl/devector.hpp" 3 | 4 | TEST(AccessTest, ALL) { 5 | rdsl::devector vec{5 , 123, 543, 954, 123, 32, 54}; 6 | 7 | EXPECT_EQ(vec[0], 5); 8 | EXPECT_EQ(vec[1], 123); 9 | EXPECT_EQ(vec[2], 543); 10 | EXPECT_EQ(vec[3], 954); 11 | EXPECT_EQ(vec[4], 123); 12 | EXPECT_EQ(vec[5], 32); 13 | EXPECT_EQ(vec[6], 54); 14 | 15 | EXPECT_EQ(vec.at(0), 5); 16 | EXPECT_EQ(vec.at(1), 123); 17 | EXPECT_EQ(vec.at(2), 543); 18 | EXPECT_EQ(vec.at(3), 954); 19 | EXPECT_EQ(vec.at(4), 123); 20 | EXPECT_EQ(vec.at(5), 32); 21 | EXPECT_EQ(vec.at(6), 54); 22 | 23 | try{ 24 | vec.at(7); 25 | EXPECT_TRUE(false); 26 | }catch(const std::out_of_range& e){} 27 | 28 | EXPECT_EQ(vec.front(), 5); 29 | EXPECT_EQ(vec.back(), 54); 30 | } -------------------------------------------------------------------------------- /test/capacity-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rdsl/devector.hpp" 3 | 4 | TEST(CapacityTest, ALL) { 5 | rdsl::devector vec(10,20); 6 | 7 | EXPECT_EQ(vec.size(), 10); 8 | EXPECT_FALSE(vec.empty()); 9 | EXPECT_GE(vec.capacity(), 10); 10 | vec.resize(20, 40); 11 | EXPECT_EQ(vec.size(), 20); 12 | EXPECT_GE(vec.capacity(), 20); 13 | EXPECT_FALSE(vec.empty()); 14 | 15 | vec.reserve(40); 16 | EXPECT_EQ(vec.size(), 20); 17 | EXPECT_GE(vec.capacity(), 40); 18 | EXPECT_FALSE(vec.empty()); 19 | 20 | vec.shrink_to_fit(); 21 | EXPECT_EQ(vec.size(), 20); 22 | EXPECT_EQ(vec.capacity(), 20); 23 | EXPECT_FALSE(vec.empty()); 24 | 25 | vec.resize(10, 3); 26 | EXPECT_EQ(vec.size(), 10); 27 | EXPECT_GE(vec.capacity(), 10); 28 | EXPECT_FALSE(vec.empty()); 29 | 30 | vec.reserve(5); 31 | EXPECT_EQ(vec.size(), 10); 32 | EXPECT_GE(vec.capacity(), 10); 33 | EXPECT_FALSE(vec.empty()); 34 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Valasiadis Fotios 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/iterator-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rdsl/devector.hpp" 3 | 4 | TEST(IteratorTest, Normal) { 5 | rdsl::devector vec0{1, 2, 3}; 6 | 7 | auto it = vec0.begin(); 8 | 9 | EXPECT_EQ(*it, 1); 10 | EXPECT_EQ(it[1], 2); 11 | EXPECT_EQ(it[2], 3); 12 | EXPECT_EQ(*++it, 2); 13 | EXPECT_EQ(it[-1], 1); 14 | it -= 1; 15 | EXPECT_EQ(it[0], 1); 16 | it += 2; 17 | EXPECT_EQ(it[0], 3); 18 | EXPECT_EQ(*it--, 3); 19 | EXPECT_EQ(*it, 2); 20 | 21 | auto it1 = vec0.end(); 22 | 23 | EXPECT_EQ(it1 - it, 2); 24 | 25 | //==, != 26 | it = vec0.begin(); 27 | EXPECT_NE(it, it1); 28 | it = vec0.end(); 29 | EXPECT_EQ(it, it1); 30 | 31 | //* 32 | it = vec0.begin(); 33 | EXPECT_EQ(*it, 1); 34 | 35 | //<, >, <=, >= 36 | EXPECT_LT(it, it1); 37 | EXPECT_GT(it1, it); 38 | EXPECT_LE(it, it1); 39 | EXPECT_GE(it1, it); 40 | 41 | it = vec0.end(); 42 | EXPECT_LE(it, it1); 43 | EXPECT_GE(it, it1); 44 | } 45 | 46 | TEST(IteratorTest, Reverse) { 47 | rdsl::devector vec0{1, 2, 3}; 48 | 49 | auto it = vec0.rbegin(); 50 | auto it1 = vec0.rend(); 51 | 52 | EXPECT_EQ(*it++, 3); 53 | EXPECT_EQ(*it++, 2); 54 | EXPECT_EQ(*it++, 1); 55 | 56 | EXPECT_EQ(*--it1, 1); 57 | EXPECT_EQ(*--it1, 2); 58 | EXPECT_EQ(*--it1, 3); 59 | } -------------------------------------------------------------------------------- /test/operator-equals-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rdsl/devector.hpp" 3 | 4 | TEST(OperatorEqualsTest, copyOperatorEquals) { 5 | rdsl::devector vec0(10,20); 6 | 7 | rdsl::devector vec1; 8 | vec1 = vec0; 9 | ASSERT_NE(vec1.data(), nullptr); 10 | EXPECT_EQ(vec1.size(), 10); 11 | EXPECT_GE(vec1.capacity(), 10); 12 | ASSERT_FALSE(vec0.empty()); 13 | 14 | for(const int& i: vec1){ 15 | ASSERT_EQ(i, 20); 16 | } 17 | 18 | rdsl::devector vec2(1000,432432); 19 | vec1 = vec2; 20 | ASSERT_NE(vec1.data(), nullptr); 21 | EXPECT_EQ(vec1.size(), 1000); 22 | EXPECT_GE(vec1.capacity(), 1000); 23 | ASSERT_FALSE(vec0.empty()); 24 | 25 | for(const int& i: vec1){ 26 | ASSERT_EQ(i, 432432); 27 | } 28 | 29 | vec2.assign(500, 343); 30 | vec1 = vec2; 31 | ASSERT_NE(vec1.data(), nullptr); 32 | EXPECT_EQ(vec1.size(), 500); 33 | EXPECT_GE(vec1.capacity(), 500); 34 | ASSERT_FALSE(vec0.empty()); 35 | 36 | for(const int& i: vec1){ 37 | ASSERT_EQ(i, 343); 38 | } 39 | } 40 | 41 | TEST(OperatorEqualsTest, moveOperatorEquals) { 42 | rdsl::devector vec0(10,20); 43 | 44 | rdsl::devector vec1; 45 | vec1 = std::move(vec0); 46 | ASSERT_NE(vec1.data(), nullptr); 47 | EXPECT_EQ(vec1.size(), 10); 48 | EXPECT_GE(vec1.capacity(), 10); 49 | ASSERT_FALSE(vec1.empty()); 50 | 51 | for(const int& i: vec1){ 52 | ASSERT_EQ(i, 20); 53 | } 54 | 55 | EXPECT_EQ(vec0.data(), nullptr); 56 | EXPECT_EQ(vec0.size(), 0); 57 | EXPECT_EQ(vec0.capacity(), 0); 58 | EXPECT_TRUE(vec0.empty()); 59 | } 60 | 61 | TEST(OperatorEqualsTest, ilOperatorEquals) { 62 | rdsl::devector vec0; 63 | vec0 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 64 | 65 | ASSERT_NE(vec0.data(), nullptr); 66 | EXPECT_EQ(vec0.size(), 10); 67 | EXPECT_GE(vec0.capacity(), 10); 68 | ASSERT_FALSE(vec0.empty()); 69 | 70 | for(int i = 0; i < 10; i = i + 1){ 71 | ASSERT_EQ(i, vec0[i]); 72 | } 73 | } -------------------------------------------------------------------------------- /test/constructor-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rdsl/devector.hpp" 3 | 4 | 5 | TEST(ConstructorTest, defaultConstructor) { 6 | rdsl::devector vec; 7 | EXPECT_EQ(vec.data(), nullptr); 8 | EXPECT_EQ(vec.size(), 0); 9 | EXPECT_EQ(vec.capacity(), 0); 10 | EXPECT_TRUE(vec.empty()); 11 | } 12 | 13 | TEST(ConstructorTest, fillConstructor) { 14 | rdsl::devector vec0(10); 15 | EXPECT_NE(vec0.data(), nullptr); 16 | EXPECT_EQ(vec0.size(), 10); 17 | EXPECT_GE(vec0.capacity(), 10); 18 | EXPECT_FALSE(vec0.empty()); 19 | 20 | rdsl::devector vec1(15, 20); 21 | EXPECT_NE(vec1.data(), nullptr); 22 | EXPECT_EQ(vec1.size(), 15); 23 | EXPECT_GE(vec1.capacity(), 15); 24 | EXPECT_FALSE(vec1.empty()); 25 | 26 | for(const int& i: vec1){ 27 | EXPECT_EQ(i, 20); 28 | } 29 | } 30 | 31 | TEST(ConstructorTest, rangeConstructor) { 32 | rdsl::devector vec0(10,20); 33 | 34 | rdsl::devector vec1(vec0.begin(), vec0.end(), vec0.size()); 35 | ASSERT_NE(vec1.data(), nullptr); 36 | EXPECT_EQ(vec1.size(), 10); 37 | EXPECT_GE(vec1.capacity(), 10); 38 | ASSERT_FALSE(vec0.empty()); 39 | 40 | for(const int& i: vec1){ 41 | ASSERT_EQ(i, 20); 42 | } 43 | 44 | rdsl::devector vec2(vec1.begin(), vec1.end()); 45 | ASSERT_NE(vec2.data(), nullptr); 46 | EXPECT_EQ(vec2.size(), 10); 47 | EXPECT_GE(vec2.capacity(), 10); 48 | ASSERT_FALSE(vec2.empty()); 49 | 50 | for(const int& i: vec2){ 51 | ASSERT_EQ(i, 20); 52 | } 53 | } 54 | 55 | TEST(ConstructorTest, copyConstructor) { 56 | rdsl::devector vec0(10,20); 57 | 58 | rdsl::devector vec1(vec0); 59 | ASSERT_NE(vec1.data(), nullptr); 60 | EXPECT_EQ(vec1.size(), 10); 61 | EXPECT_GE(vec1.capacity(), 10); 62 | ASSERT_FALSE(vec0.empty()); 63 | 64 | for(const int& i: vec1){ 65 | ASSERT_EQ(i, 20); 66 | } 67 | } 68 | 69 | TEST(ConstructorTest, moveConstructor) { 70 | rdsl::devector vec0(10,20); 71 | 72 | rdsl::devector vec1(std::move(vec0)); 73 | ASSERT_NE(vec1.data(), nullptr); 74 | EXPECT_EQ(vec1.size(), 10); 75 | EXPECT_GE(vec1.capacity(), 10); 76 | ASSERT_FALSE(vec1.empty()); 77 | 78 | for(const int& i: vec1){ 79 | ASSERT_EQ(i, 20); 80 | } 81 | 82 | EXPECT_EQ(vec0.data(), nullptr); 83 | EXPECT_EQ(vec0.size(), 0); 84 | EXPECT_EQ(vec0.capacity(), 0); 85 | EXPECT_TRUE(vec0.empty()); 86 | } 87 | 88 | TEST(ConstructorTest, ilConstructor) { 89 | rdsl::devector vec0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 90 | ASSERT_NE(vec0.data(), nullptr); 91 | EXPECT_EQ(vec0.size(), 10); 92 | EXPECT_GE(vec0.capacity(), 10); 93 | ASSERT_FALSE(vec0.empty()); 94 | 95 | for(int i = 0; i < 10; i = i + 1){ 96 | ASSERT_EQ(i, vec0[i]); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # devector 2 | Header-only **double ended vector** implementation for efficient insertions/removals at both the start & end of it at the expense of an extra pointer. 3 | 4 | Following C++ standard with slight modifications. 5 | 6 | Currently supports up to C++14. 7 | 8 | ## Implementation details 9 | **devector** keeps a dynamic array internally which it uses to store its objects. It differs from *std::vector* from the fact that *begin()* isn't necessarily pointing to the start of the array, it's instead up to the user to decide. 10 | 11 | A simple visualisation: 12 | 13 | ![image](https://user-images.githubusercontent.com/72366635/153786421-6ba94e57-47f1-42d2-a190-d12f2d003eeb.png) 14 | 15 | In order to control where *begin* is placed, a third template parameter named **OffsetBy** is introduced which **should** have a method with the following signature: 16 | 17 | `size_t off_by(size_t free_blocks);` 18 | 19 | The one and only parameter is the count of free slots inside the array at any given moment the method is called. 20 | It should return an integer which is going to be **begin**'s offset from **array_begin**. You are free to make the method **static, const, noexcept** or whatever else you desire. The default implementation is this: 21 | 22 | ![image](https://user-images.githubusercontent.com/72366635/153787147-86a15cce-aa3a-4b00-97b8-93fb419e699d.png) 23 | 24 | The offset is used upon reallocations, assignments of any sort, or shifting caused from operations such as *insert*, *erase* *operator=* etc... 25 | 26 | A general rule of thumb is that whenever an operation has to move and/or copy things around, devector will automatically place them in the desired position according to the offset. 27 | 28 | 29 | As a consequence of the above, if you make a custom OffsetBy class that always returns 0 as offset, the behavior should be exactly the same as **std::vector**. 30 | 31 | If needed in the future **offset_by_traits** shall also be introduced. 32 | ## Which methods differ from std::vector and how 33 | 34 | This container implements the very same methods the [standard](https://en.cppreference.com/w/cpp/container/vector) does, following exception safety rules, iterator validity and even thread-safety wherever possible. The differences are in fact: 35 | 36 | Any operation that causes shifting, like **insert at any position besides begin & end, erase at any position besides begin & end, emplace at any position besides begin & end** will now not only invalidate the iterators following **pos**(the position iterator each of these functions take as argument), but the whole [begin,end) set except for very specific situations which you shouldn't rely upon. 37 | 38 | New methods are introduced, here is a list: 39 | * resize_front() 40 | * resize_back() 41 | * push_front() 42 | * pop_front() 43 | * emplace_front() 44 | * get_offset_by() 45 | 46 | each of which does exactly the same their x_back() pair does but for the front instead. resize() still exists and defaults to resize_back(). 47 | 48 | 49 | Every constructor or operation that previously had an optional **allocator_type& alloc** parameter now also has an optional **offset_by_type& off_by** type. 50 | 51 | 52 | ## Collaborate 53 | You are absolutely welcome to report bugs, contribute by solving issues, or even help build C++14, C++17, and C++20 versions. 54 | 55 | ## About 56 | Licenced under MIT Licence. 57 | -------------------------------------------------------------------------------- /test/modifiers-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rdsl/devector.hpp" 3 | 4 | struct input_it: public std::iterator { 5 | input_it(const input_it&) = default; 6 | input_it(input_it&&) noexcept = default; 7 | input_it& operator=(const input_it&) = default; 8 | input_it& operator=(input_it&&) = default; 9 | 10 | explicit input_it(int state = 0): state(state) {} 11 | 12 | int state; 13 | 14 | int operator*() { return state; } 15 | input_it& operator++() { ++state; return *this; } 16 | input_it operator++(int) { ++state; return input_it(state - 1); } 17 | 18 | bool operator!=(const input_it& other) { return state != other.state; } 19 | }; 20 | 21 | TEST(ModifiersTest, AssignTest) { 22 | rdsl::devector vec(10,20); 23 | 24 | rdsl::devector vec1; 25 | 26 | vec1.assign(vec.begin(), vec.size()); 27 | EXPECT_EQ(vec1.size(), 10); 28 | EXPECT_FALSE(vec1.empty()); 29 | EXPECT_GE(vec1.capacity(), 10); 30 | for(const int& i: vec1){ 31 | EXPECT_EQ(i, 20); 32 | } 33 | 34 | vec1.assign(30, 23); 35 | EXPECT_EQ(vec1.size(), 30); 36 | EXPECT_FALSE(vec1.empty()); 37 | EXPECT_GE(vec1.capacity(), 30); 38 | for(const int& i: vec1){ 39 | EXPECT_EQ(i, 23); 40 | } 41 | 42 | vec1.assign({3, 4, 5, 6, 7}); 43 | EXPECT_EQ(vec1.size(), 5); 44 | EXPECT_FALSE(vec1.empty()); 45 | EXPECT_GE(vec1.capacity(), 5); 46 | 47 | EXPECT_EQ(vec1[0], 3); 48 | EXPECT_EQ(vec1[1], 4); 49 | EXPECT_EQ(vec1[2], 5); 50 | EXPECT_EQ(vec1[3], 6); 51 | EXPECT_EQ(vec1[4], 7); 52 | } 53 | 54 | TEST(ModifiersTest, PushPopBackFrontTest) { 55 | rdsl::devector vec; 56 | 57 | vec.push_front(10); 58 | vec.push_back(20); 59 | vec.push_front(30); 60 | vec.push_front(40); 61 | vec.push_back(50); 62 | 63 | EXPECT_EQ(vec.size(), 5); 64 | EXPECT_FALSE(vec.empty()); 65 | EXPECT_GE(vec.capacity(), 5); 66 | 67 | EXPECT_EQ(vec[0], 40); 68 | EXPECT_EQ(vec[1], 30); 69 | EXPECT_EQ(vec[2], 10); 70 | EXPECT_EQ(vec[3], 20); 71 | EXPECT_EQ(vec[4], 50); 72 | 73 | vec.pop_front(); 74 | vec.pop_front(); 75 | vec.pop_back(); 76 | 77 | EXPECT_EQ(vec.size(), 2); 78 | EXPECT_FALSE(vec.empty()); 79 | EXPECT_GE(vec.capacity(), 2); 80 | 81 | EXPECT_EQ(vec[0], 10); 82 | EXPECT_EQ(vec[1], 20); 83 | } 84 | 85 | TEST(ModifiersTest, InsertEraseTest) { 86 | rdsl::devector vec{3, 65, 543, 13, 5432, 954, 4321}; 87 | 88 | vec.insert(vec.end(), 13, 20); 89 | EXPECT_EQ(vec.size(), 20); 90 | EXPECT_FALSE(vec.empty()); 91 | EXPECT_GE(vec.capacity(), 20); 92 | for(int i = 7; i < 20; i = i + 1){ 93 | EXPECT_EQ(vec[i], 20); 94 | } 95 | 96 | vec.insert(vec.begin(), {23, 54, 94, 432}); 97 | EXPECT_EQ(vec.size(), 24); 98 | EXPECT_FALSE(vec.empty()); 99 | EXPECT_GE(vec.capacity(), 24); 100 | 101 | EXPECT_EQ(vec[0], 23); 102 | EXPECT_EQ(vec[1], 54); 103 | EXPECT_EQ(vec[2], 94); 104 | EXPECT_EQ(vec[3], 432); 105 | 106 | rdsl::devector temp{72,53,4324,653,123}; 107 | 108 | vec.insert(vec.begin() + 4, temp.begin(), temp.size()); 109 | EXPECT_EQ(vec.size(), 29); 110 | EXPECT_FALSE(vec.empty()); 111 | EXPECT_GE(vec.capacity(), 29); 112 | 113 | vec.insert(vec.begin() + 9, 3, 2); 114 | EXPECT_EQ(vec.size(), 32); 115 | EXPECT_FALSE(vec.empty()); 116 | EXPECT_GE(vec.capacity(), 32); 117 | 118 | rdsl::devector result{23, 54, 94, 432, 72, 53, 4324, 653, 123, 2, 2, 2, 3, 65, 543, 13, 5432, 954,4321}; 119 | for(int i = 0; i < 19; i = i + 1){ 120 | EXPECT_EQ(vec[i], result[i]); 121 | } 122 | for(int i = 19; i < 32; i = i + 1){ 123 | EXPECT_EQ(vec[i], 20); 124 | } 125 | 126 | vec.erase(vec.begin()); 127 | vec.erase(vec.end() - 1); 128 | vec.erase(vec.begin() + 3, vec.end()); 129 | EXPECT_EQ(vec.size(), 3); 130 | EXPECT_FALSE(vec.empty()); 131 | EXPECT_GE(vec.capacity(), 3); 132 | 133 | EXPECT_EQ(vec[0], 54); 134 | EXPECT_EQ(vec[1], 94); 135 | EXPECT_EQ(vec[2], 432); 136 | 137 | vec.emplace_back(4); 138 | vec.emplace_front(9); 139 | vec.emplace(vec.begin() + 2, 13); 140 | 141 | EXPECT_EQ(vec.size(), 6); 142 | EXPECT_FALSE(vec.empty()); 143 | EXPECT_GE(vec.capacity(), 6); 144 | 145 | EXPECT_EQ(vec[0], 9); 146 | EXPECT_EQ(vec[1], 54); 147 | EXPECT_EQ(vec[2], 13); 148 | EXPECT_EQ(vec[3], 94); 149 | EXPECT_EQ(vec[4], 432); 150 | EXPECT_EQ(vec[5], 4); 151 | 152 | vec.insert(vec.begin() + 2, input_it(), input_it(10)); 153 | 154 | EXPECT_EQ(vec.size(), 16); 155 | EXPECT_FALSE(vec.empty()); 156 | EXPECT_GE(vec.capacity(), 16); 157 | 158 | EXPECT_EQ(vec[0], 9); 159 | EXPECT_EQ(vec[1], 54); 160 | EXPECT_EQ(vec[2], 0); 161 | EXPECT_EQ(vec[3], 1); 162 | EXPECT_EQ(vec[4], 2); 163 | EXPECT_EQ(vec[5], 3); 164 | EXPECT_EQ(vec[6], 4); 165 | EXPECT_EQ(vec[7], 5); 166 | EXPECT_EQ(vec[8], 6); 167 | EXPECT_EQ(vec[9], 7); 168 | EXPECT_EQ(vec[10], 8); 169 | EXPECT_EQ(vec[11], 9); 170 | EXPECT_EQ(vec[12], 13); 171 | EXPECT_EQ(vec[13], 94); 172 | EXPECT_EQ(vec[14], 432); 173 | EXPECT_EQ(vec[15], 4); 174 | } 175 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ##### Windows 2 | # Windows thumbnail cache files 3 | Thumbs.db 4 | Thumbs.db:encryptable 5 | ehthumbs.db 6 | ehthumbs_vista.db 7 | 8 | # Dump file 9 | *.stackdump 10 | 11 | # Folder config file 12 | [Dd]esktop.ini 13 | 14 | # Recycle Bin used on file shares 15 | $RECYCLE.BIN/ 16 | 17 | # Windows Installer files 18 | *.cab 19 | *.msi 20 | *.msix 21 | *.msm 22 | *.msp 23 | 24 | # Windows shortcuts 25 | *.lnk 26 | 27 | ##### Linux 28 | *~ 29 | 30 | # temporary files which can be created if a process still has a handle open of a deleted file 31 | .fuse_hidden* 32 | 33 | # KDE directory preferences 34 | .directory 35 | 36 | # Linux trash folder which might appear on any partition or disk 37 | .Trash-* 38 | 39 | # .nfs files are created when an open file is removed but is still being accessed 40 | .nfs* 41 | 42 | ##### MacOS 43 | # General 44 | .DS_Store 45 | .AppleDouble 46 | .LSOverride 47 | 48 | # Icon must end with two \r 49 | Icon 50 | 51 | # Thumbnails 52 | ._* 53 | 54 | # Files that might appear in the root of a volume 55 | .DocumentRevisions-V100 56 | .fseventsd 57 | .Spotlight-V100 58 | .TemporaryItems 59 | .Trashes 60 | .VolumeIcon.icns 61 | .com.apple.timemachine.donotpresent 62 | 63 | # Directories potentially created on remote AFP share 64 | .AppleDB 65 | .AppleDesktop 66 | Network Trash Folder 67 | Temporary Items 68 | .apdisk 69 | 70 | ##### Android 71 | # Built application files 72 | *.apk 73 | *.ap_ 74 | *.aab 75 | 76 | # Files for the ART/Dalvik VM 77 | *.dex 78 | 79 | # Java class files 80 | *.class 81 | 82 | # Generated files 83 | bin/ 84 | gen/ 85 | out/ 86 | # Uncomment the following line in case you need and you don't have the release build type files in your app 87 | # release/ 88 | 89 | # Gradle files 90 | .gradle/ 91 | build/ 92 | 93 | # Local configuration file (sdk path, etc) 94 | local.properties 95 | 96 | # Proguard folder generated by Eclipse 97 | proguard/ 98 | 99 | # Log Files 100 | *.log 101 | 102 | # Android Studio Navigation editor temp files 103 | .navigation/ 104 | 105 | # Android Studio captures folder 106 | captures/ 107 | 108 | # IntelliJ 109 | *.iml 110 | .idea/workspace.xml 111 | .idea/tasks.xml 112 | .idea/gradle.xml 113 | .idea/assetWizardSettings.xml 114 | .idea/dictionaries 115 | .idea/libraries 116 | # Android Studio 3 in .gitignore file. 117 | .idea/caches 118 | .idea/modules.xml 119 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 120 | .idea/navEditor.xml 121 | 122 | # Keystore files 123 | # Uncomment the following lines if you do not want to check your keystore files in. 124 | #*.jks 125 | #*.keystore 126 | 127 | # External native build folder generated in Android Studio 2.2 and later 128 | .externalNativeBuild 129 | 130 | # Google Services (e.g. APIs or Firebase) 131 | # google-services.json 132 | 133 | # Freeline 134 | freeline.py 135 | freeline/ 136 | freeline_project_description.json 137 | 138 | # fastlane 139 | fastlane/report.xml 140 | fastlane/Preview.html 141 | fastlane/screenshots 142 | fastlane/test_output 143 | fastlane/readme.md 144 | 145 | # Version control 146 | vcs.xml 147 | 148 | # lint 149 | lint/intermediates/ 150 | lint/generated/ 151 | lint/outputs/ 152 | lint/tmp/ 153 | # lint/reports/ 154 | 155 | ##### Backup 156 | *.bak 157 | *.gho 158 | *.ori 159 | *.orig 160 | *.tmp 161 | 162 | ##### GPG 163 | secring.* 164 | 165 | ##### Dropbox 166 | # Dropbox settings and caches 167 | .dropbox 168 | .dropbox.attr 169 | .dropbox.cache 170 | 171 | ##### SynopsysVCS 172 | # Waveform formats 173 | *.vcd 174 | *.vpd 175 | *.evcd 176 | *.fsdb 177 | 178 | # Default name of the simulation executable. A different name can be 179 | # specified with this switch (the associated daidir database name is 180 | # also taken from here): -o / 181 | simv 182 | 183 | # Generated for Verilog and VHDL top configs 184 | simv.daidir/ 185 | simv.db.dir/ 186 | 187 | # Infrastructure necessary to co-simulate SystemC models with 188 | # Verilog/VHDL models. An alternate directory may be specified with this 189 | # switch: -Mdir= 190 | csrc/ 191 | 192 | # Log file - the following switch allows to specify the file that will be 193 | # used to write all messages from simulation: -l 194 | *.log 195 | 196 | # Coverage results (generated with urg) and database location. The 197 | # following switch can also be used: urg -dir .vdb 198 | simv.vdb/ 199 | urgReport/ 200 | 201 | # DVE and UCLI related files. 202 | DVEfiles/ 203 | ucli.key 204 | 205 | # When the design is elaborated for DirectC, the following file is created 206 | # with declarations for C/C++ functions. 207 | vc_hdrs.h 208 | 209 | ##### SVN 210 | .svn/ 211 | 212 | ##### Mercurial 213 | .hg/ 214 | .hgignore 215 | .hgsigs 216 | .hgsub 217 | .hgsubstate 218 | .hgtags 219 | 220 | ##### Bazaar 221 | .bzr/ 222 | .bzrignore 223 | 224 | ##### CVS 225 | /CVS/* 226 | **/CVS/* 227 | .cvsignore 228 | */.cvsignore 229 | 230 | ##### TortoiseGit 231 | # Project-level settings 232 | /.tgitconfig 233 | 234 | ##### PuTTY 235 | # Private key 236 | *.ppk 237 | 238 | ##### Vim 239 | # Swap 240 | [._]*.s[a-v][a-z] 241 | !*.svg # comment out if you don't need vector files 242 | [._]*.sw[a-p] 243 | [._]s[a-rt-v][a-z] 244 | [._]ss[a-gi-z] 245 | [._]sw[a-p] 246 | 247 | # Session 248 | Session.vim 249 | Sessionx.vim 250 | 251 | # Temporary 252 | .netrwhist 253 | *~ 254 | # Auto-generated tag files 255 | tags 256 | # Persistent undo 257 | [._]*.un~ 258 | 259 | ##### Emacs 260 | # -*- mode: gitignore; -*- 261 | *~ 262 | \#*\# 263 | /.emacs.desktop 264 | /.emacs.desktop.lock 265 | *.elc 266 | auto-save-list 267 | tramp 268 | .\#* 269 | 270 | # Org-mode 271 | .org-id-locations 272 | *_archive 273 | 274 | # flymake-mode 275 | *_flymake.* 276 | 277 | # eshell files 278 | /eshell/history 279 | /eshell/lastdir 280 | 281 | # elpa packages 282 | /elpa/ 283 | 284 | # reftex files 285 | *.rel 286 | 287 | # AUCTeX auto folder 288 | /auto/ 289 | 290 | # cask packages 291 | .cask/ 292 | dist/ 293 | 294 | # Flycheck 295 | flycheck_*.el 296 | 297 | # server auth directory 298 | /server/ 299 | 300 | # projectiles files 301 | .projectile 302 | 303 | # directory configuration 304 | .dir-locals.el 305 | 306 | # network security 307 | /network-security.data 308 | 309 | ##### SublimeText 310 | # Cache files for Sublime Text 311 | *.tmlanguage.cache 312 | *.tmPreferences.cache 313 | *.stTheme.cache 314 | 315 | # Workspace files are user-specific 316 | *.sublime-workspace 317 | 318 | # Project files should be checked into the repository, unless a significant 319 | # proportion of contributors will probably not be using Sublime Text 320 | # *.sublime-project 321 | 322 | # SFTP configuration file 323 | sftp-config.json 324 | sftp-config-alt*.json 325 | 326 | # Package control specific files 327 | Package Control.last-run 328 | Package Control.ca-list 329 | Package Control.ca-bundle 330 | Package Control.system-ca-bundle 331 | Package Control.cache/ 332 | Package Control.ca-certs/ 333 | Package Control.merged-ca-bundle 334 | Package Control.user-ca-bundle 335 | oscrypto-ca-bundle.crt 336 | bh_unicode_properties.cache 337 | 338 | # Sublime-github package stores a github token in this file 339 | # https://packagecontrol.io/packages/sublime-github 340 | GitHub.sublime-settings 341 | 342 | ##### Notepad++ 343 | # Notepad++ backups # 344 | *.bak 345 | 346 | ##### TextMate 347 | *.tmproj 348 | *.tmproject 349 | tmtags 350 | 351 | ##### VisualStudioCode 352 | .vscode/* 353 | .vscode 354 | #!.vscode/settings.json 355 | #!.vscode/tasks.json 356 | #!.vscode/launch.json 357 | #!.vscode/extensions.json 358 | *.code-workspace 359 | 360 | # Local History for Visual Studio Code 361 | .history/ 362 | 363 | ##### NetBeans 364 | **/nbproject/private/ 365 | **/nbproject/Makefile-*.mk 366 | **/nbproject/Package-*.bash 367 | build/ 368 | nbbuild/ 369 | dist/ 370 | nbdist/ 371 | .nb-gradle/ 372 | 373 | ##### JetBrains 374 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 375 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 376 | 377 | .idea 378 | # User-specific stuff 379 | .idea/**/workspace.xml 380 | .idea/**/tasks.xml 381 | .idea/**/usage.statistics.xml 382 | .idea/**/dictionaries 383 | .idea/**/shelf 384 | 385 | # Generated files 386 | .idea/**/contentModel.xml 387 | 388 | # Sensitive or high-churn files 389 | .idea/**/dataSources/ 390 | .idea/**/dataSources.ids 391 | .idea/**/dataSources.local.xml 392 | .idea/**/sqlDataSources.xml 393 | .idea/**/dynamic.xml 394 | .idea/**/uiDesigner.xml 395 | .idea/**/dbnavigator.xml 396 | 397 | # Gradle 398 | .idea/**/gradle.xml 399 | .idea/**/libraries 400 | 401 | # Gradle and Maven with auto-import 402 | # When using Gradle or Maven with auto-import, you should exclude module files, 403 | # since they will be recreated, and may cause churn. Uncomment if using 404 | # auto-import. 405 | # .idea/artifacts 406 | # .idea/compiler.xml 407 | # .idea/jarRepositories.xml 408 | # .idea/modules.xml 409 | # .idea/*.iml 410 | # .idea/modules 411 | # *.iml 412 | # *.ipr 413 | 414 | # CMake 415 | cmake-build-*/ 416 | 417 | # Mongo Explorer plugin 418 | .idea/**/mongoSettings.xml 419 | 420 | # File-based project format 421 | *.iws 422 | 423 | # IntelliJ 424 | out/ 425 | 426 | # mpeltonen/sbt-idea plugin 427 | .idea_modules/ 428 | 429 | # JIRA plugin 430 | atlassian-ide-plugin.xml 431 | 432 | # Cursive Clojure plugin 433 | .idea/replstate.xml 434 | 435 | # Crashlytics plugin (for Android Studio and IntelliJ) 436 | com_crashlytics_export_strings.xml 437 | crashlytics.properties 438 | crashlytics-build.properties 439 | fabric.properties 440 | 441 | # Editor-based Rest Client 442 | .idea/httpRequests 443 | 444 | # Android studio 3.1+ serialized cache file 445 | .idea/caches/build_file_checksums.ser 446 | 447 | ##### Eclipse 448 | .metadata 449 | bin/ 450 | tmp/ 451 | *.tmp 452 | *.bak 453 | *.swp 454 | *~.nib 455 | local.properties 456 | .settings/ 457 | .loadpath 458 | .recommenders 459 | 460 | # External tool builders 461 | .externalToolBuilders/ 462 | 463 | # Locally stored "Eclipse launch configurations" 464 | *.launch 465 | 466 | # PyDev specific (Python IDE for Eclipse) 467 | *.pydevproject 468 | 469 | # CDT-specific (C/C++ Development Tooling) 470 | .cproject 471 | 472 | # CDT- autotools 473 | .autotools 474 | 475 | # Java annotation processor (APT) 476 | .factorypath 477 | 478 | # PDT-specific (PHP Development Tools) 479 | .buildpath 480 | 481 | # sbteclipse plugin 482 | .target 483 | 484 | # Tern plugin 485 | .tern-project 486 | 487 | # TeXlipse plugin 488 | .texlipse 489 | 490 | # STS (Spring Tool Suite) 491 | .springBeans 492 | 493 | # Code Recommenders 494 | .recommenders/ 495 | 496 | # Annotation Processing 497 | .apt_generated/ 498 | .apt_generated_test/ 499 | 500 | # Scala IDE specific (Scala & Java development for Eclipse) 501 | .cache-main 502 | .scala_dependencies 503 | .worksheet 504 | 505 | # Uncomment this line if you wish to ignore the project description file. 506 | # Typically, this file would be tracked if it contains build/dependency configurations: 507 | #.project 508 | 509 | ##### Qt 510 | # C++ objects and libs 511 | *.slo 512 | *.lo 513 | *.o 514 | *.a 515 | *.la 516 | *.lai 517 | *.so 518 | *.so.* 519 | *.dll 520 | *.dylib 521 | 522 | # Qt-es 523 | object_script.*.Release 524 | object_script.*.Debug 525 | *_plugin_import.cpp 526 | /.qmake.cache 527 | /.qmake.stash 528 | *.pro.user 529 | *.pro.user.* 530 | *.qbs.user 531 | *.qbs.user.* 532 | *.moc 533 | moc_*.cpp 534 | moc_*.h 535 | qrc_*.cpp 536 | ui_*.h 537 | *.qmlc 538 | *.jsc 539 | Makefile* 540 | *build-* 541 | *.qm 542 | *.prl 543 | 544 | # Qt unit tests 545 | target_wrapper.* 546 | 547 | # QtCreator 548 | *.autosave 549 | 550 | # QtCreator Qml 551 | *.qmlproject.user 552 | *.qmlproject.user.* 553 | 554 | # QtCreator CMake 555 | CMakeLists.txt.user* 556 | 557 | # QtCreator 4.8< compilation database 558 | compile_commands.json 559 | 560 | # QtCreator local machine specific files for imported projects 561 | *creator.user* 562 | 563 | ##### VisualStudio 564 | ##### VisualStudio 565 | ## Ignore Visual Studio temporary files, build results, and 566 | ## files generated by popular Visual Studio add-ons. 567 | ## 568 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 569 | 570 | # User-specific files 571 | *.rsuser 572 | *.suo 573 | *.user 574 | *.userosscache 575 | *.sln.docstates 576 | 577 | # User-specific files (MonoDevelop/Xamarin Studio) 578 | *.userprefs 579 | 580 | # Mono auto generated files 581 | mono_crash.* 582 | 583 | # Build results 584 | [Dd]ebug/ 585 | [Dd]ebugPublic/ 586 | [Rr]elease/ 587 | [Rr]eleases/ 588 | x64/ 589 | x86/ 590 | [Ww][Ii][Nn]32/ 591 | [Aa][Rr][Mm]/ 592 | [Aa][Rr][Mm]64/ 593 | bld/ 594 | [Bb]in/ 595 | [Oo]bj/ 596 | [Ll]og/ 597 | [Ll]ogs/ 598 | 599 | # Visual Studio 2015/2017 cache/options directory 600 | .vs/ 601 | # Uncomment if you have tasks that create the project's static files in wwwroot 602 | #wwwroot/ 603 | 604 | # Visual Studio 2017 auto generated files 605 | Generated\ Files/ 606 | 607 | # MSTest test Results 608 | [Tt]est[Rr]esult*/ 609 | [Bb]uild[Ll]og.* 610 | 611 | # NUnit 612 | *.VisualState.xml 613 | TestResult.xml 614 | nunit-*.xml 615 | 616 | # Build Results of an ATL Project 617 | [Dd]ebugPS/ 618 | [Rr]eleasePS/ 619 | dlldata.c 620 | 621 | # Benchmark Results 622 | BenchmarkDotNet.Artifacts/ 623 | 624 | # .NET Core 625 | project.lock.json 626 | project.fragment.lock.json 627 | artifacts/ 628 | 629 | # ASP.NET Scaffolding 630 | ScaffoldingReadMe.txt 631 | 632 | # StyleCop 633 | StyleCopReport.xml 634 | 635 | # Files built by Visual Studio 636 | *_i.c 637 | *_p.c 638 | *_h.h 639 | *.ilk 640 | *.meta 641 | *.obj 642 | *.iobj 643 | *.pch 644 | *.pdb 645 | *.ipdb 646 | *.pgc 647 | *.pgd 648 | *.rsp 649 | *.sbr 650 | *.tlb 651 | *.tli 652 | *.tlh 653 | *.tmp 654 | *.tmp_proj 655 | *_wpftmp.csproj 656 | *.log 657 | *.vspscc 658 | *.vssscc 659 | .builds 660 | *.pidb 661 | *.svclog 662 | *.scc 663 | 664 | # Chutzpah Test files 665 | _Chutzpah* 666 | 667 | # Visual C++ cache files 668 | ipch/ 669 | *.aps 670 | *.ncb 671 | *.opendb 672 | *.opensdf 673 | *.sdf 674 | *.cachefile 675 | *.VC.db 676 | *.VC.VC.opendb 677 | 678 | # Visual Studio profiler 679 | *.psess 680 | *.vsp 681 | *.vspx 682 | *.sap 683 | 684 | # Visual Studio Trace Files 685 | *.e2e 686 | 687 | # TFS 2012 Local Workspace 688 | $tf/ 689 | 690 | # Guidance Automation Toolkit 691 | *.gpState 692 | 693 | # ReSharper is a .NET coding add-in 694 | _ReSharper*/ 695 | *.[Rr]e[Ss]harper 696 | *.DotSettings.user 697 | 698 | # TeamCity is a build add-in 699 | _TeamCity* 700 | 701 | # DotCover is a Code Coverage Tool 702 | *.dotCover 703 | 704 | # AxoCover is a Code Coverage Tool 705 | .axoCover/* 706 | !.axoCover/settings.json 707 | 708 | # Coverlet is a free, cross platform Code Coverage Tool 709 | coverage*[.json, .xml, .info] 710 | 711 | # Visual Studio code coverage results 712 | *.coverage 713 | *.coveragexml 714 | 715 | # NCrunch 716 | _NCrunch_* 717 | .*crunch*.local.xml 718 | nCrunchTemp_* 719 | 720 | # MightyMoose 721 | *.mm.* 722 | AutoTest.Net/ 723 | 724 | # Web workbench (sass) 725 | .sass-cache/ 726 | 727 | # Installshield output folder 728 | [Ee]xpress/ 729 | 730 | # DocProject is a documentation generator add-in 731 | DocProject/buildhelp/ 732 | DocProject/Help/*.HxT 733 | DocProject/Help/*.HxC 734 | DocProject/Help/*.hhc 735 | DocProject/Help/*.hhk 736 | DocProject/Help/*.hhp 737 | DocProject/Help/Html2 738 | DocProject/Help/html 739 | 740 | # Click-Once directory 741 | publish/ 742 | 743 | # Publish Web Output 744 | *.[Pp]ublish.xml 745 | *.azurePubxml 746 | # Note: Comment the next line if you want to checkin your web deploy settings, 747 | # but database connection strings (with potential passwords) will be unencrypted 748 | *.pubxml 749 | *.publishproj 750 | 751 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 752 | # checkin your Azure Web App publish settings, but sensitive information contained 753 | # in these scripts will be unencrypted 754 | PublishScripts/ 755 | 756 | # NuGet Packages 757 | *.nupkg 758 | # NuGet Symbol Packages 759 | *.snupkg 760 | # The packages folder can be ignored because of Package Restore 761 | **/[Pp]ackages/* 762 | # except build/, which is used as an MSBuild target. 763 | !**/[Pp]ackages/build/ 764 | # Uncomment if necessary however generally it will be regenerated when needed 765 | #!**/[Pp]ackages/repositories.config 766 | # NuGet v3's project.json files produces more ignorable files 767 | *.nuget.props 768 | *.nuget.targets 769 | 770 | # Microsoft Azure Build Output 771 | csx/ 772 | *.build.csdef 773 | 774 | # Microsoft Azure Emulator 775 | ecf/ 776 | rcf/ 777 | 778 | # Windows Store app package directories and files 779 | AppPackages/ 780 | BundleArtifacts/ 781 | Package.StoreAssociation.xml 782 | _pkginfo.txt 783 | *.appx 784 | *.appxbundle 785 | *.appxupload 786 | 787 | # Visual Studio cache files 788 | # files ending in .cache can be ignored 789 | *.[Cc]ache 790 | # but keep track of directories ending in .cache 791 | !?*.[Cc]ache/ 792 | 793 | # Others 794 | ClientBin/ 795 | ~$* 796 | *~ 797 | *.dbmdl 798 | *.dbproj.schemaview 799 | *.jfm 800 | *.pfx 801 | *.publishsettings 802 | orleans.codegen.cs 803 | 804 | # Including strong name files can present a security risk 805 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 806 | #*.snk 807 | 808 | # Since there are multiple workflows, uncomment next line to ignore bower_components 809 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 810 | #bower_components/ 811 | 812 | # RIA/Silverlight projects 813 | Generated_Code/ 814 | 815 | # Backup & report files from converting an old project file 816 | # to a newer Visual Studio version. Backup files are not needed, 817 | # because we have git ;-) 818 | _UpgradeReport_Files/ 819 | Backup*/ 820 | UpgradeLog*.XML 821 | UpgradeLog*.htm 822 | ServiceFabricBackup/ 823 | *.rptproj.bak 824 | 825 | # SQL Server files 826 | *.mdf 827 | *.ldf 828 | *.ndf 829 | 830 | # Business Intelligence projects 831 | *.rdl.data 832 | *.bim.layout 833 | *.bim_*.settings 834 | *.rptproj.rsuser 835 | *- [Bb]ackup.rdl 836 | *- [Bb]ackup ([0-9]).rdl 837 | *- [Bb]ackup ([0-9][0-9]).rdl 838 | 839 | # Microsoft Fakes 840 | FakesAssemblies/ 841 | 842 | # GhostDoc plugin setting file 843 | *.GhostDoc.xml 844 | 845 | # Node.js Tools for Visual Studio 846 | .ntvs_analysis.dat 847 | node_modules/ 848 | 849 | # Visual Studio 6 build log 850 | *.plg 851 | 852 | # Visual Studio 6 workspace options file 853 | *.opt 854 | 855 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 856 | *.vbw 857 | 858 | # Visual Studio LightSwitch build output 859 | **/*.HTMLClient/GeneratedArtifacts 860 | **/*.DesktopClient/GeneratedArtifacts 861 | **/*.DesktopClient/ModelManifest.xml 862 | **/*.Server/GeneratedArtifacts 863 | **/*.Server/ModelManifest.xml 864 | _Pvt_Extensions 865 | 866 | # Paket dependency manager 867 | .paket/paket.exe 868 | paket-files/ 869 | 870 | # FAKE - F# Make 871 | .fake/ 872 | 873 | # CodeRush personal settings 874 | .cr/personal 875 | 876 | # Python Tools for Visual Studio (PTVS) 877 | __pycache__/ 878 | *.pyc 879 | 880 | # Cake - Uncomment if you are using it 881 | # tools/** 882 | # !tools/packages.config 883 | 884 | # Tabs Studio 885 | *.tss 886 | 887 | # Telerik's JustMock configuration file 888 | *.jmconfig 889 | 890 | # BizTalk build output 891 | *.btp.cs 892 | *.btm.cs 893 | *.odx.cs 894 | *.xsd.cs 895 | 896 | # OpenCover UI analysis results 897 | OpenCover/ 898 | 899 | # Azure Stream Analytics local run output 900 | ASALocalRun/ 901 | 902 | # MSBuild Binary and Structured Log 903 | *.binlog 904 | 905 | # NVidia Nsight GPU debugger configuration file 906 | *.nvuser 907 | 908 | # MFractors (Xamarin productivity tool) working folder 909 | .mfractor/ 910 | 911 | # Local History for Visual Studio 912 | .localhistory/ 913 | 914 | # BeatPulse healthcheck temp database 915 | healthchecksdb 916 | 917 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 918 | MigrationBackup/ 919 | 920 | # Ionide (cross platform F# VS Code tools) working folder 921 | .ionide/ 922 | 923 | # Fody - auto-generated XML schema 924 | FodyWeavers.xsd 925 | 926 | ##### Gradle 927 | .gradle 928 | **/build/ 929 | !src/**/build/ 930 | 931 | # Ignore Gradle GUI config 932 | gradle-app.setting 933 | 934 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 935 | !gradle-wrapper.jar 936 | 937 | # Cache of project 938 | .gradletasknamecache 939 | 940 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 941 | # gradle/wrapper/gradle-wrapper.properties 942 | 943 | ##### CMake 944 | CMakeLists.txt.user 945 | CMakeCache.txt 946 | CMakeFiles 947 | CMakeScripts 948 | Testing 949 | Makefile 950 | cmake_install.cmake 951 | install_manifest.txt 952 | compile_commands.json 953 | CTestTestfile.cmake 954 | _deps 955 | 956 | ##### C++ 957 | # Prerequisites 958 | *.d 959 | 960 | # Compiled Object files 961 | *.slo 962 | *.lo 963 | *.o 964 | *.obj 965 | 966 | # Precompiled Headers 967 | *.gch 968 | *.pch 969 | 970 | # Compiled Dynamic libraries 971 | *.so 972 | *.dylib 973 | *.dll 974 | 975 | # Fortran module files 976 | *.mod 977 | *.smod 978 | 979 | # Compiled Static libraries 980 | *.lai 981 | *.la 982 | *.a 983 | *.lib 984 | 985 | # Executables 986 | *.exe 987 | *.out 988 | *.app 989 | 990 | ##### C 991 | # Prerequisites 992 | *.d 993 | 994 | # Object files 995 | *.o 996 | *.ko 997 | *.obj 998 | *.elf 999 | 1000 | # Linker output 1001 | *.ilk 1002 | *.map 1003 | *.exp 1004 | 1005 | # Precompiled Headers 1006 | *.gch 1007 | *.pch 1008 | 1009 | # Libraries 1010 | *.lib 1011 | *.a 1012 | *.la 1013 | *.lo 1014 | 1015 | # Shared objects (inc. Windows DLLs) 1016 | *.dll 1017 | *.so 1018 | *.so.* 1019 | *.dylib 1020 | 1021 | # Executables 1022 | *.exe 1023 | *.out 1024 | *.app 1025 | *.i*86 1026 | *.x86_64 1027 | *.hex 1028 | 1029 | # Debug files 1030 | *.dSYM/ 1031 | *.su 1032 | *.idb 1033 | *.pdb 1034 | 1035 | # Kernel Module Compile Results 1036 | *.mod* 1037 | *.cmd 1038 | .tmp_versions/ 1039 | modules.order 1040 | Module.symvers 1041 | Mkfile.old 1042 | dkms.conf -------------------------------------------------------------------------------- /include/rdsl/devector.hpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 Valasiadis Fotios 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | * 25 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 26 | * 27 | * devector.hpp 0.0.0 28 | * 29 | * A header-only continuous-storage double ended vector implementation for efficient insertions/removals at both the start & end of it. 30 | */ 31 | 32 | #ifndef DEVECTOR_RDSL_28092021 33 | #define DEVECTOR_RDSL_28092021 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | namespace rdsl{ 40 | 41 | template 42 | using al_traits = std::allocator_traits; 43 | 44 | template 45 | using it_traits = std::iterator_traits; 46 | 47 | template 48 | struct is_at_least_forward{ 49 | static constexpr bool value = false; 50 | }; 51 | 52 | template<> 53 | struct is_at_least_forward{ 54 | static constexpr bool value = true; 55 | }; 56 | 57 | template<> 58 | struct is_at_least_forward{ 59 | static constexpr bool value = true; 60 | }; 61 | 62 | template<> 63 | struct is_at_least_forward{ 64 | static constexpr bool value = true; 65 | }; 66 | 67 | template 68 | struct is_at_least_input{ 69 | static constexpr bool value = is_at_least_forward::value; 70 | }; 71 | 72 | template<> 73 | struct is_at_least_input{ 74 | static constexpr bool value = true; 75 | }; 76 | 77 | #if __cplusplus < 201402L 78 | template 79 | using enable_if_t = typename std::enable_if::type; 80 | #else 81 | template 82 | using enable_if_t = std::enable_if_t; 83 | #endif 84 | 85 | template 86 | using is_iterator = enable_if_t::iterator_category>::value, int>; 87 | 88 | struct offset_by{ 89 | static size_t off_by(size_t free_blocks) noexcept{ 90 | return free_blocks / 2; 91 | } 92 | }; 93 | 94 | template, class OffsetBy = rdsl::offset_by> 95 | struct devector{ 96 | using value_type = T; 97 | using allocator_type = Alloc; 98 | using offset_by_type = OffsetBy; 99 | using reference = value_type&; 100 | using const_reference = const value_type&; 101 | using pointer = typename al_traits::pointer; 102 | using const_pointer = typename al_traits::const_pointer; 103 | using size_type = typename al_traits::size_type; 104 | using difference_type = typename al_traits::difference_type; 105 | using iterator = pointer; 106 | using const_iterator = const_pointer; 107 | using reverse_iterator = std::reverse_iterator; 108 | using const_reverse_iterator = std::reverse_iterator; 109 | 110 | private: 111 | struct compressed_alloc: public allocator_type{ 112 | compressed_alloc(const allocator_type& alloc = allocator_type()) 113 | :allocator_type(alloc) 114 | {} 115 | 116 | compressed_alloc(const compressed_alloc&) = delete; 117 | compressed_alloc(compressed_alloc&&) noexcept = delete; 118 | compressed_alloc& operator=(const compressed_alloc&) = delete; 119 | compressed_alloc& operator=(compressed_alloc&&) noexcept = delete; 120 | 121 | allocator_type& get() noexcept{ return *this; } 122 | const allocator_type& get() const noexcept{ return *this; } 123 | 124 | pointer arr; 125 | }alloc; 126 | 127 | struct compressed_offs: public offset_by_type{ 128 | compressed_offs(const offset_by_type& offs = offset_by_type()) 129 | :offset_by_type(offs) 130 | {} 131 | 132 | compressed_offs(const compressed_offs&) = delete; 133 | compressed_offs(compressed_offs&&) noexcept = delete; 134 | compressed_offs& operator=(const compressed_offs&) = delete; 135 | compressed_offs& operator=(compressed_offs&&) noexcept = delete; 136 | 137 | offset_by_type& get() noexcept{ return *this; } 138 | const offset_by_type& get() const noexcept{ return *this; } 139 | 140 | size_type capacity; 141 | }offs; 142 | 143 | pointer begin_; 144 | pointer end_; 145 | 146 | static constexpr float factor = 1.6f; // new_capacity = capacity * factor 147 | 148 | struct buffer_guard{ 149 | pointer begin; 150 | pointer end; 151 | allocator_type& alloc; 152 | 153 | buffer_guard(allocator_type& alloc, pointer begin, pointer end) 154 | :alloc(alloc), begin(begin), end(end) {} 155 | 156 | buffer_guard(allocator_type& alloc, pointer start) 157 | :alloc(alloc), begin(start), end(start) {} 158 | 159 | buffer_guard(allocator_type& alloc) 160 | :alloc(alloc), begin(nullptr), end(nullptr) {} 161 | 162 | void guard(pointer begin, pointer end){ 163 | this->begin = begin; 164 | this->end = end; 165 | } 166 | 167 | void guard(pointer start){ 168 | begin = end = start; 169 | } 170 | 171 | void release(){ 172 | begin = end; 173 | } 174 | 175 | ~buffer_guard(){ 176 | while(begin != end){ 177 | al_traits::destroy(alloc, begin); 178 | ++begin; 179 | } 180 | } 181 | }; 182 | 183 | struct memory_guard{ 184 | pointer arr; 185 | size_type capacity; 186 | allocator_type& alloc; 187 | 188 | memory_guard(allocator_type& alloc, size_type capacity) 189 | :alloc(alloc), capacity(capacity), arr(alloc.allocate(capacity)) {} 190 | 191 | void release(){ 192 | arr = nullptr; 193 | } 194 | 195 | ~memory_guard(){ 196 | if(arr){ 197 | alloc.deallocate(arr, capacity); 198 | } 199 | } 200 | }; 201 | 202 | public: 203 | 204 | size_type capacity() const noexcept{ 205 | return offs.capacity; 206 | } 207 | 208 | size_type max_size() const{ 209 | return al_traits::max_size(alloc); 210 | } 211 | 212 | iterator begin() noexcept{ 213 | return begin_; 214 | } 215 | 216 | const_iterator begin() const noexcept{ 217 | return begin_; 218 | } 219 | 220 | iterator end() noexcept{ 221 | return end_; 222 | } 223 | 224 | const_iterator end() const noexcept{ 225 | return end_; 226 | } 227 | 228 | reverse_iterator rbegin() noexcept{ 229 | return reverse_iterator(end_); 230 | } 231 | 232 | const_reverse_iterator rbegin() const noexcept{ 233 | return const_reverse_iterator(end_); 234 | } 235 | 236 | reverse_iterator rend() noexcept{ 237 | return reverse_iterator(begin_); 238 | } 239 | 240 | const_reverse_iterator rend() const noexcept{ 241 | return const_reverse_iterator(begin_); 242 | } 243 | 244 | const_iterator cbegin() const noexcept{ 245 | return begin(); 246 | } 247 | 248 | const_iterator cend() const noexcept{ 249 | return end(); 250 | } 251 | 252 | const_reverse_iterator crbegin() const noexcept{ 253 | return rbegin(); 254 | } 255 | 256 | const_reverse_iterator crend() const noexcept{ 257 | return rend(); 258 | } 259 | 260 | size_type size() const noexcept{ 261 | return end() - begin(); 262 | } 263 | 264 | bool empty() const noexcept{ 265 | return end() == begin(); 266 | } 267 | 268 | private: 269 | size_type free_front() const noexcept{ return begin_ - alloc.arr; } 270 | size_type free_back() const noexcept{ return alloc.arr + offs.capacity - end_; } 271 | size_type free_total() const noexcept{ return offs.capacity - size(); } 272 | 273 | pointer allocate_n(size_type n){ 274 | auto ptr = alloc.allocate(n); 275 | offs.capacity = n; 276 | return ptr; 277 | } 278 | 279 | void deallocate() noexcept{ 280 | if(offs.capacity){ 281 | alloc.deallocate(alloc.arr, offs.capacity); 282 | offs.capacity = 0; 283 | } 284 | } 285 | 286 | void construct(size_type n, const_reference val){ 287 | begin_ = end_ = alloc.arr + offs.off_by(offs.capacity - n); 288 | while(n--){ 289 | al_traits::construct(alloc, end_, val); 290 | ++end_; 291 | } 292 | } 293 | 294 | template = 0> 295 | void construct(InputIterator first, size_type distance){ 296 | begin_ = end_ = alloc.arr + offs.off_by(offs.capacity - distance); 297 | while(distance--){ 298 | al_traits::construct(alloc, end_, *first); 299 | ++first; 300 | ++end_; 301 | } 302 | } 303 | 304 | template = 0> 305 | void construct_move(InputIterator first, size_type distance){ 306 | begin_ = end_ = alloc.arr + offs.off_by(offs.capacity - distance); 307 | while(distance--){ 308 | al_traits::construct(alloc, end_, std::move_if_noexcept(*first)); 309 | ++first; 310 | ++end_; 311 | } 312 | } 313 | 314 | void destroy_all() noexcept{ 315 | while(begin_ != end_){ 316 | al_traits::destroy(alloc, begin_); 317 | ++begin_; 318 | } 319 | } 320 | 321 | void steal_ownership(devector& x) noexcept{ 322 | offs.capacity = x.offs.capacity; 323 | alloc.arr = x.alloc.arr; 324 | begin_ = x.begin_; 325 | end_ = x.end_; 326 | 327 | x.alloc.arr = x.begin_ = x.end_ = nullptr; 328 | x.offs.capacity = 0; 329 | } 330 | 331 | bool in_bounds(pointer it) const noexcept{ 332 | return it >= begin_ && it < end_; 333 | } 334 | 335 | int next_capacity() const noexcept{ 336 | return factor * offs.capacity + 1; 337 | } 338 | /** 339 | * @brief Allocates a new memory chunk of *new_capacity* capacity and copies all elements into it, respecting the offset factor. 340 | * *new capacity* should be greater equal to size. 341 | */ 342 | void reallocate(size_type new_capacity, size_type offset){ 343 | memory_guard mem_guard(alloc, new_capacity); 344 | 345 | buffer_guard buf_guard(alloc, mem_guard.arr + offset); 346 | 347 | for(; begin_ != end_; ++begin_, ++buf_guard.end){ 348 | al_traits::construct(alloc, buf_guard.end, std::move_if_noexcept(*begin_)); 349 | } 350 | destroy_all(); 351 | deallocate(); 352 | 353 | alloc.arr = mem_guard.arr; 354 | begin_ = buf_guard.begin; 355 | end_ = buf_guard.end; 356 | offs.capacity = new_capacity; 357 | 358 | buf_guard.release(); 359 | mem_guard.release(); 360 | } 361 | 362 | void reallocate(size_type new_capacity){ 363 | reallocate(new_capacity, offs.off_by(new_capacity - size())); 364 | } 365 | 366 | template 367 | void front_shift_while(pointer& new_begin, Pred pred){ 368 | while(!empty() && pred()){ 369 | al_traits::construct(alloc, new_begin, std::move(*begin_)); 370 | al_traits::destroy(alloc, begin_); 371 | ++begin_; 372 | ++new_begin; 373 | } 374 | } 375 | 376 | template 377 | void back_shift_while(pointer& new_end, Pred pred){ 378 | while(!empty() && pred()){ 379 | al_traits::construct(alloc, new_end - 1, std::move(end_[-1])); 380 | al_traits::destroy(alloc, end_ - 1); 381 | --end_; 382 | --new_end; 383 | } 384 | } 385 | 386 | /** 387 | * @brief Segregates the container into two parts with a gap of 'n' 388 | * elements starting at 'pos' while also shifting the container to 389 | * the desired position according to *offset*. 390 | * 391 | * @return pointer to the first element of the 'n' element gap. 392 | */ 393 | pointer segregate(pointer new_begin, pointer new_end, const_iterator pos, size_type n){ 394 | pointer free_space; 395 | buffer_guard front_guard(alloc); 396 | buffer_guard back_guard(alloc); 397 | 398 | if(!in_bounds(new_begin)){ 399 | front_guard.guard(new_begin); 400 | front_shift_while(front_guard.end, [this, pos]{ return begin_ < pos; }); 401 | 402 | free_space = front_guard.end; 403 | 404 | if(!in_bounds(front_guard.end + n)){ 405 | back_guard.guard(front_guard.end + n); 406 | front_shift_while(back_guard.end, []{ return true; }); 407 | }else{ 408 | back_guard.guard(new_end); 409 | back_shift_while(back_guard.begin, [this, pos]{ return end_ > pos; }); 410 | } 411 | }else{ 412 | back_guard.guard(new_end); 413 | back_shift_while(back_guard.begin, [this, pos]{ return end_ > pos; }); 414 | 415 | free_space = back_guard.begin - n; 416 | 417 | if(!in_bounds(back_guard.begin - n - 1)){ 418 | front_guard.guard(back_guard.begin - n); 419 | back_shift_while(front_guard.begin, []{ return true; }); 420 | }else{ 421 | front_guard.guard(new_begin); 422 | front_shift_while(front_guard.end, [this, pos]{ return begin_ < pos; }); 423 | } 424 | } 425 | 426 | front_guard.release(); 427 | back_guard.release(); 428 | 429 | return free_space; 430 | } 431 | 432 | /** 433 | * @brief merges two ranges into one, destroying any elements between them. 434 | * Also shifts the elements in case [new_begin, new_end) isn't inside [begin, end). 435 | * 436 | * @return pointer 437 | */ 438 | pointer integrate(pointer new_begin, pointer new_end, const_iterator pos, size_type n){ 439 | pointer ret = new_begin + (pos - begin_); 440 | buffer_guard front_guard(alloc); 441 | buffer_guard back_guard(alloc); 442 | 443 | if(!in_bounds(new_begin)){ 444 | front_guard.guard(new_begin); 445 | 446 | while(begin_ < pos){ 447 | al_traits::construct(alloc, front_guard.end, *begin_); 448 | ++front_guard.end; 449 | pop_front(); 450 | } 451 | 452 | while(n--){ 453 | pop_front(); 454 | } 455 | 456 | while(!empty()){ 457 | al_traits::construct(alloc, front_guard.end, *begin_); 458 | ++front_guard.end; 459 | pop_front(); 460 | } 461 | }else if(!in_bounds(new_end)){ 462 | back_guard.guard(new_end); 463 | 464 | while(end_ < pos + n){ 465 | al_traits::construct(alloc, back_guard.begin - 1, end_[-1]); 466 | --back_guard.begin; 467 | pop_back(); 468 | } 469 | 470 | while(n--){ 471 | pop_back(); 472 | } 473 | 474 | while(!empty()){ 475 | al_traits::construct(alloc, back_guard.begin - 1, end_[-1]); 476 | --back_guard.begin; 477 | pop_back(); 478 | } 479 | }else{ 480 | auto const front_shift = new_begin - begin_; 481 | auto const back_shift = end_ - new_end; 482 | 483 | while(begin_ < pos){ 484 | begin_[front_shift] = std::move(*begin_); 485 | pop_front(); 486 | } 487 | 488 | while(begin_ < new_begin){ 489 | pop_front(); 490 | } 491 | 492 | while(end_ > pos + n){ 493 | end_[-back_shift - 1] = std::move(end_[-1]); 494 | pop_back(); 495 | } 496 | 497 | while(end_ > new_end){ 498 | pop_back(); 499 | } 500 | } 501 | 502 | begin_ = new_begin; 503 | end_ = new_end; 504 | front_guard.release(); 505 | back_guard.release(); 506 | 507 | return ret; 508 | } 509 | 510 | size_type capacity_to_fit(size_type n) const noexcept{ 511 | float temp_capacity = offs.capacity ? offs.capacity : 1; 512 | while(temp_capacity < n){ 513 | temp_capacity = factor * temp_capacity; 514 | } 515 | return static_cast(temp_capacity); 516 | } 517 | 518 | template 519 | iterator insert_impl(const_iterator position, size_type n, Insert ins){ 520 | iterator pos; // position of first newly-created element 521 | 522 | if(n <= free_total()){ 523 | if(position == begin_){ 524 | buffer_guard front_guard(alloc, begin_ - n); 525 | while(n--){ 526 | ins(front_guard.end); 527 | ++front_guard.end; 528 | } 529 | begin_ = front_guard.begin; 530 | front_guard.release(); 531 | }else if(position == end_){ 532 | while(n--){ 533 | ins(end_); 534 | ++end_; 535 | } 536 | }else{ 537 | const pointer new_begin = alloc.arr + offs.off_by(free_total() - n); 538 | const pointer new_end = new_begin + n + size(); 539 | 540 | const pointer free_space = segregate(new_begin, new_end, position, n); 541 | 542 | buffer_guard front_guard(alloc, new_begin, free_space); 543 | buffer_guard back_guard(alloc, free_space + n, new_end); 544 | 545 | while(n--){ 546 | ins(front_guard.end); 547 | ++front_guard.end; 548 | } 549 | 550 | begin_ = new_begin; 551 | end_ = new_end; 552 | 553 | front_guard.release(); 554 | back_guard.release(); 555 | 556 | pos = free_space; 557 | } 558 | }else{ 559 | const size_type new_size = size() + n; 560 | 561 | memory_guard mem_guard(alloc, capacity_to_fit(new_size)); 562 | 563 | const size_type front_space = offs.off_by(mem_guard.capacity - new_size); 564 | 565 | buffer_guard buf_guard(alloc, mem_guard.arr + front_space); 566 | 567 | auto it = begin(); 568 | for(; it < position; ++it){ 569 | al_traits::construct(alloc, buf_guard.end, std::move_if_noexcept(*it)); 570 | ++buf_guard.end; 571 | } 572 | 573 | pos = buf_guard.end; 574 | while(n--){ 575 | ins(buf_guard.end); 576 | ++buf_guard.end; 577 | } 578 | for(; it < end(); ++it){ 579 | al_traits::construct(alloc, buf_guard.end, std::move_if_noexcept(*it)); 580 | ++buf_guard.end; 581 | } 582 | 583 | destroy_all(); 584 | deallocate(); 585 | 586 | alloc.arr = mem_guard.arr; 587 | offs.capacity = mem_guard.capacity; 588 | 589 | begin_ = buf_guard.begin; 590 | end_ = buf_guard.end; 591 | 592 | buf_guard.release(); 593 | mem_guard.release(); 594 | } 595 | 596 | return pos; 597 | } 598 | 599 | public: 600 | 601 | explicit devector(const allocator_type& allocator = allocator_type(), const offset_by_type& offset_by = offset_by_type()) 602 | :alloc(allocator), offs(offset_by) 603 | { 604 | begin_ = end_ = alloc.arr = nullptr; 605 | offs.capacity = 0; 606 | } 607 | 608 | explicit devector(const offset_by_type& offset_by) 609 | :devector(allocator_type(), offset_by) 610 | {} 611 | 612 | devector( 613 | size_type n, 614 | const_reference val, 615 | const allocator_type& allocator = allocator_type(), 616 | const offset_by_type& offset_by = offset_by_type() 617 | ) 618 | :alloc(allocator), offs(offset_by) 619 | { 620 | alloc.arr = allocate_n(n); 621 | try{ 622 | construct(n, val); 623 | }catch(...){ 624 | destroy_all(); 625 | deallocate(); 626 | throw; 627 | } 628 | } 629 | 630 | devector(size_type n, const_reference val, const offset_by_type& offset_by) 631 | :devector(n, val, allocator_type(), offset_by) 632 | {} 633 | 634 | #if __cplusplus < 201402L 635 | explicit devector(size_type n) 636 | :devector(n, value_type()) 637 | {} 638 | #else 639 | explicit devector( 640 | size_type n, 641 | const allocator_type& allocator = allocator_type(), 642 | const offset_by_type& offset_by = offset_by_type() 643 | ) 644 | :devector(n, value_type(), allocator, offset_by) 645 | {} 646 | #endif 647 | 648 | template = 0> 649 | devector( 650 | InputIterator first, 651 | InputIterator last, 652 | size_type distance, 653 | const allocator_type& allocator = allocator_type(), 654 | const offset_by_type& offset_by = offset_by_type() 655 | ) 656 | :alloc(allocator), offs(offset_by) 657 | { 658 | alloc.arr = allocate_n(distance); 659 | try{ 660 | construct(first, distance); 661 | }catch(...){ 662 | destroy_all(); 663 | deallocate(); 664 | throw; 665 | } 666 | } 667 | 668 | template = 0> 669 | devector( 670 | InputIterator first, 671 | InputIterator last, 672 | size_type distance, 673 | const offset_by_type& offset_by 674 | ) 675 | :devector(first, last, distance, allocator_type(), offset_by) 676 | {} 677 | 678 | template = 0> 679 | devector( 680 | InputIterator first, 681 | InputIterator last, 682 | const allocator_type& allocator = allocator_type(), 683 | const offset_by_type& offset_by = offset_by_type() 684 | ) 685 | :devector(allocator, offset_by) 686 | { 687 | if(is_at_least_forward::iterator_category>::value){ 688 | const size_type distance = std::distance(first, last); 689 | alloc.arr = allocate_n(distance); 690 | try{ 691 | construct(first, distance); 692 | }catch(...){ 693 | destroy_all(); 694 | deallocate(); 695 | throw; 696 | } 697 | }else{ 698 | while(first != last){ 699 | push_back(*first); 700 | ++first; 701 | } 702 | } 703 | } 704 | 705 | template = 0> 706 | devector( 707 | InputIterator first, 708 | InputIterator last, 709 | const offset_by_type& offset_by 710 | ) 711 | :devector(first, last, allocator_type(), offset_by) 712 | {} 713 | 714 | devector(const devector& x, const allocator_type& allocator, const offset_by_type& offset_by) 715 | :devector(x.begin(), x.end(), x.size(), allocator, offset_by) 716 | {} 717 | 718 | devector(const devector& x, const allocator_type& allocator) 719 | :devector(x.begin(), x.end(), x.size(), allocator, x.offs) 720 | {} 721 | 722 | devector(const devector& x, const offset_by_type& offset_by) 723 | :devector(x.begin(), x.end(), x.size(), x.alloc, offset_by) 724 | {} 725 | 726 | devector(const devector& x) 727 | :devector(x, al_traits::select_on_container_copy_construction(x.alloc), x.offs) 728 | {} 729 | 730 | devector(devector&& x) noexcept 731 | :devector(std::move(x), x.alloc, x.offs) 732 | {} 733 | 734 | devector(devector&& x, const allocator_type& allocator, const offset_by_type& offset_by) noexcept 735 | :offs(offset_by) 736 | { 737 | if(allocator == x.alloc){ 738 | alloc.get() = x.alloc.get(); 739 | steal_ownership(x); 740 | }else{ 741 | alloc.get() = allocator; 742 | 743 | alloc.arr = allocate_n(x.size()); 744 | construct_move(x.begin(), x.size()); 745 | } 746 | } 747 | 748 | devector(devector&& x, const allocator_type& allocator) noexcept 749 | :devector(std::move(x), allocator, x.offs) 750 | {} 751 | 752 | devector(devector&& x, const offset_by_type& offset_by) noexcept 753 | :devector(std::move(x), x.alloc, offset_by) 754 | {} 755 | 756 | devector( 757 | std::initializer_list il, 758 | const allocator_type& allocator = allocator_type(), 759 | const offset_by_type& offset_by = offset_by_type() 760 | ) 761 | :devector(il.begin(), il.end(), il.size(), allocator, offset_by) 762 | {} 763 | 764 | devector(std::initializer_list il, const offset_by_type& offset_by) 765 | :devector(il.begin(), il.end(), il.size(), allocator_type(), offset_by) 766 | {} 767 | 768 | ~devector(){ 769 | destroy_all(); 770 | deallocate(); 771 | } 772 | 773 | template = 0> 774 | void assign (InputIterator first, size_type distance){ 775 | destroy_all(); 776 | if(offs.capacity < distance){ 777 | reallocate(capacity_to_fit(distance)); 778 | } 779 | construct(first, distance); 780 | } 781 | 782 | template = 0> 783 | void assign (InputIterator first, InputIterator last){ 784 | if(is_at_least_forward::value){ 785 | assign(first, std::distance(first,last)); 786 | }else{ 787 | destroy_all(); 788 | begin_ = end_ = alloc.arr + offs.off_by(free_total()); 789 | while(first != last){ 790 | push_back(*first); 791 | ++first; 792 | } 793 | } 794 | } 795 | 796 | void assign(size_type n, const_reference val){ 797 | destroy_all(); 798 | if(offs.capacity < n){ 799 | reallocate(capacity_to_fit(n)); 800 | } 801 | construct(n, val); 802 | } 803 | 804 | void assign(std::initializer_list il){ 805 | destroy_all(); 806 | if(offs.capacity < il.size()){ 807 | reallocate(capacity_to_fit(il.size())); 808 | } 809 | construct(il.begin(), il.size()); 810 | } 811 | 812 | devector& operator=(const devector& x){ 813 | if(this == &x){ 814 | return *this; 815 | } 816 | 817 | offs.get() = x.offs.get(); 818 | 819 | if(al_traits::propagate_on_container_copy_assignment::value && alloc != x.alloc){ 820 | destroy_all(); 821 | deallocate(); 822 | 823 | alloc.get() = x.alloc.get(); 824 | 825 | alloc.arr = allocate_n(capacity_to_fit(x.size())); 826 | construct(x.begin(), x.size()); 827 | 828 | }else{ 829 | if(offs.capacity < x.size()){ 830 | destroy_all(); 831 | deallocate(); 832 | alloc.arr = allocate_n(capacity_to_fit(x.size())); 833 | construct(x.begin(), x.size()); 834 | }else{ 835 | const pointer new_begin = alloc.arr + offs.off_by(offs.capacity - x.size()); 836 | const pointer new_end = new_begin + x.size(); 837 | 838 | while(!empty() && begin_ < new_begin){ 839 | pop_front(); 840 | } 841 | 842 | while(!empty() && end_ > new_end){ 843 | pop_back(); 844 | } 845 | 846 | buffer_guard guard(alloc, new_begin); 847 | 848 | for(auto it = x.begin_; it != x.end_; ++it, ++guard.end){ 849 | if(in_bounds(guard.end)){ 850 | *guard.end = *it; 851 | }else{ 852 | al_traits::construct(alloc, guard.end, *it); 853 | } 854 | } 855 | 856 | begin_ = new_begin; 857 | end_ = new_end; 858 | guard.release(); 859 | } 860 | } 861 | 862 | 863 | return *this; 864 | } 865 | 866 | devector& operator=(devector&& x){ 867 | if(this == &x){ 868 | return *this; 869 | } 870 | 871 | offs.get() = std::move(x.offs.get()); 872 | 873 | if(!al_traits::propagate_on_container_move_assignment::value){ 874 | if(alloc != x.alloc){ 875 | if(offs.capacity < x.size()){ 876 | destroy_all(); 877 | deallocate(); 878 | alloc.arr = allocate_n(capacity_to_fit(x.size())); 879 | construct_move(x.begin_, x.size()); 880 | }else{ 881 | const pointer new_begin = alloc.arr + offs.off_by(offs.capacity - x.size()); 882 | const pointer new_end = new_begin + x.size(); 883 | 884 | while(!empty() && begin_ < new_begin){ 885 | pop_front(); 886 | } 887 | 888 | while(!empty() && end_ > new_end){ 889 | pop_back(); 890 | } 891 | 892 | buffer_guard guard(alloc, new_begin); 893 | 894 | for(auto it = x.begin_; it != x.end_; ++it, ++guard.end){ 895 | if(in_bounds(guard.end)){ 896 | *guard.end = std::move(*it); 897 | }else{ 898 | al_traits::construct(alloc, guard.end, std::move(*it)); 899 | } 900 | } 901 | 902 | begin_ = new_begin; 903 | end_ = new_end; 904 | guard.release(); 905 | } 906 | }else{ 907 | destroy_all(); 908 | deallocate(); 909 | steal_ownership(x); 910 | } 911 | }else{ 912 | destroy_all(); 913 | deallocate(); 914 | steal_ownership(x); 915 | alloc.get() = std::move(x.alloc.get()); 916 | } 917 | 918 | return *this; 919 | } 920 | 921 | devector& operator=(std::initializer_list il){ 922 | if(offs.capacity < il.size()){ 923 | destroy_all(); 924 | deallocate(); 925 | alloc.arr = allocate_n(capacity_to_fit(il.size())); 926 | construct(il.begin(), il.size()); 927 | }else{ 928 | const pointer new_begin = alloc.arr + offs.off_by(offs.capacity - il.size()); 929 | const pointer new_end = new_begin + il.size(); 930 | 931 | while(!empty() && begin_ < new_begin){ 932 | pop_front(); 933 | } 934 | 935 | while(!empty() && end_ > new_end){ 936 | pop_back(); 937 | } 938 | 939 | buffer_guard guard(alloc, new_begin); 940 | 941 | for(auto it = il.begin(); it != il.end(); ++it, ++guard.end){ 942 | if(in_bounds(guard.end)){ 943 | *guard.end = *it; 944 | }else{ 945 | al_traits::construct(alloc, guard.end, *it); 946 | } 947 | } 948 | 949 | begin_ = new_begin; 950 | end_ = new_begin + il.size(); 951 | guard.release(); 952 | } 953 | 954 | return *this; 955 | } 956 | 957 | void resize_front(size_type n, const_reference val = value_type()){ 958 | while(n < size()){ 959 | pop_front(); 960 | } 961 | if(n > offs.capacity){ 962 | reallocate(capacity_to_fit(n), free_back()); 963 | } 964 | while(n > size()){ 965 | push_front(val); 966 | } 967 | } 968 | 969 | void resize_back(size_type n, const_reference val = value_type()){ 970 | while(n < size()){ 971 | pop_back(); 972 | } 973 | if(n > offs.capacity){ 974 | reallocate(capacity_to_fit(n), free_front()); 975 | } 976 | while(n > size()){ 977 | push_back(val); 978 | } 979 | } 980 | 981 | void resize(size_type n, const_reference val = value_type()){ 982 | resize_back(n, val); 983 | } 984 | 985 | void reserve(size_type n){ 986 | if(n > offs.capacity){ 987 | reallocate(n); 988 | } 989 | } 990 | 991 | void shrink_to_fit(){ 992 | reallocate(size()); 993 | } 994 | 995 | reference operator[](size_type index){ 996 | return begin_[index]; 997 | } 998 | 999 | const_reference operator[](size_type index) const{ 1000 | return begin_[index]; 1001 | } 1002 | 1003 | reference at(size_type index){ 1004 | if(in_bounds(begin_ + index)){ 1005 | return begin_[index]; 1006 | }else{ 1007 | throw std::out_of_range("index " + std::to_string(index) + " out of range for array of size " + std::to_string(size())); 1008 | } 1009 | } 1010 | 1011 | const_reference at(size_type index) const{ 1012 | if(in_bounds(begin_ + index)){ 1013 | return begin_[index]; 1014 | }else{ 1015 | throw std::out_of_range("index " + std::to_string(index) + " out of range for array of size " + std::to_string(size())); 1016 | } 1017 | } 1018 | 1019 | reference front(){ 1020 | return *begin_; 1021 | } 1022 | 1023 | const_reference front() const{ 1024 | return *begin_; 1025 | } 1026 | 1027 | reference back(){ 1028 | return *(end_ - 1); 1029 | } 1030 | 1031 | const_reference back() const{ 1032 | return *(end_ - 1); 1033 | } 1034 | 1035 | pointer data() noexcept{ 1036 | return alloc.arr; 1037 | } 1038 | 1039 | const_pointer data() const noexcept{ 1040 | return alloc.arr; 1041 | } 1042 | 1043 | void push_back(const_reference val){ 1044 | if(!free_back()){ 1045 | const auto new_capacity = next_capacity(); 1046 | auto offset = offs.off_by(new_capacity - size()); 1047 | offset -= offset == (new_capacity - size()); 1048 | reallocate(new_capacity, offset); 1049 | } 1050 | 1051 | al_traits::construct(alloc, end_, val); 1052 | ++end_; 1053 | } 1054 | 1055 | void push_back(value_type&& val){ 1056 | if(!free_back()){ 1057 | const auto new_capacity = next_capacity(); 1058 | auto offset = offs.off_by(new_capacity - size()); 1059 | offset -= offset == (new_capacity - size()); 1060 | reallocate(new_capacity, offset); 1061 | } 1062 | 1063 | al_traits::construct(alloc, end_, std::move(val)); 1064 | ++end_; 1065 | } 1066 | 1067 | void push_front(const_reference val){ 1068 | if(!free_front()){ 1069 | const auto new_capacity = next_capacity(); 1070 | const auto offset = offs.off_by(new_capacity - size()); 1071 | reallocate(new_capacity, offset + !offset); 1072 | } 1073 | 1074 | al_traits::construct(alloc, begin_.ptr - 1, val); 1075 | --begin_; 1076 | } 1077 | 1078 | void push_front(value_type&& val){ 1079 | if(!free_front()){ 1080 | const auto new_capacity = next_capacity(); 1081 | const auto offset = offs.off_by(new_capacity - size()); 1082 | reallocate(new_capacity, offset + !offset); 1083 | } 1084 | 1085 | al_traits::construct(alloc, begin_ - 1, std::move(val)); 1086 | --begin_; 1087 | } 1088 | 1089 | void pop_back() noexcept{ 1090 | al_traits::destroy(alloc, end_ - 1); 1091 | --end_; 1092 | } 1093 | 1094 | void pop_front() noexcept{ 1095 | al_traits::destroy(alloc, begin_); 1096 | ++begin_; 1097 | } 1098 | 1099 | iterator insert(const_iterator position, size_type n, const_reference val){ 1100 | return insert_impl(position, n, [&val, this](pointer p){ 1101 | al_traits::construct(alloc, p, val); 1102 | }); 1103 | } 1104 | 1105 | iterator insert(const_iterator position, const_reference val){ 1106 | return insert(position, 1, val); 1107 | } 1108 | 1109 | iterator insert(const_iterator position, value_type&& val){ 1110 | return insert_impl(position, 1, [&val, this](pointer p) mutable{ 1111 | al_traits::construct(alloc, p, std::move(val)); 1112 | }); 1113 | } 1114 | 1115 | template = 0> 1116 | iterator insert(const_iterator position, InputIterator first, size_type n){ 1117 | return insert_impl(position, n, [first, this](pointer p) mutable{ 1118 | al_traits::construct(alloc, p, *first++); 1119 | }); 1120 | } 1121 | 1122 | template = 0> 1123 | iterator insert(const_iterator position, InputIterator first, InputIterator last){ 1124 | if(is_at_least_forward::iterator_category>::value){ 1125 | return insert(position, first, std::distance(first, last)); 1126 | }else{ 1127 | const auto index = position - cbegin(); 1128 | memory_guard mem_guard(alloc, cend() - position + 1); 1129 | buffer_guard buf_guard(alloc, mem_guard.arr + mem_guard.capacity - 1); 1130 | 1131 | while(buf_guard.begin != mem_guard.arr){ 1132 | al_traits::construct(alloc, buf_guard.begin - 1, std::move(back())); 1133 | --buf_guard.begin; 1134 | pop_back(); 1135 | } 1136 | 1137 | while(first != last){ 1138 | push_back(*first); 1139 | ++first; 1140 | } 1141 | 1142 | reserve(capacity() + buf_guard.end - buf_guard.begin); 1143 | for(pointer it = buf_guard.begin; it != buf_guard.end; ++it){ 1144 | al_traits::construct(alloc, end_, std::move(*it)); 1145 | ++end_; 1146 | } 1147 | 1148 | return begin_ + index; 1149 | } 1150 | } 1151 | 1152 | iterator insert(const_iterator position, std::initializer_list il){ 1153 | return insert(position, il.begin(), il.size()); 1154 | } 1155 | 1156 | iterator erase(const_iterator first, const_iterator last){ 1157 | iterator pos; 1158 | 1159 | if(first == begin_){ 1160 | while(begin_ < last){ 1161 | al_traits::destroy(alloc, begin_); 1162 | ++begin_; 1163 | } 1164 | return begin_; 1165 | }else if(last == end_){ 1166 | while(end_ > first){ 1167 | al_traits::destroy(alloc, end_ - 1); 1168 | --end_; 1169 | } 1170 | return end_; 1171 | }else{ 1172 | const size_type n = last - first; 1173 | 1174 | const pointer new_begin = alloc.arr + offs.off_by(free_total() + n); 1175 | const pointer new_end = new_begin + size() - n; 1176 | 1177 | return integrate(new_begin, new_end, first, n); 1178 | } 1179 | } 1180 | 1181 | iterator erase(const_iterator position){ 1182 | return erase(position, position + 1); 1183 | } 1184 | 1185 | void swap(devector& x){ 1186 | std::swap(alloc.arr, x.alloc.arr); 1187 | std::swap(begin_, x.begin_); 1188 | std::swap(end_, x.end_); 1189 | std::swap(offs.capacity, x.offs.capacity); 1190 | std::swap(offs, x.offs); 1191 | if(al_traits::propagate_on_container_swap){ 1192 | std::swap(alloc, x.alloc); 1193 | } 1194 | } 1195 | 1196 | void clear() noexcept{ 1197 | destroy_all(); 1198 | } 1199 | 1200 | template 1201 | iterator emplace(const_iterator position, Args&&... args){ 1202 | return insert_impl(position, 1, [&](pointer p){ 1203 | al_traits::construct(alloc, p, std::forward(args)...); 1204 | }); 1205 | } 1206 | 1207 | template 1208 | iterator emplace_back(Args&&... args){ 1209 | if(!free_back()){ 1210 | const auto new_capacity = next_capacity(); 1211 | auto offset = offs.off_by(new_capacity - size()); 1212 | offset -= offset == (new_capacity - size()); 1213 | reallocate(new_capacity, offset); 1214 | } 1215 | 1216 | al_traits::construct(alloc, end_, std::forward(args)...); 1217 | return end_++; 1218 | } 1219 | 1220 | template 1221 | iterator emplace_front(Args&&... args){ 1222 | if(!free_front()){ 1223 | const auto new_capacity = next_capacity(); 1224 | const auto offset = offs.off_by(new_capacity - size()); 1225 | reallocate(new_capacity, offset + !offset); 1226 | } 1227 | 1228 | al_traits::construct(alloc, begin_ - 1, std::forward(args)...); 1229 | return begin_--; 1230 | } 1231 | 1232 | allocator_type get_allocator() const noexcept{ 1233 | return alloc; 1234 | } 1235 | 1236 | offset_by_type get_offset_by() const noexcept{ 1237 | return offs; 1238 | } 1239 | }; 1240 | 1241 | template 1242 | bool operator== (const devector& lhs, const devector& rhs){ 1243 | if(lhs.size() != rhs.size()){ 1244 | return false; 1245 | } 1246 | 1247 | for(auto it0 = lhs.begin(), it1 = rhs.begin(); it0 != lhs.end(); ++it0, ++it1){ 1248 | if(*it0 != *it1){ 1249 | return false; 1250 | } 1251 | } 1252 | 1253 | return true; 1254 | } 1255 | 1256 | template 1257 | bool operator!= (const devector& lhs, const devector& rhs){ 1258 | return !(lhs == rhs); 1259 | } 1260 | 1261 | template 1262 | bool operator< (const devector& lhs, const devector& rhs){ 1263 | auto it1 = rhs.cbegin(); 1264 | for(auto it0 = lhs.cbegin(); it0 != lhs.cend(); ++it0, ++it1){ 1265 | if(it1 == rhs.cend() || *it1 < *it0){ 1266 | return false; 1267 | }else if(*it0 < *it1){ 1268 | return true; 1269 | } 1270 | } 1271 | 1272 | return it1 != rhs.cend(); 1273 | } 1274 | 1275 | template 1276 | bool operator<= (const devector& lhs, const devector& rhs){ 1277 | return !(rhs < lhs); 1278 | } 1279 | 1280 | template 1281 | bool operator> (const devector& lhs, const devector& rhs){ 1282 | return rhs < lhs; 1283 | } 1284 | 1285 | template 1286 | bool operator>= (const devector& lhs, const devector& rhs){ 1287 | return !(lhs < rhs); 1288 | } 1289 | 1290 | template 1291 | void swap(devector& x, devector y){ 1292 | x.swap(y); 1293 | } 1294 | } //rdsl 1295 | 1296 | #endif 1297 | --------------------------------------------------------------------------------