Giter Club home page Giter Club logo

plf_list's Introduction

plf::list

A drop-in replacement for std::list with (on average):

  • 293% faster insertion
  • 57% faster erasure
  • 17% faster iteration
  • 77% faster sorting
  • 70% faster reversal
  • 91% faster remove/remove_if
  • 63% faster unique
  • 811% faster clear (1147900% for trivially-destructible types)
  • 1248% faster destruction (6350% for trivially-destructible types)
  • 20-24% faster performance overall in ordered use-case benchmarking(insertion, erasure and iteration on the fly and over time)

(Benchmarks performed on a haswell-based CPU under GCC 8.1: http://www.plflib.org/benchmarks_haswell_gcc.htm Insertion, erasure, and iteration percentages obtained as average of performance across 5 types from char to very large struct)

Documentation and function descriptions are here: https://plflib.org/list.htm plf::list is C++98/03/11/14/17/20/23/etc compatible.

plf_list's People

Contributors

mattreecebentley avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

plf_list's Issues

shrink_to_fit is bugged

	plf::list<int> wow;
	wow.push_back(1);
	wow.push_back(7);
	wow.push_back(3);
	wow.push_back(5);
	wow.push_back(4);
	const auto size1 = wow.size(); //5

	wow.shrink_to_fit();
	const auto size2 = wow.size(); //0

	wow.resize(4);
	const auto size3 = wow.size(); //4

	wow.shrink_to_fit();
	const auto size4 = wow.size(); //0

As you can see, shrink_to_fit() is not behaving properly.

plf_list.remove() leaves an element stuck in the list

Add the following test to plf_list_test_suite.cpp (remove ( ==5))

list1.remove(4)
failpass("should be empty list", 0 == list1.size())

Also replicated by:
plf::list<int*> x;
int a;
int b;
x.push_back(&a);
x.push_back(&b);
x.remove(&a);
x.remove(&b);
failpass("should be empty" 0 == x.size())

Love the list, we are seeing a 16% increase in performance. Luckily our own unittest alerted us to this problem.

share a way to print item in plf::list in GDB

add following to your ~/.gdbinit file:

#

define plflist
	if $argc == 0
		help plflist
	else
		set $end = $arg0.end_iterator.node_pointer
		set $current = $arg0.begin_iterator.node_pointer
		set $size = 0
		while $current != $end
			if $argc == 2
				printf "elem[%u]: ", $size
	                        p *($arg1*)(&($current->element))
			end
			if $argc == 3
				if $size == $arg2
					printf "elem[%u]: ", $size
	                                p *($arg1*)(&($current->element))
				end
			end
			set $current = $current->next
			set $size++
		end
		printf "plflist size = %u \n", $arg0.total_size
		if $argc == 1
			printf "plflist "
			whatis $arg0
			printf "Use plflist <variable_name> <element_type> to see the elements in the list.\n"
		end
	end
end

document plflist
	Prints plf::list<T> information.
	Syntax: plflist <list> <T> <idx>: Prints list size, if T defined all elements or just element at idx
	Examples:
	plflist l - prints list size and definition
	plflist l int - prints all elements and list size
	plflist l int 2 - prints the third element in the list (if exists) and list size
end

To use it in GDB:

##  plf::list<int> list1 = { 1, 2, 3, 4, 5 };

## print all items in list1
(gdb) plflist list1 int
elem[0]: $1 = 1
elem[1]: $2 = 2
elem[2]: $3 = 3
elem[3]: $4 = 4
elem[4]: $5 = 5
plflist size = 5 

## print fourth item in list1
(gdb) plflist list1 int 3
elem[3]: $6 = 4
plflist size = 5 

non-const unordered_find_single()

iterator unordered_find_single(const element_type &element_to_match) PLF_LIST_NOEXCEPT

I would expect this function to be marked const, if it [the function] cannot be marked const because of some internal (state?), the function should be declared const and the internal (state) mutable.

This function must be marked const.

unordered_find_if would be useful

It would be useful to have something equivalent to std::find_if (provide a predicate function) for the unordered_find functions.

Thanks for the great library

Bug: list can enter an invalid state, causing a hang due to infinite loop

Hi there,

number_of_erased_nodes can overflow and then cause problems in the next push_back/insert.

Add assert here:

insert(position, *it++);
assert(node_allocator_pair.number_of_erased_nodes != 0);  //<-- add this assert to catch the point in time at which it will overflow
--node_allocator_pair.number_of_erased_nodes;

This code will reproduce the hang:

#include "plf_list.h"

int main()
{
	plf::list<int> list_one;
	list_one.push_back(1);
	list_one.push_back(2);

	plf::list<int> error_list;
	error_list.push_back(1);
	error_list.push_back(2);
	error_list.push_back(3);
	error_list.push_back(4);
	error_list.erase(std::remove_if(error_list.begin(), error_list.end(), [](const auto i) { return i == 2 || i == 3; } ), error_list.end());   //<-- in here number_of_erased_nodes becomes 2 which will then cause the invalid state to happen in next call

	error_list.insert(error_list.end(), list_one.begin(), list_one.end());   //<-- invalid state caused in here
	error_list.push_back(5);   //<-- hangs in here (infinite loop somewhere else in the code because number_of_erased_nodes became 18446744073...)
}

Thanks

ranges reverse_view and such no longer work and give compile error

plf::list used to support for loop with reverse ranges, but now no longer compiles

plf::list<int> abc;
for (int x : std::ranges::reverse_view(abc)) {
}
for (int x : abc | std::views::reverse) {
}
for (int x : std::views::reverse(abc)) {
}

All of these give compile errors:

ranges(4854,36): error C2440: '': cannot convert from 'initializer list' to 'std::reverse_iterator<plf::list<int,std::allocator>::list_iterator>'
message : No constructor could take the source type, or constructor overload resolution was ambiguous

On MSVC 2022

Calling splice() on first element drops list elements

Calling void splice(const_iterator position, const_iterator location) where location is the first element in a list seems to drop elements from the list. This should reproduce it:

#include <iostream>
#include "plf_list.h"

void print(const plf::list<int>& list1)
{
  for (auto& elem : list1)
  {
    std::cout << elem << ' ';
  }
  std::cout << std::endl;
}

int main()
{
  plf::list<int> list1 = { 1, 2, 3, 4, 5 };

  // Outputs "1 2 3 4 5 "
  print(list1);

  // Shift 1 after 5:
  list1.splice(list1.end(), list1.begin());

  // Outputs "1 "
  print(list1);

  return 0;
}

Tested with v2.02.

Compile warning

On Visual Studio 2017, I get the warning:
warning C4458: declaration of 'end_node' hides class member

on this line:
inline PLF_LIST_FORCE_INLINE void destroy_all_node_pointers(group_pointer_type const group_to_process, const node_pointer_type end_node) PLF_LIST_NOEXCEPT

If you rename end_node parameter, this warning goes away.

PLF_CPP20_SUPPORT bugs insert due to multiple reasons. On Visual Studio latest version

with PLF_CPP20_SUPPORT enabled these issues occur:

  1. insert() returns void (should be iterator)
  2. insert() gives me other vague errors about not being able to find matching parameters, probably due to the iterator parameters that I don't fill in my code as that's not normally required.

I have to comment out PLF_CPP20_SUPPORT to make it compile.

missing splice interface

plf::list do not have same splice interface as std::list as below

void  splice(const_iterator __position, list&& __x, const_iterator __first,  const_iterator __last) noexcept

following code can compile through, change to plf::list, will failed to compile

#include <iostream>
#include <list>
#include "plf_list.h"

void print(const std::list<int>& l)
{
  for (auto& elem : l)
  {
    std::cout << elem << ' ';
  }
  std::cout << std::endl;
}

int main()
{
  std::list<int> list1 = { 1, 2, 3, 4, 5 };

  std::list<int> list2 = { 11, 22, 33, 44, 55 };
  list1.splice(list1.end(), list2, list2.begin(), list2.end());

  print(list1);
  print(list2);

  return 0;
}

missing std::sort on clang 12

 /home/runner/work/cage/cage/externals/plf/plf_list/plf_list.h:2790:4: error: no member named 'sort' in namespace 'std'; did you mean simply 'sort'?
                        PLF_SORT_FUNCTION(node_pointers, node_pointer, sort_dereferencer<comparison_function>(compare));
                        ^~~~~~~~~~~~~~~~~
                        sort
/home/runner/work/cage/cage/externals/plf/plf_list/plf_list.h:231:28: note: expanded from macro 'PLF_SORT_FUNCTION'
        #define PLF_SORT_FUNCTION std::sort
                                  ^~~~~

Error appears when compiling with clang 12 or clang 13. Otherwise clang 14 and clang 15 are passing.

I assume it is missing the include algorithm. The preprocesor if looks suspicious to me.

#if !defined(PLF_SORT_FUNCTION) || defined(PLF_CPP20_SUPPORT)

The PLF_SORT_FUNCTION is defined few lines above, and the PLF_CPP20_SUPPORT is not defined.

iterator operators not returning iterator reference

For parity with std::list, (at least in Visual Studio), the following should return a reference to the list_iterator, rather than a copy:

inline PLF_LIST_FORCE_INLINE list_iterator operator ++ () PLF_LIST_NOEXCEPT
inline PLF_LIST_FORCE_INLINE list_iterator operator -- () PLF_LIST_NOEXCEPT
inline list_iterator operator = (const list_iterator &rh) PLF_LIST_NOEXCEPT
inline list_iterator operator = (const list_iterator &&rh) PLF_LIST_NOEXCEPT

inline PLF_LIST_FORCE_INLINE list_reverse_iterator operator ++ () PLF_LIST_NOEXCEPT
inline PLF_LIST_FORCE_INLINE list_reverse_iterator operator -- () PLF_LIST_NOEXCEPT
inline list_reverse_iterator operator = (const list_reverse_iterator &rh) PLF_LIST_NOEXCEPT
inline list_reverse_iterator operator = (const list_reverse_iterator &&rh) PLF_LIST_NOEXCEPT

Move constructor crashed

Hi I suspected the move semantics are not handled properly. We are using your project but it crashed when constructing a list with move constructor.

		list(list &&source) PLF_LIST_NOEXCEPT:
			element_allocator_type(source),
			groups(std::move(source.groups)),
			end_node(std::move(source.end_node)),
			last_endpoint(std::move(source.last_endpoint)),
			end_iterator(reinterpret_cast<node_pointer_type>(&end_node)),
			begin_iterator((source.begin_iterator.node_pointer == source.end_iterator.node_pointer) ? reinterpret_cast<node_pointer_type>(&end_node) : std::move(source.begin_iterator)),
			node_pointer_allocator_pair(source.node_pointer_allocator_pair.total_number_of_elements),
			node_allocator_pair(source.node_allocator_pair.number_of_erased_nodes)
		{
			end_node.previous->next = begin_iterator.node_pointer->previous = end_iterator.node_pointer;
			source.groups.blank();
			source.node_pointer_allocator_pair.total_number_of_elements = 0;
                        
                        source.reset();   // NEED to clean out source to avoid crash
		}

Compiler warnings "type qualifiers ignored on cast result type"

Every usage of the macro

#define PLF_LIST_BLOCK_MIN static_cast<const group_size_type>(...)

results in a warning with GCC because const does not do anything in the cast result type.
The specific warning is -Wignored-qualifiers.

Removing const should fix it.

Cannot use non-const functors for sort

With std::list, I can use a functor with a non-const operator() when sorting. This can be helpful when the compare has to build some temporary data per item (like a display name), caching the value internally so that it doesn't have to build the display name every time that record is compared during the sort.

This can be fixed by adding a second, non-const operator() in sort_dereferencer with the same code as the const version. I am not sure this works on all compilers/platforms.

Fixes for memory errors

I ran some tests of plf_list with GCC's -fsanitize=undefined and -fsanitize=address, and found a few issues:

  • Check size to avoid performing a memcpy with a source pointer that might be null
  • Use std::memmove over std::memcpy where ranges might overlap
  • Avoid reading groups.last_endpoint_group when it might be out-of-bounds

plf_sanitize.patch.txt

splicing the last element to the end drops it

Calling splice() to move the last element to the end drops it

#include <iostream>
#include "plf_list.h"

void print(const plf::list<int>& list1)
{
  for (auto& elem : list1)
  {
    std::cout << elem << ' ';
  }
  std::cout << std::endl;
}

int main()
{
  plf::list<int> list1 = { 1, 2, 3, 4, 5 };

  // Outputs "1 2 3 4 5 "
  print(list1);

  // This *should* be a no-op:
  list1.splice(list1.end(), std::prev(list1.end()));

  // Outputs "1 2 3 4"
  print(list1);

  return 0;
}

Move assignment of empty list in gcc 5/6 results in a segfault

When building with gcc 5.4.1 and gcc 6.3.0 on Ubuntu 16.04 with --std=c++11 or c++14, assigning one empty plf::list to another results in a segfault.

There is no issue in gcc 7.2.

My repro test case:

#include "plf_list.h"

int main(int argc, char* argv[])
{
   plf::list<int> testList;

   testList = plf::list<int>();
}

Regression in C++ standard compatibility

I was updating the plf_list recipe for Conan Center (conan-io/conan-center-index#21933) and noticed that after a version bump from v2.57 to v2.70 the library no longer only compiles without issues with the C++17 standard and compatible compiler versions. Older compiler versions (GCC < 7 and Clang < 5) fail with

In file included from plf_list/all/test_package/test_package.cpp:1:0:
plf_list.h: In member function ‘plf::list<element_type, allocator_type>::iterator plf::list<element_type, allocator_type>::unordered_find_single(const element_type&) const’:
plf_list.h:3497:45: error: missing template arguments before ‘(’ token
   return unordered_find_single(plf::equal_to(element_to_match));
                                             ^
plf_list.h: In member function ‘plf::list<plf::list<element_type, allocator_type>::list_iterator<false> > plf::list<element_type, allocator_type>::unordered_find_multiple(const element_type&, plf::list<element_type, allocator_type>::size_type) const’:
plf_list.h:3584:47: error: missing template arguments before ‘(’ token
   return unordered_find_multiple(plf::equal_to(element_to_match), number_to_find);
                                               ^
plf_list.h: In member function ‘plf::list<plf::list<element_type, allocator_type>::list_iterator<false> > plf::list<element_type, allocator_type>::unordered_find_all(const element_type&) const’:
plf_list.h:3651:42: error: missing template arguments before ‘(’ token
   return unordered_find_all(plf::equal_to(element_to_match));

I thought you might want to know as the stated expected compatibility is for C++98.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.