Skip to content

Commit

Permalink
Addition of FlatSet from rvalue of Vector
Browse files Browse the repository at this point in the history
  • Loading branch information
sjanel committed Dec 1, 2021
1 parent c81ddff commit bbcd676
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 27 deletions.
8 changes: 7 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required (VERSION 3.14)

project(amc
VERSION 2.1
VERSION 2.3
DESCRIPTION "Header base library of C++ containers"
LANGUAGES CXX
)
Expand Down Expand Up @@ -31,6 +31,7 @@ endif()
option(AMC_ENABLE_TESTS "Build the unit tests" ${MAIN_PROJECT})
option(AMC_ENABLE_BENCHMARKS "Build the benchmarks" ${BENCH_BUILD})
option(AMC_ENABLE_ASAN "Compile with AddressSanitizer" ${ASAN_BUILD})
option(AMC_PEDANTIC "If set, only standard API (in respect to STL) will be defined. Additional features are enabled when OFF" OFF)

# Activate all warnings, in all build modes
if(MAIN_PROJECT)
Expand All @@ -45,6 +46,11 @@ if(AMC_ENABLE_ASAN AND NOT MSVC)
add_compile_options(-g -fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero -fno-sanitize-recover=all)
endif()

if (NOT AMC_PEDANTIC)
message(STATUS "Compile with non standard features")
add_compile_definitions(AMC_NONSTD_FEATURES)
endif()

# Create interface library for header files
include(GNUInstallDirs)

