Skip to content

Are PLF Library Collections More Efficient Than the STL?

Author: Dominick Radcliffe

Collections are a crucial aspect of software development and they hold the data we need. Therefore, it is vital that these data structures be efficient and effective. The C++ Standard Template Library (STL) most notably houses the vector data structure.

The Premise

The PLF library makes some bold claims with its list implementation by calling it a drop-in replacement for std::vector.

Top 4 commonly used operations and their optimizations: - 293% faster insertion operations - 57% faster erasure - 77% faster sorting - 70% faster reversal

 

The Setup

Creating a test environment with some simple test cases to collect benchmarks. Using GCC 6.3.0 as the compiler and Google Benchmark to log run efficiency and times.

Benchmarking will use CPU cycles to determine efficiency and each test will be run 5 times to calculate an average score.

All tests will be setup in the style of unit tests to run benchmarks. Passing in a state to a range based for loop will now time that snippet: cpp static void BM_SomeFunction(benchmark::State& state) { for (auto _ : state) { // This code gets timed SomeFunction(); } }
Then you must register this function to run it: cpp // Register the function as a benchmark BENCHMARK(BM_SomeFunction); // Run the benchmark BENCHMARK_MAIN();

 

Insertion

Benchmarking a simple push_back operation on each of the lists is a proper starting point:

static void BM_VectorInsert(benchmark::State& state) {
    std::vector<int> list = {1, 2, 3, 4};
    for (auto _ : state) {
        list.push_back(1);
    }
}

static void BM_PLFInsert(benchmark::State& state) {
    plf::list<int> list = {1, 2, 3, 4};
    for (auto _ : state) {
        list.push_back(1);
    }
}

The results are as follows:
Vec: 112000000 PLF: 21333333
Vec: 112000000 PLF: 32000000
Vec: 100000000 PLF: 28000000
Vec: 100000000 PLF: 24888889
Vec: 100000000 PLF: 44800000

This gives us a 72% average increase in efficiency, sweet!

Erasure

For removal, just removing the last element in the list should suffice for a meaningful test.

static void BM_VectorErase(benchmark::State& state) {
    std::vector<int> list = {1, 2, 3, 4};

    for (auto _ : state) {
        list.erase(list.begin() + 3);
    }
}

static void BM_PLFErase(benchmark::State& state) {
    plf::list<int> list = {1, 2, 3, 4};

    for (auto _ : state) {
        list.remove(4);
    }
}

The results are as follows:
Vec: 1000000000 PLF: 298666667
Vec: 1039200800 PLF: 235789474
Vec: 1000505701 PLF: 186666667
Vec: 1004000372 PLF: 194782609
Vec: 1000060500 PLF: 228072727

With that, we have an approximate 53% increase, a lot closer estimate to what is advertised unlike insertion.

Sorting

For sorting I'll just use a randomized list and sort the vector in ascending order.

static void BM_VectorSort(benchmark::State& state) {
    std::vector<int> list = {4, 2, 1, 3};

    for (auto _ : state) {
        std::sort(list.begin(), list.end());
    }
}

static void BM_PLFSort(benchmark::State& state) {
    plf::list<int> list = {4, 2, 1, 3};

    for (auto _ : state) {
        list.sort();
    }
}

The results are as follows:
Vec: 172307692 PLF: 8960000
Vec: 298666667 PLF: 8960000
Vec: 213333333 PLF: 8960000
Vec: 235789474 PLF: 11150223
Vec: 235789474 PLF: 10000000

That's about a 95% increase which is great! The difference in using the standard library sort versus their built in method is quite significant.

 

Reversal

Reversing a list is the final topic I am going to cover, using our trusty code we have seen:

static void BM_VectorRev(benchmark::State& state) {
    std::vector<int> list = {1, 2, 3, 4};

    for (auto _ : state) {
        std::reverse(list.begin(), list.end());
    }
}

static void BM_PLFRev(benchmark::State& state) {
    plf::list<int> list = {1, 2, 3, 4};

    for (auto _ : state) {
        list.reverse();
    }
}

The results are as follows:
Vec: 1002004080 PLF: 224000000
Vec: 1100306030 PLF: 248888889
Vec: 1020500611 PLF: 235789474
Vec: 1803040021 PLF: 224000000
Vec: 1040200390 PLF: 298666667

That leaves us with an approximate 72% increase which is pretty spot on with what the PLF library claims.

Conclusion

After conducting all my tests between plf::list and std::vector, I can confidently conclude that the efficiency claims made by the PLF library do indeed have a solid backing and some of the tests even came close or outperformed what was advertised. However, it is crucial to keep note of differences in compilers, optimization levels, and CPU architectures when reading statistics such as these.

I hope you now have an idea what type of collections you may consider using in your future projects for peak efficiency!