Expand Down
47 changes: 43 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@
- [Vectors](#vectors)
- [Sets](#sets)
- [Other benefits](#other-benefits)
- [For vector types](#for-vector-types)
- [For FlatSet](#for-flatset)
- [What is a trivially relocatable type?](#what-is-a-trivially-relocatable-type)
- [Build](#build)
- [Build with CMake](#build-with-cmake)
- [Options](#options)
- [As a main project](#as-a-main-project)
- [As a sub-project with cmake](#as-a-sub-project-with-cmake)
- [Tested environments](#tested-environments)
Expand Down Expand Up @@ -81,6 +84,31 @@ For sets, time axis is in logarithmic scale.
- Templated code generation is minimized thanks to the late location of the integral N template parameter
- Optimized emulations of standard library features for older C++ compilers are provided when C++ version < C++17

A set of non standard methods and constructors are defined for convenience, provided that `amc` is compiled with `AMC_PEDANTIC` disabled (default, see [Options](#options)).
Here is a brief summary of these extras (compared to their STL equivalents):

#### For vector types
For all vectors (`FixedCapacityVector`, `SmallVector`, `vector`)
| Method | Description |
| -------------- | ------------------------------------------------------------ |
| `pop_back_val` | Same as `pop_back`, returning popped value. |
| `append` | Same as `insert(vec.end(), ...)` |
| `swap2` | Swap with all other flavors of vectors, not just `this` type |

For `SmallVector` only, there is a constructor from a rvalue of a `amc::vector` that allows stealing of its dynamic storage.

#### For FlatSet
| Method | Description |
| --------------- | ------------------------------------------------------------------------------------------ |
| `data` | Returns `data` const pointer from underlying vector |
| `operator[n]` | Access to the underlying value at position 'n' for the `FlatSet` |
| `at(n)` | Access to the underlying value at position 'n' for the `FlatSet`, throwing if our of range |
| `capacity` | Calls underlying vector `capacity` method |
| `reserve` | Calls underlying vector `reserve` method |
| `shrink_to_fit` | Calls `shrink_to_fit` of underlying vector |

There is an additional constructor and assignment operator from a rvalue of the underlying vector type, stealing its dynamic storage.

## What is a trivially relocatable type?

It describes the ability of moving around memory a value of type T by using `memcpy` (as opposed to the conservative approach of calling the copy constructor and the destroying the old temporary).
Expand All @@ -96,7 +124,16 @@ The most convenient way to mark a type as trivially relocatable is to declare in

This is only necessary for non trivially copyable types, because trivially copyable types are trivially relocatable by default.

## Build
## Build with CMake

### Options

| CMake flag | Description |
| --------------------- | ------------------------------------------------------------------------------------------------------------------ |
| AMC_ENABLE_TESTS | Build **amc** with unit tests (default if main project) |
| AMC_ENABLE_BENCHMARKS | Build **amc** with benchmarks against STL (default if main project and Release mode) |
| AMC_ENABLE_ASAN | Build with Address Sanitizer mode (only GCC and Clang) |
| AMC_PEDANTIC | If **OFF**, non standard methods and constructors are added for containers (see [Other benefits](#other-benefits)) |

### As a main project

Expand All @@ -107,15 +144,15 @@ Vectors and `FlatSet` containers require a C++11 compiler.

Unit tests and benchmarks are provided. They can be compiled with **cmake**.

By default, both will be compiled only if 'amc' is instantiated as the main project. You can manually force the build of the tests and benchmarks thanks to following flags:
By default, both will be compiled only if 'amc' is instantiated as the main project. You can manually force the build of the tests and benchmarks thanks to following `cmake` flags:
```
AMC_ENABLE_TESTS
AMC_ENABLE_BENCHMARKS
```

Bundled tests depend on [Google Test](https://github.com/google/googletest), benchmarks on [Google benchmarks](https://github.com/google/benchmark).

`cmake` will retrieve them automatically thanks to [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) feature.
If not installed on your machine, `cmake` will retrieve them automatically thanks to [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) feature.

To compile and launch the tests in `Debug` mode, simply launch

Expand Down Expand Up @@ -171,6 +208,8 @@ This library has been tested on Ubuntu 18.04 and Windows 10 (Visual Studio 2019)
- Clang from version 6.0
- MSVC 19.28
You can refer to the CI configurations (lots of compilers are tested) to see the full list of tested compilers.
## Usage examples
### Vectors
Expand Down
28 changes: 22 additions & 6 deletions include/amc/flatset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ class FlatSet : private Compare {
node_type &operator=(const node_type &) = delete;
node_type &operator=(node_type &&o) noexcept(std::is_nothrow_move_assignable<value_type>::value) = default;

~node_type() = default;

bool empty() const noexcept { return !_optV.has_value(); }
explicit operator bool() const noexcept { return _optV.has_value(); }
allocator_type get_allocator() const { return static_cast<allocator_type>(*this); }
Expand Down Expand Up @@ -142,6 +140,22 @@ class FlatSet : private Compare {

FlatSet(std::initializer_list<value_type> list, const Alloc &alloc) : FlatSet(list, Compare(), alloc) {}

#ifdef AMC_NONSTD_FEATURES
/// Non standard constructor of a FlatSet from a Vector, stealing its dynamic memory.
explicit FlatSet(VecType &&v, const Compare &comp = Compare(), const Alloc &alloc = Alloc())
: Compare(comp), _sortedVector(std::move(v), alloc) {
std::sort(_sortedVector.begin(), _sortedVector.end(), comp);
eraseDuplicates();
}

FlatSet &operator=(VecType &&v) {
_sortedVector = std::move(v);
std::sort(_sortedVector.begin(), _sortedVector.end(), compRef());
eraseDuplicates();
return *this;
}
#endif

FlatSet &operator=(std::initializer_list<value_type> list) {
_sortedVector.clear();
insert(list.begin(), list.end());
Expand All @@ -164,20 +178,22 @@ class FlatSet : private Compare {
const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(cend()); }
const_reverse_iterator crend() const noexcept { return const_reverse_iterator(cbegin()); }

#ifdef AMC_NONSTD_FEATURES
const_pointer data() const noexcept { return _sortedVector.data(); }

const_reference operator[](size_type idx) const { return _sortedVector[idx]; }

const_reference at(size_type idx) const { return _sortedVector.at(idx); }

bool empty() const noexcept { return _sortedVector.empty(); }
size_type size() const noexcept { return _sortedVector.size(); }
size_type max_size() const noexcept { return _sortedVector.max_size(); }

size_type capacity() const noexcept { return _sortedVector.capacity(); }
void reserve(size_type size) { _sortedVector.reserve(size); }

void shrink_to_fit() { _sortedVector.shrink_to_fit(); }
#endif

bool empty() const noexcept { return _sortedVector.empty(); }
size_type size() const noexcept { return _sortedVector.size(); }
size_type max_size() const noexcept { return _sortedVector.max_size(); }

void clear() noexcept { _sortedVector.clear(); }

Expand Down
2 changes: 0 additions & 2 deletions include/amc/smallset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,6 @@ class SmallSet {
node_type &operator=(const node_type &) = delete;
node_type &operator=(node_type &&o) noexcept(std::is_nothrow_move_assignable<value_type>::value) = default;

~node_type() = default;

bool empty() const noexcept { return !_optV.has_value(); }
explicit operator bool() const noexcept { return _optV.has_value(); }
allocator_type get_allocator() const { return static_cast<allocator_type>(*this); }
Expand Down
8 changes: 7 additions & 1 deletion include/amc/vectorcommon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1159,11 +1159,13 @@ class VectorImpl : public VectorDestr<T, Alloc, SizeType, WithInlineElements, Gr
this->decrSize();
}

#ifdef AMC_NONSTD_FEATURES
T pop_back_val() {
T lastEl = std::move(back());
pop_back();
return lastEl;
}
#endif

void clear() noexcept {
amc::destroy_n(this->begin(), this->size());
Expand Down Expand Up @@ -1310,7 +1312,11 @@ class VectorImpl : public VectorDestr<T, Alloc, SizeType, WithInlineElements, Gr
this->setSize(count);
}

// Additional convenient methods not present in std::vector
#ifndef AMC_NONSTD_FEATURES
protected:
#endif

// Additional convenient methods activated when non standard features are enabled

/// Like swap, but can take other vectors of same type with different inline number of elements
/// It has one drawback though: it can throw (as it can make SmallVectors grow)
Expand Down
37 changes: 24 additions & 13 deletions test/sets_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,20 +384,20 @@ TYPED_TEST(SetListMergeTest, MergeWithEmpty) {
using SetType = TypeParam;

SetType s1{0, 1};
SetType s2{};
SetType s2;
s1.merge(s2);
EXPECT_EQ(s1, SetType({0, 1}));
EXPECT_EQ(s2, SetType({}));
EXPECT_EQ(s2, SetType());
}

TYPED_TEST(SetListMergeTest, MergeFromEmpty) {
using SetType = TypeParam;

SetType s1{};
SetType s1;
SetType s2{0, 1};
s1.merge(s2);
EXPECT_EQ(s1, SetType({0, 1}));
EXPECT_EQ(s2, SetType({}));
EXPECT_EQ(s2, SetType());
}

TYPED_TEST(SetListMergeTest, MergeNewElems) {
Expand Down Expand Up @@ -455,6 +455,19 @@ TEST(FlatSetTest, MergeDifferentCompare) {
EXPECT_EQ(s2, RevSetType({19, 4, 2, -2}));
}

#ifdef AMC_SMALLSET
TEST(SmallSetTest, MergeDifferentCompare) {
using SetType = SmallSet<char, 20, std::less<char>>;
using RevSetType = SmallSet<char, 10, std::greater<char>>;
SetType s1{'B', 'D', 'E', 'G'};
RevSetType s2{'H', 'E', 'C', 'A'};
s1.merge(s2);
EXPECT_EQ(s1, SetType({'A', 'B', 'C', 'D', 'E', 'G', 'H'}));
EXPECT_EQ(s2, RevSetType({'E'}));
}
#endif

#ifdef AMC_NONSTD_FEATURES
TEST(FlatSetTest, SpecificPointerMethods) {
using SetType = FlatSet<int>;
SetType s{-2, 0, 2, 3, 4, 6, 19};
Expand All @@ -465,15 +478,13 @@ TEST(FlatSetTest, SpecificPointerMethods) {
EXPECT_THROW(s.at(7), std::out_of_range);
}

#ifdef AMC_SMALLSET
TEST(SmallSetTest, MergeDifferentCompare) {
using SetType = SmallSet<char, 20, std::less<char>>;
using RevSetType = SmallSet<char, 10, std::greater<char>>;
SetType s1{'B', 'D', 'E', 'G'};
RevSetType s2{'H', 'E', 'C', 'A'};
s1.merge(s2);
EXPECT_EQ(s1, SetType({'A', 'B', 'C', 'D', 'E', 'G', 'H'}));
EXPECT_EQ(s2, RevSetType({'E'}));
TEST(FlatSetTest, CreateFromVector) {
using VecType = amc::vector<int>;
using SetType = FlatSet<int, std::less<int>, amc::allocator<int>, VecType>;
VecType myVec = {5, -1, 6, 8, 0};
SetType s(std::move(myVec));
EXPECT_TRUE(myVec.empty());
EXPECT_EQ(s, SetType({-1, 0, 5, 6, 8}));
}
#endif
} // namespace amc
11 changes: 11 additions & 0 deletions test/vectors_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,12 @@ void ChecksAgainstTab(const VecType &cont, std::initializer_list<typename VecTyp
refTab.assign(v + 1, 42);
EXPECT_EQ(cpy, VecType(refTab.begin(), refTab.end()));

#ifdef AMC_NONSTD_FEATURES
ValueType lastEl = cpy.pop_back_val();
#else
ValueType lastEl = std::move(cpy.back());
cpy.pop_back();
#endif
EXPECT_EQ(lastEl, ValueType(42));
EXPECT_EQ(static_cast<int>(cpy.size()), v);
EXPECT_TRUE(cpy.empty() || cpy.back() == ValueType(42));
Expand Down Expand Up @@ -308,6 +313,7 @@ TEST(VectorTest, NonCopyableType) {
EXPECT_EQ(v[6], NonCopyableType());
}

#ifdef AMC_NONSTD_FEATURES
TEST(VectorTest, CustomSwap) {
using ObjType = NonTriviallyRelocatableType;
using Bar7Vector = FixedCapacityVector<ObjType, 7>;
Expand Down Expand Up @@ -372,6 +378,7 @@ TEST(VectorTest, CustomSwap) {
bar6.swap2(barvec2);
barvec2.swap2(bar6);
}
#endif

TEST(VectorTest, TrickyEmplace) {
using VectorType = vector<ComplexTriviallyRelocatableType>;
Expand Down Expand Up @@ -417,7 +424,9 @@ TEST(VectorTest, SizeTypeNoIntegerOverflowFixedCapacityVector) {
EXPECT_THROW(v.insert(v.begin() + 1, kTab, kTab + 6), ExceptionType);
v.resize(255);
int i = 4;
#ifdef AMC_NONSTD_FEATURES
EXPECT_THROW(v.append(1U, 0), ExceptionType);
#endif
EXPECT_THROW(v.push_back(0), ExceptionType);
EXPECT_THROW(v.push_back(i), ExceptionType);
EXPECT_THROW(v.emplace_back(0), ExceptionType);
Expand All @@ -431,7 +440,9 @@ TEST(VectorTest, SizeTypeNoIntegerOverflowSmallVector) {
const int kTab[] = {1, 2, 3, 4, 5, 6};
EXPECT_THROW(v.insert(v.begin() + 1, kTab, kTab + 6), ExceptionType);
v.resize(255);
#ifdef AMC_NONSTD_FEATURES
EXPECT_THROW(v.append(1, 0), ExceptionType);
#endif
EXPECT_THROW(v.push_back(0), ExceptionType);
EXPECT_THROW(v.push_back(4), ExceptionType);
EXPECT_THROW(v.emplace_back(0), ExceptionType);
Expand Down

0 comments on commit bbcd676

Please sign in to comment.