diff --git a/Builds/VisualStudio2013/Beast.props b/Builds/VisualStudio2013/Beast.props index 792f3409c..078aa95db 100644 --- a/Builds/VisualStudio2013/Beast.props +++ b/Builds/VisualStudio2013/Beast.props @@ -8,7 +8,7 @@ Level4 - BEAST_COMPILING_STATIC_LIBARARY=1;_CRTDBG_MAP_ALLOC;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + BEAST_COMPILING_STATIC_LIBARARY=1;_CRTDBG_MAP_ALLOC;_WIN32_WINNT=0x0600;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false $(RepoDir)\config;%(AdditionalIncludeDirectories) diff --git a/Builds/VisualStudio2013/beast.vcxproj b/Builds/VisualStudio2013/beast.vcxproj index d9b188b11..95f484156 100644 --- a/Builds/VisualStudio2013/beast.vcxproj +++ b/Builds/VisualStudio2013/beast.vcxproj @@ -116,6 +116,20 @@ + + + + + + + + + + + + + + @@ -125,6 +139,8 @@ + + @@ -152,6 +168,7 @@ + @@ -205,11 +222,13 @@ + + @@ -416,6 +435,12 @@ + + true + true + true + true + true true @@ -440,6 +465,13 @@ true true + + + true + true + true + true + true diff --git a/Builds/VisualStudio2013/beast.vcxproj.filters b/Builds/VisualStudio2013/beast.vcxproj.filters index 277ad5962..b57463e16 100644 --- a/Builds/VisualStudio2013/beast.vcxproj.filters +++ b/Builds/VisualStudio2013/beast.vcxproj.filters @@ -195,9 +195,6 @@ {92d1bb42-289a-4444-85c7-cb87540f2fff} - - {8832eb52-53f9-4850-8dc9-1d579a386a0e} - {5904368f-a0f2-4d26-a031-8cbe4448dc3f} @@ -297,6 +294,18 @@ {43cc0f2a-9905-4081-8104-48d2c4be9e7e} + + {48c7ee12-704c-42cb-99ea-9a486bb4b57e} + + + {e30eda19-95b4-4831-b86a-ee5fae88abd2} + + + {a4dca8cc-7d1f-4353-b7e1-15eab33e8bd4} + + + {8832eb52-53f9-4850-8dc9-1d579a386a0e} + @@ -1269,6 +1278,66 @@ beast\chrono + + beast + + + beast + + + beast\type_traits + + + beast\utility + + + beast\container\detail + + + beast\container\detail + + + beast\container + + + beast\container + + + beast\container + + + beast\container + + + beast\container + + + beast\container + + + beast\container + + + beast\container + + + beast\container\detail + + + beast\container\detail + + + beast\container\detail + + + beast + + + beast\container + + + beast\container + @@ -1847,6 +1916,15 @@ beast\chrono + + beast\chrono\impl + + + beast\container + + + beast\container\impl + diff --git a/beast/chrono/impl/basic_seconds_clock.cpp b/beast/chrono/impl/basic_seconds_clock.cpp index fcbdd17ee..6c12ac195 100644 --- a/beast/chrono/impl/basic_seconds_clock.cpp +++ b/beast/chrono/impl/basic_seconds_clock.cpp @@ -31,8 +31,7 @@ public: { beginTestCase ("now"); - auto const now (basic_seconds_clock < - std::chrono::steady_clock>::now ()); + basic_seconds_clock ::now (); pass (); } diff --git a/beast/container/Container.cpp b/beast/container/Container.cpp new file mode 100644 index 000000000..21948eb8f --- /dev/null +++ b/beast/container/Container.cpp @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "BeastConfig.h" + +#include "impl/aged_associative_container.cpp" diff --git a/beast/container/aged_container.h b/beast/container/aged_container.h new file mode 100644 index 000000000..726dbeb3a --- /dev/null +++ b/beast/container/aged_container.h @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_CONTAINER_H_INCLUDED +#define BEAST_CONTAINER_AGED_CONTAINER_H_INCLUDED + +#include + +namespace beast { + +template +struct is_aged_container + : std::false_type +{ +}; + +} + +#endif diff --git a/beast/container/aged_container_utility.h b/beast/container/aged_container_utility.h new file mode 100644 index 000000000..317f833d1 --- /dev/null +++ b/beast/container/aged_container_utility.h @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_CONTAINER_UTILITY_H_INCLUDED +#define BEAST_CONTAINER_AGED_CONTAINER_UTILITY_H_INCLUDED + +#include "aged_container.h" + +#include + +namespace beast { + +/** Expire aged container items past the specified age. */ +template +typename std::enable_if < + is_aged_container ::value, + std::size_t +>::type +expire (AgedContainer& c, std::chrono::duration const& age) +{ + std::size_t n (0); + auto const expired (c.clock().now() - age); + for (auto iter (c.chronological.cbegin()); + iter != c.chronological.cend() && + iter.when() <= expired;) + { + iter = c.erase (iter); + ++n; + } + return n; +} + +} + +#endif diff --git a/beast/container/aged_map.h b/beast/container/aged_map.h new file mode 100644 index 000000000..6475e853a --- /dev/null +++ b/beast/container/aged_map.h @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_MAP_H_INCLUDED +#define BEAST_CONTAINER_AGED_MAP_H_INCLUDED + +#include "detail/aged_ordered_container.h" + +#include +#include +#include + +namespace beast { + +template < + class Key, + class T, + class Duration = std::chrono::seconds, + class Compare = std::less , + class Allocator = std::allocator > +> +using aged_map = detail::aged_ordered_container < + false, true, Key, T, Duration, Compare, Allocator>; + +} + +#endif diff --git a/beast/container/aged_multimap.h b/beast/container/aged_multimap.h new file mode 100644 index 000000000..58a060dce --- /dev/null +++ b/beast/container/aged_multimap.h @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_MULTIMAP_H_INCLUDED +#define BEAST_CONTAINER_AGED_MULTIMAP_H_INCLUDED + +#include "detail/aged_ordered_container.h" + +#include +#include +#include + +namespace beast { + +template < + class Key, + class T, + class Duration = std::chrono::seconds, + class Compare = std::less , + class Allocator = std::allocator > +> +using aged_multimap = detail::aged_ordered_container < + true, true, Key, T, Duration, Compare, Allocator>; + +} + +#endif diff --git a/beast/container/aged_multiset.h b/beast/container/aged_multiset.h new file mode 100644 index 000000000..ce420977f --- /dev/null +++ b/beast/container/aged_multiset.h @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_MULTISET_H_INCLUDED +#define BEAST_CONTAINER_AGED_MULTISET_H_INCLUDED + +#include "detail/aged_ordered_container.h" + +#include +#include +#include + +namespace beast { + +template < + class Key, + class Duration = std::chrono::seconds, + class Compare = std::less , + class Allocator = std::allocator +> +using aged_multiset = detail::aged_ordered_container < + true, false, Key, void, Duration, Compare, Allocator>; + +} + +#endif diff --git a/beast/container/aged_set.h b/beast/container/aged_set.h new file mode 100644 index 000000000..db69158ba --- /dev/null +++ b/beast/container/aged_set.h @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_SET_H_INCLUDED +#define BEAST_CONTAINER_AGED_SET_H_INCLUDED + +#include "detail/aged_ordered_container.h" + +#include +#include +#include + +namespace beast { + +template < + class Key, + class Duration = std::chrono::seconds, + class Compare = std::less , + class Allocator = std::allocator +> +using aged_set = detail::aged_ordered_container < + false, false, Key, void, Duration, Compare, Allocator>; + +} + +#endif diff --git a/beast/container/aged_unordered_map.h b/beast/container/aged_unordered_map.h new file mode 100644 index 000000000..909a1c7f1 --- /dev/null +++ b/beast/container/aged_unordered_map.h @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_UNORDERED_MAP_H_INCLUDED +#define BEAST_CONTAINER_AGED_UNORDERED_MAP_H_INCLUDED + +#include "detail/aged_unordered_container.h" + +#include +#include +#include + +namespace beast { + +template < + class Key, + class T, + class Duration = std::chrono::seconds, + class Hash = std::hash , + class KeyEqual = std::equal_to , + class Allocator = std::allocator > +> +using aged_unordered_map = detail::aged_unordered_container < + false, true, Key, T, Duration, Hash, KeyEqual, Allocator>; + +} + +#endif diff --git a/beast/container/aged_unordered_multimap.h b/beast/container/aged_unordered_multimap.h new file mode 100644 index 000000000..b3270d81a --- /dev/null +++ b/beast/container/aged_unordered_multimap.h @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_UNORDERED_MULTIMAP_H_INCLUDED +#define BEAST_CONTAINER_AGED_UNORDERED_MULTIMAP_H_INCLUDED + +#include "detail/aged_unordered_container.h" + +#include +#include +#include + +namespace beast { + +template < + class Key, + class T, + class Duration = std::chrono::seconds, + class Hash = std::hash , + class KeyEqual = std::equal_to , + class Allocator = std::allocator > +> +using aged_unordered_multimap = detail::aged_unordered_container < + true, true, Key, T, Duration, Hash, KeyEqual, Allocator>; + +} + +#endif diff --git a/beast/container/aged_unordered_multiset.h b/beast/container/aged_unordered_multiset.h new file mode 100644 index 000000000..b121ad9bb --- /dev/null +++ b/beast/container/aged_unordered_multiset.h @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_UNORDERED_MULTISET_H_INCLUDED +#define BEAST_CONTAINER_AGED_UNORDERED_MULTISET_H_INCLUDED + +#include "detail/aged_unordered_container.h" + +#include +#include +#include + +namespace beast { + +template < + class Key, + class Duration = std::chrono::seconds, + class Hash = std::hash , + class KeyEqual = std::equal_to , + class Allocator = std::allocator +> +using aged_unordered_multiset = detail::aged_unordered_container < + true, false, Key, void, Duration, Hash, KeyEqual, Allocator>; + +} + +#endif diff --git a/beast/container/aged_unordered_set.h b/beast/container/aged_unordered_set.h new file mode 100644 index 000000000..8c9090b45 --- /dev/null +++ b/beast/container/aged_unordered_set.h @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_UNORDERED_SET_H_INCLUDED +#define BEAST_CONTAINER_AGED_UNORDERED_SET_H_INCLUDED + +#include "detail/aged_unordered_container.h" + +#include +#include +#include + +namespace beast { + +template < + class Key, + class Duration = std::chrono::seconds, + class Hash = std::hash , + class KeyEqual = std::equal_to , + class Allocator = std::allocator +> +using aged_unordered_set = detail::aged_unordered_container < + false, false, Key, void, Duration, Hash, KeyEqual, Allocator>; + +} + +#endif diff --git a/beast/container/detail/aged_associative_container.h b/beast/container/detail/aged_associative_container.h new file mode 100644 index 000000000..df0bb1d7c --- /dev/null +++ b/beast/container/detail/aged_associative_container.h @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_ASSOCIATIVE_CONTAINER_H_INCLUDED +#define BEAST_CONTAINER_AGED_ASSOCIATIVE_CONTAINER_H_INCLUDED + +#include + +namespace beast { +namespace detail { + +// Extracts the key portion of value +template +struct aged_associative_container_extract_t +{ + template + decltype (Value::first) const& + operator() (Value const& value) const + { + return value.first; + } +}; + +template <> +struct aged_associative_container_extract_t +{ + template + Value const& + operator() (Value const& value) const + { + return value; + } +}; + +} +} + +#endif diff --git a/beast/container/detail/aged_container_iterator.h b/beast/container/detail/aged_container_iterator.h new file mode 100644 index 000000000..363447c41 --- /dev/null +++ b/beast/container/detail/aged_container_iterator.h @@ -0,0 +1,156 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_CONTAINER_ITERATOR_H_INCLUDED +#define BEAST_CONTAINER_AGED_CONTAINER_ITERATOR_H_INCLUDED + +#include +#include + +namespace beast { + +template +class aged_ordered_container; + +namespace detail { + +// Idea for Base template argument to prevent having to repeat +// the base class declaration comes from newbiz on ##c++/Freenode +// +// If Iterator is SCARY then this iterator will be as well. +template < + bool is_const, + class Iterator, + class Base = + std::iterator < + typename std::iterator_traits ::iterator_category, + typename std::conditional ::type, + typename std::iterator_traits ::difference_type> +> +class aged_container_iterator + : public Base +{ +public: + typedef typename Iterator::value_type::stashed::time_point time_point; + + aged_container_iterator () + { + } + + template + aged_container_iterator (aged_container_iterator < + false, OtherIterator, OtherBase> const& other) + : m_iter (other.m_iter) + { + } + + template + aged_container_iterator& operator= (aged_container_iterator < + other_is_const, OtherIterator, OtherBase> const& other) + { + m_iter = other.m_iter; + return *this; + } + + template + bool operator== (aged_container_iterator < + other_is_const, OtherIterator, OtherBase> const& other) const + { + return m_iter == other.m_iter; + } + + template + bool operator!= (aged_container_iterator < + other_is_const, OtherIterator, OtherBase> const& other) const + { + return m_iter != other.m_iter; + } + + aged_container_iterator& operator++ () + { + ++m_iter; + return *this; + } + + aged_container_iterator operator++ (int) + { + aged_container_iterator const prev (*this); + ++m_iter; + return prev; + } + + aged_container_iterator& operator-- () + { + --m_iter; + return *this; + } + + aged_container_iterator operator-- (int) + { + aged_container_iterator const prev (*this); + --m_iter; + return prev; + } + + typename Base::reference operator* () const + { + return m_iter->value; + } + + typename Base::pointer operator-> () const + { + return &m_iter->value; + } + + time_point const& when () const + { + return m_iter->when; + } + +private: + template + friend class aged_ordered_container; + + template + friend class aged_unordered_container; + + template + friend class aged_container_iterator; + + template + aged_container_iterator (OtherIterator const& iter) + : m_iter (iter) + { + } + + Iterator const& iterator() const + { + return m_iter; + } + + Iterator m_iter; +}; + +} + +} + +#endif diff --git a/beast/container/detail/aged_ordered_container.h b/beast/container/detail/aged_ordered_container.h new file mode 100644 index 000000000..2759fd5b0 --- /dev/null +++ b/beast/container/detail/aged_ordered_container.h @@ -0,0 +1,1927 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_ORDERED_CONTAINER_H_INCLUDED +#define BEAST_CONTAINER_AGED_ORDERED_CONTAINER_H_INCLUDED + +#include "aged_container_iterator.h" +#include "aged_associative_container.h" + +#include "../aged_container.h" + +#include "../../chrono/abstract_clock.h" +#include "../../equal.h" +#include "../../equal_to.h" +#include "../../is_constructible.h" +#include "../../utility/empty_base_optimization.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace detail { + +/** Associative container where each element is also indexed by time. + + This container mirrors the interface of the standard library ordered + associative containers, with the addition that each element is associated + with a `when` `time_point` which is obtained from the value of the clock's + `now`. The function `touch` updates the time for an element to the current + time as reported by the clock. + + An extra set of iterator types and member functions are provided in the + `chronological` memberspace that allow traversal in temporal or reverse + temporal order. This container is useful as a building block for caches + whose items expire after a certain amount of time. The chronological + iterators allow for fully customizable expiration strategies. + + @see aged_set, aged_multiset, aged_map, aged_multimap +*/ +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Duration = std::chrono::seconds, + class Compare = std::less , + class Allocator = std::allocator < + typename std::conditional , + Key>::type> +> +class aged_ordered_container +{ +public: + typedef abstract_clock clock_type; + typedef typename clock_type::time_point time_point; + typedef typename clock_type::duration duration; + typedef Key key_type; + typedef T mapped_type; + typedef typename std::conditional < + IsMap, + std::pair , + Key>::type value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + // Introspection (for unit tests) + typedef std::false_type is_unordered; + typedef std::integral_constant is_multi; + typedef std::integral_constant is_map; + + // VFALCO TODO How can we reorder the declarations to keep + // all the public things together contiguously? + +private: + static Key const& extract (value_type const& value) + { + return aged_associative_container_extract_t () (value); + } + + // VFALCO TODO hoist to remove template argument dependencies + struct element + : boost::intrusive::set_base_hook < + boost::intrusive::link_mode < + boost::intrusive::normal_link> + > + , boost::intrusive::list_base_hook < + boost::intrusive::link_mode < + boost::intrusive::normal_link> + > + { + // Stash types here so the iterator doesn't + // need to see the container declaration. + struct stashed + { + typedef typename aged_ordered_container::value_type value_type; + typedef typename aged_ordered_container::time_point time_point; + }; + + element ( + time_point const& when_, + value_type const& value_) + : value (value_) + , when (when_) + { + } + + element ( + time_point const& when_, + value_type&& value_) + : value (std::move (value_)) + , when (when_) + { + } + + template < + class... Args, + class = typename std::enable_if < + std::is_constructible ::value>::type + > + element (time_point const& when_, Args&&... args) + : value (std::forward (args)...) + , when (when_) + { + } + + value_type value; + time_point when; + }; + + // VFALCO TODO This should only be enabled for maps. + class pair_value_compare + : private empty_base_optimization + , public std::binary_function + { + public: + bool operator() (value_type const& lhs, value_type const& rhs) const + { + return this->member() (lhs.first, rhs.first); + } + + pair_value_compare () + { + } + + pair_value_compare (pair_value_compare const& other) + : empty_base_optimization (other) + { + } + + private: + friend aged_ordered_container; + + pair_value_compare (Compare const& compare) + : empty_base_optimization (compare) + { + } + }; + + // Compares value_type against element, used in insert_check + // VFALCO TODO hoist to remove template argument dependencies + class KeyValueCompare + : private empty_base_optimization + , public std::binary_function + { + public: + KeyValueCompare () + { + } + + KeyValueCompare (Compare const& compare) + : empty_base_optimization (compare) + { + } + + // VFALCO NOTE WE might want only to enable these overloads + // if Compare has is_transparent +#if 0 + template + bool operator() (K const& k, element const& e) const + { + return this->member() (k, extract (e.value)); + } + + template + bool operator() (element const& e, K const& k) const + { + return this->member() (extract (e.value), k); + } +#endif + + bool operator() (Key const& k, element const& e) const + { + return this->member() (k, extract (e.value)); + } + + bool operator() (element const& e, Key const& k) const + { + return this->member() (extract (e.value), k); + } + + Compare& compare() + { + return empty_base_optimization ::member(); + } + + Compare const& compare() const + { + return empty_base_optimization ::member(); + } + }; + + typedef typename boost::intrusive::make_list + >::type list_type; + + typedef typename std::conditional < + IsMulti, + typename boost::intrusive::make_multiset + >::type, + typename boost::intrusive::make_set + >::type + >::type cont_type; + + typedef typename std::allocator_traits < + Allocator>::template rebind_alloc ElementAllocator; + + using ElementAllocatorTraits = std::allocator_traits ; + + class config_t + : private KeyValueCompare + , private empty_base_optimization + { + public: + explicit config_t ( + clock_type& clock_) + : clock (clock_) + { + } + + config_t ( + clock_type& clock_, + Compare const& comp) + : KeyValueCompare (comp) + , clock (clock_) + { + } + + config_t ( + clock_type& clock_, + Allocator const& alloc_) + : empty_base_optimization (alloc_) + , clock (clock_) + { + } + + config_t ( + clock_type& clock_, + Compare const& comp, + Allocator const& alloc_) + : KeyValueCompare (comp) + , empty_base_optimization (alloc_) + , clock (clock_) + { + } + + config_t (config_t const& other) + : KeyValueCompare (other.key_compare()) + , empty_base_optimization ( + ElementAllocatorTraits:: + select_on_container_copy_construction ( + other.alloc())) + , clock (other.clock) + { + } + + config_t (config_t const& other, Allocator const& alloc) + : KeyValueCompare (other.key_compare()) + , empty_base_optimization (alloc) + , clock (other.clock) + { + } + + config_t (config_t&& other) + : KeyValueCompare (std::move (other.key_compare())) + , empty_base_optimization ( + std::move (other)) + , clock (other.clock) + { + } + + config_t (config_t&& other, Allocator const& alloc) + : KeyValueCompare (std::move (other.key_compare())) + , empty_base_optimization (alloc) + , clock (other.clock) + { + } + + config_t& operator= (config_t const& other) + { + if (this != &other) + { + compare() = other.compare(); + alloc() = other.alloc(); + clock = other.clock; + } + return *this; + } + + config_t& operator= (config_t&& other) + { + compare() = std::move (other.compare()); + alloc() = std::move (other.alloc()); + clock = other.clock; + return *this; + } + + Compare& compare () + { + return KeyValueCompare::compare(); + } + + Compare const& compare () const + { + return KeyValueCompare::compare(); + } + + KeyValueCompare& key_compare() + { + return *this; + } + + KeyValueCompare const& key_compare() const + { + return *this; + } + + ElementAllocator& alloc() + { + return empty_base_optimization < + ElementAllocator>::member(); + } + + ElementAllocator const& alloc() const + { + return empty_base_optimization < + ElementAllocator>::member(); + } + + std::reference_wrapper clock; + }; + + template + element* new_element (Args&&... args) + { + element* const p ( + ElementAllocatorTraits::allocate (m_config.alloc(), 1)); + ElementAllocatorTraits::construct (m_config.alloc(), + p, clock().now(), std::forward (args)...); + return p; + } + + void delete_element (element* p) + { + ElementAllocatorTraits::destroy (m_config.alloc(), p); + ElementAllocatorTraits::deallocate (m_config.alloc(), p, 1); + } + + void unlink_and_delete_element (element* p) + { + chronological.list.erase ( + chronological.list.iterator_to (*p)); + m_cont.erase (m_cont.iterator_to (*p)); + delete_element (p); + } + +public: + typedef Compare key_compare; + typedef typename std::conditional < + IsMap, + pair_value_compare, + Compare>::type value_compare; + typedef Allocator allocator_type; + typedef value_type& reference; + typedef value_type const& const_reference; + typedef typename std::allocator_traits < + Allocator>::pointer pointer; + typedef typename std::allocator_traits < + Allocator>::const_pointer const_pointer; + + typedef detail::aged_container_iterator iterator; + typedef detail::aged_container_iterator const_iterator; + typedef detail::aged_container_iterator reverse_iterator; + typedef detail::aged_container_iterator const_reverse_iterator; + + //-------------------------------------------------------------------------- + // + // Chronological ordered iterators + // + // "Memberspace" + // http://accu.org/index.php/journals/1527 + // + //-------------------------------------------------------------------------- + + class chronological_t + { + public: + typedef detail::aged_container_iterator iterator; + typedef detail::aged_container_iterator const_iterator; + typedef detail::aged_container_iterator reverse_iterator; + typedef detail::aged_container_iterator const_reverse_iterator; + + iterator begin () + { + return iterator (list.begin()); + } + + const_iterator begin () const + { + return const_iterator (list.begin ()); + } + + const_iterator cbegin() const + { + return const_iterator (list.begin ()); + } + + iterator end () + { + return iterator (list.end ()); + } + + const_iterator end () const + { + return const_iterator (list.end ()); + } + + const_iterator cend () const + { + return const_iterator (list.end ()); + } + + reverse_iterator rbegin () + { + return reverse_iterator (list.rbegin()); + } + + const_reverse_iterator rbegin () const + { + return const_reverse_iterator (list.rbegin ()); + } + + const_reverse_iterator crbegin() const + { + return const_reverse_iterator (list.rbegin ()); + } + + reverse_iterator rend () + { + return reverse_iterator (list.rend ()); + } + + const_reverse_iterator rend () const + { + return const_reverse_iterator (list.rend ()); + } + + const_reverse_iterator crend () const + { + return const_reverse_iterator (list.rend ()); + } + + iterator iterator_to (value_type& value) + { + static_assert (std::is_standard_layout ::value, + "must be standard layout"); + return list.iterator_to (*reinterpret_cast ( + reinterpret_cast(&value)-((std::size_t) + std::addressof(((element*)0)->member)))); + } + + const_iterator iterator_to (value_type const& value) const + { + static_assert (std::is_standard_layout ::value, + "must be standard layout"); + return list.iterator_to (*reinterpret_cast ( + reinterpret_cast(&value)-((std::size_t) + std::addressof(((element*)0)->member)))); + } + + private: + chronological_t () + { + } + + chronological_t (chronological_t const&) = delete; + chronological_t (chronological_t&&) = delete; + + friend class aged_ordered_container; + list_type mutable list; + } chronological; + + //-------------------------------------------------------------------------- + // + // Construction + // + //-------------------------------------------------------------------------- + + explicit aged_ordered_container (clock_type& clock); + + aged_ordered_container (clock_type& clock, + Compare const& comp); + + aged_ordered_container (clock_type& clock, + Allocator const& alloc); + + aged_ordered_container (clock_type& clock, + Compare const& comp, Allocator const& alloc); + + template + aged_ordered_container (InputIt first, InputIt last, clock_type& clock); + + template + aged_ordered_container (InputIt first, InputIt last, clock_type& clock, + Compare const& comp); + + template + aged_ordered_container (InputIt first, InputIt last, clock_type& clock, + Allocator const& alloc); + + template + aged_ordered_container (InputIt first, InputIt last, clock_type& clock, + Compare const& comp, Allocator const& alloc); + + aged_ordered_container (aged_ordered_container const& other); + + aged_ordered_container (aged_ordered_container const& other, + Allocator const& alloc); + + aged_ordered_container (aged_ordered_container&& other); + + aged_ordered_container (aged_ordered_container&& other, + Allocator const& alloc); + + aged_ordered_container (std::initializer_list init, + clock_type& clock); + + aged_ordered_container (std::initializer_list init, + clock_type& clock, Compare const& comp); + + aged_ordered_container (std::initializer_list init, + clock_type& clock, Allocator const& alloc); + + aged_ordered_container (std::initializer_list init, + clock_type& clock, Compare const& comp, Allocator const& alloc); + + ~aged_ordered_container(); + + aged_ordered_container& + operator= (aged_ordered_container const& other); + + aged_ordered_container& + operator= (aged_ordered_container&& other); + + aged_ordered_container& + operator= (std::initializer_list init); + + allocator_type + get_allocator() const + { + return m_config.alloc(); + } + + clock_type& + clock() + { + return m_config.clock; + } + + clock_type const& + clock() const + { + return m_config.clock; + } + + //-------------------------------------------------------------------------- + // + // Element access (maps) + // + //-------------------------------------------------------------------------- + + template < + class K, + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if ::type> + typename std::conditional ::type& + at (K const& k); + + template < + class K, + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if ::type> + typename std::conditional ::type const& + at (K const& k) const; + + template < + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if ::type> + typename std::conditional ::type& + operator[] (Key const& key); + + template < + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if ::type> + typename std::conditional ::type& + operator[] (Key&& key); + + //-------------------------------------------------------------------------- + // + // Iterators + // + //-------------------------------------------------------------------------- + + iterator + begin () + { + return iterator (m_cont.begin()); + } + + const_iterator + begin () const + { + return const_iterator (m_cont.begin ()); + } + + const_iterator + cbegin() const + { + return const_iterator (m_cont.begin ()); + } + + iterator + end () + { + return iterator (m_cont.end ()); + } + + const_iterator + end () const + { + return const_iterator (m_cont.end ()); + } + + const_iterator + cend () const + { + return const_iterator (m_cont.end ()); + } + + reverse_iterator + rbegin () + { + return reverse_iterator (m_cont.rbegin()); + } + + const_reverse_iterator + rbegin () const + { + return const_reverse_iterator (m_cont.rbegin ()); + } + + const_reverse_iterator + crbegin() const + { + return const_reverse_iterator (m_cont.rbegin ()); + } + + reverse_iterator + rend () + { + return reverse_iterator (m_cont.rend ()); + } + + const_reverse_iterator + rend () const + { + return const_reverse_iterator (m_cont.rend ()); + } + + const_reverse_iterator + crend () const + { + return const_reverse_iterator (m_cont.rend ()); + } + + iterator + iterator_to (value_type& value) + { + static_assert (std::is_standard_layout ::value, + "must be standard layout"); + return m_cont.iterator_to (*reinterpret_cast ( + reinterpret_cast(&value)-((std::size_t) + std::addressof(((element*)0)->member)))); + } + + const_iterator + iterator_to (value_type const& value) const + { + static_assert (std::is_standard_layout ::value, + "must be standard layout"); + return m_cont.iterator_to (*reinterpret_cast ( + reinterpret_cast(&value)-((std::size_t) + std::addressof(((element*)0)->member)))); + } + + //-------------------------------------------------------------------------- + // + // Capacity + // + //-------------------------------------------------------------------------- + + bool + empty() const noexcept + { + return m_cont.empty(); + } + + size_type + size() const noexcept + { + return m_cont.size(); + } + + size_type + max_size() const noexcept + { + return m_config.max_size(); + } + + //-------------------------------------------------------------------------- + // + // Modifiers + // + //-------------------------------------------------------------------------- + + void + clear(); + + // map, set + template + auto + insert (value_type const& value) -> + typename std::enable_if >::type; + + // multimap, multiset + template + auto + insert (value_type const& value) -> + typename std::enable_if ::type; + + // set + template + auto + insert (value_type&& value) -> + typename std::enable_if >::type; + + // multiset + template + auto + insert (value_type&& value) -> + typename std::enable_if ::type; + + //--- + + // map, set + template + auto + insert (const_iterator hint, value_type const& value) -> + typename std::enable_if ::type; + + // multimap, multiset + template + typename std::enable_if ::type + insert (const_iterator const& /*hint*/, value_type const& value) + { + // VFALCO TODO Figure out how to utilize 'hint' + return insert (value); + } + + // map, set + template + auto + insert (const_iterator hint, value_type&& value) -> + typename std::enable_if ::type; + + // multimap, multiset + template + typename std::enable_if ::type + insert (const_iterator const& /*hint*/, value_type&& value) + { + // VFALCO TODO Figure out how to utilize 'hint' + return insert (std::move (value)); + } + + // map, multimap + template < + class P, + bool maybe_map = IsMap + > + typename std::enable_if ::value, + typename std::conditional + >::type + >::type + insert (P&& value) + { + return emplace (std::forward

(value)); + } + + // map, multimap + template < + class P, + bool maybe_map = IsMap + > + typename std::enable_if ::value, + typename std::conditional + >::type + >::type + insert (const_iterator hint, P&& value) + { + return emplace_hint (hint, std::forward

(value)); + } + + template + void + insert (InputIt first, InputIt const& last) + { + for (; first != last; ++first) + insert (cend(), *first); + } + + void + insert (std::initializer_list init) + { + insert (init.begin(), init.end()); + } + + // map, set + template + auto + emplace (Args&&... args) -> + typename std::enable_if >::type; + + // multiset, multimap + template + auto + emplace (Args&&... args) -> + typename std::enable_if ::type; + + // map, set + template + auto + emplace_hint (const_iterator const& hint, Args&&... args) -> + typename std::enable_if >::type; + + // multiset, multimap + template + typename std::enable_if ::type + emplace_hint (const_iterator const& /*hint*/, Args&&... args) + { + // VFALCO TODO Figure out how to utilize 'hint' + return emplace ( + std::forward (args)...); + } + + template + detail::aged_container_iterator + erase (detail::aged_container_iterator < + is_const, Iterator, Base> const& pos); + + template + detail::aged_container_iterator + erase (detail::aged_container_iterator < + is_const, Iterator, Base> first, + detail::aged_container_iterator < + is_const, Iterator, Base> const& last); + + template + auto + erase (K const& k) -> + size_type; + + void + swap (aged_ordered_container& other) noexcept; + + //-------------------------------------------------------------------------- + + template + void + touch (detail::aged_container_iterator < + is_const, Iterator, Base> const& pos) + { + touch (pos, clock().now()); + } + + template + size_type + touch (K const& k); + + //-------------------------------------------------------------------------- + // + // Lookup + // + //-------------------------------------------------------------------------- + + // VFALCO TODO Respect is_transparent (c++14) + template + size_type + count (K const& k) const + { + return m_cont.count (k, + std::cref (m_config.key_compare())); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + iterator + find (K const& k) + { + return iterator (m_cont.find (k, + std::cref (m_config.key_compare()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + const_iterator + find (K const& k) const + { + return const_iterator (m_cont.find (k, + std::cref (m_config.key_compare()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + std::pair + equal_range (K const& k) + { + auto const r (m_cont.equal_range (k, + std::cref (m_config.key_compare()))); + return std::make_pair (iterator (r.first), + iterator (r.second)); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + std::pair + equal_range (K const& k) const + { + auto const r (m_cont.equal_range (k, + std::cref (m_config.key_compare()))); + return std::make_pair (const_iterator (r.first), + const_iterator (r.second)); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + iterator + lower_bound (K const& k) + { + return iterator (m_cont.lower_bound (k, + std::cref (m_config.key_compare()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + const_iterator + lower_bound (K const& k) const + { + return const_iterator (m_cont.lower_bound (k, + std::cref (m_config.key_compare()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + iterator + upper_bound (K const& k) + { + return iterator (m_cont.upper_bound (k, + std::cref (m_config.key_compare()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + const_iterator + upper_bound (K const& k) const + { + return const_iterator (m_cont.upper_bound (k, + std::cref (m_config.key_compare()))); + } + + //-------------------------------------------------------------------------- + // + // Observers + // + //-------------------------------------------------------------------------- + + key_compare + key_comp() const + { + return m_config.compare(); + } + + // VFALCO TODO Should this return const reference for set? + value_compare + value_comp() const + { + return value_compare (m_config.compare()); + } + + //-------------------------------------------------------------------------- + // + // Comparison + // + //-------------------------------------------------------------------------- + + // This differs from the standard in that the comparison + // is only done on the key portion of the value type, ignoring + // the mapped type. + // + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherT, + class OtherDuration, + class OtherAllocator + > + bool + operator== ( + aged_ordered_container const& other) const; + + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherT, + class OtherDuration, + class OtherAllocator + > + bool + operator!= ( + aged_ordered_container const& other) const + { + return ! (this->operator== (other)); + } + + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherT, + class OtherDuration, + class OtherAllocator + > + bool + operator< ( + aged_ordered_container const& other) const + { + value_compare const comp (value_comp ()); + return std::lexicographical_compare ( + cbegin(), cend(), other.cbegin(), other.cend(), comp); + } + + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherT, + class OtherDuration, + class OtherAllocator + > + bool + operator<= ( + aged_ordered_container const& other) const + { + return ! (other < *this); + } + + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherT, + class OtherDuration, + class OtherAllocator + > + bool + operator> ( + aged_ordered_container const& other) const + { + return other < *this; + } + + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherT, + class OtherDuration, + class OtherAllocator + > + bool + operator>= ( + aged_ordered_container const& other) const + { + return ! (*this < other); + } + +private: + template + void + touch (detail::aged_container_iterator < + is_const, Iterator, Base> const& pos, + typename clock_type::time_point const& now); + + template ::propagate_on_container_swap::value> + typename std::enable_if ::type + swap_data (aged_ordered_container& other) noexcept; + + template ::propagate_on_container_swap::value> + typename std::enable_if ::type + swap_data (aged_ordered_container& other) noexcept; + +private: + config_t m_config; + cont_type mutable m_cont; +}; + +//------------------------------------------------------------------------------ + +template +aged_ordered_container :: +aged_ordered_container ( + clock_type& clock) + : m_config (clock) +{ +} + +template +aged_ordered_container :: +aged_ordered_container ( + clock_type& clock, + Compare const& comp) + : m_config (clock, comp) +{ +} + +template +aged_ordered_container :: +aged_ordered_container ( + clock_type& clock, + Allocator const& alloc) + : m_config (clock, alloc) +{ +} + +template +aged_ordered_container :: +aged_ordered_container ( + clock_type& clock, + Compare const& comp, + Allocator const& alloc) + : m_config (clock, comp, alloc) +{ +} + +template +template +aged_ordered_container :: +aged_ordered_container (InputIt first, InputIt last, + clock_type& clock) + : m_config (clock) +{ + insert (first, last); +} + +template +template +aged_ordered_container :: +aged_ordered_container (InputIt first, InputIt last, + clock_type& clock, + Compare const& comp) + : m_config (clock, comp) +{ + insert (first, last); +} + +template +template +aged_ordered_container :: +aged_ordered_container (InputIt first, InputIt last, + clock_type& clock, + Allocator const& alloc) + : m_config (clock, alloc) +{ + insert (first, last); +} + +template +template +aged_ordered_container :: +aged_ordered_container (InputIt first, InputIt last, + clock_type& clock, + Compare const& comp, + Allocator const& alloc) + : m_config (clock, comp, alloc) +{ + insert (first, last); +} + +template +aged_ordered_container :: +aged_ordered_container (aged_ordered_container const& other) + : m_config (other.m_config) +{ + insert (other.cbegin(), other.cend()); +} + +template +aged_ordered_container :: +aged_ordered_container (aged_ordered_container const& other, + Allocator const& alloc) + : m_config (other.m_config, alloc) +{ + insert (other.cbegin(), other.cend()); +} + +template +aged_ordered_container :: +aged_ordered_container (aged_ordered_container&& other) + : m_config (std::move (other.m_config)) + , m_cont (std::move (other.m_cont)) +{ + chronological.list = std::move (other.chronological.list); +} + +template +aged_ordered_container :: +aged_ordered_container (aged_ordered_container&& other, + Allocator const& alloc) + : m_config (std::move (other.m_config), alloc) +{ + insert (other.cbegin(), other.cend()); + other.clear (); +} + +template +aged_ordered_container :: +aged_ordered_container (std::initializer_list init, + clock_type& clock) + : m_config (clock) +{ + insert (init.begin(), init.end()); +} + +template +aged_ordered_container :: +aged_ordered_container (std::initializer_list init, + clock_type& clock, + Compare const& comp) + : m_config (clock, comp) +{ + insert (init.begin(), init.end()); +} + +template +aged_ordered_container :: +aged_ordered_container (std::initializer_list init, + clock_type& clock, + Allocator const& alloc) + : m_config (clock, alloc) +{ + insert (init.begin(), init.end()); +} + +template +aged_ordered_container :: +aged_ordered_container (std::initializer_list init, + clock_type& clock, + Compare const& comp, + Allocator const& alloc) + : m_config (clock, comp, alloc) +{ + insert (init.begin(), init.end()); +} + +template +aged_ordered_container :: +~aged_ordered_container() +{ + clear(); +} + +template +auto +aged_ordered_container :: +operator= (aged_ordered_container const& other) -> + aged_ordered_container& +{ + if (this != &other) + { + clear(); + this->m_config = other.m_config; + insert (other.begin(), other.end()); + } + return *this; +} + +template +auto +aged_ordered_container :: +operator= (aged_ordered_container&& other) -> + aged_ordered_container& +{ + clear(); + this->m_config = std::move (other.m_config); + insert (other.begin(), other.end()); + other.clear(); + return *this; +} + +template +auto +aged_ordered_container :: +operator= (std::initializer_list init) -> + aged_ordered_container& +{ + clear (); + insert (init); + return *this; +} + +//------------------------------------------------------------------------------ + +template +template +typename std::conditional ::type& +aged_ordered_container :: +at (K const& k) +{ + auto const iter (m_cont.find (k, + std::cref (m_config.key_compare()))); + if (iter == m_cont.end()) + throw std::out_of_range ("key not found"); + return iter->value.second; +} + +template +template +typename std::conditional ::type const& +aged_ordered_container :: +at (K const& k) const +{ + auto const iter (m_cont.find (k, + std::cref (m_config.key_compare()))); + if (iter == m_cont.end()) + throw std::out_of_range ("key not found"); + return iter->value.second; +} + +template +template +typename std::conditional ::type& +aged_ordered_container :: +operator[] (Key const& key) +{ + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (key, + std::cref (m_config.key_compare()), d)); + if (result.second) + { + element* const p (new_element ( + std::piecewise_construct, std::forward_as_tuple (key), + std::forward_as_tuple ())); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return p->value.second; + } + return result.first->value.second; +} + +template +template +typename std::conditional ::type& +aged_ordered_container :: +operator[] (Key&& key) +{ + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (key, + std::cref (m_config.key_compare()), d)); + if (result.second) + { + element* const p (new_element ( + std::piecewise_construct, + std::forward_as_tuple (std::move (key)), + std::forward_as_tuple ())); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return p->value.second; + } + return result.first->value.second; +} + +//------------------------------------------------------------------------------ + +template +void +aged_ordered_container :: +clear() +{ + for (auto iter (chronological.list.begin()); + iter != chronological.list.end();) + delete_element (&*iter++); + chronological.list.clear(); + m_cont.clear(); +} + +// map, set +template +template +auto +aged_ordered_container :: +insert (value_type const& value) -> + typename std::enable_if >::type +{ + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (extract (value), + std::cref (m_config.key_compare()), d)); + if (result.second) + { + element* const p (new_element (value)); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return std::make_pair (iterator (iter), true); + } + return std::make_pair (iterator (result.first), false); +} + +// multimap, multiset +template +template +auto +aged_ordered_container :: +insert (value_type const& value) -> + typename std::enable_if ::type +{ + auto const before (m_cont.upper_bound ( + extract (value), std::cref (m_config.key_compare()))); + element* const p (new_element (value)); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_before (before, *p)); + return iterator (iter); +} + +// set +template +template +auto +aged_ordered_container :: +insert (value_type&& value) -> + typename std::enable_if >::type +{ + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (extract (value), + std::cref (m_config.key_compare()), d)); + if (result.second) + { + element* const p (new_element (std::move (value))); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return std::make_pair (iterator (iter), true); + } + return std::make_pair (iterator (result.first), false); +} + +// multiset +template +template +auto +aged_ordered_container :: +insert (value_type&& value) -> + typename std::enable_if ::type +{ + auto const before (m_cont.upper_bound ( + extract (value), std::cref (m_config.key_compare()))); + element* const p (new_element (std::move (value))); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_before (before, *p)); + return iterator (iter); +} + +//--- + +// map, set +template +template +auto +aged_ordered_container :: +insert (const_iterator hint, value_type const& value) -> + typename std::enable_if ::type +{ + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (hint.iterator(), + extract (value), std::cref (m_config.key_compare()), d)); + if (result.second) + { + element* const p (new_element (value)); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return iterator (iter); + } + return iterator (result.first); +} + +// map, set +template +template +auto +aged_ordered_container :: +insert (const_iterator hint, value_type&& value) -> + typename std::enable_if ::type +{ + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (hint.iterator(), + extract (value), std::cref (m_config.key_compare()), d)); + if (result.second) + { + element* const p (new_element (std::move (value))); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return iterator (iter); + } + return iterator (result.first); +} + +// map, set +template +template +auto +aged_ordered_container :: +emplace (Args&&... args) -> + typename std::enable_if >::type +{ + // VFALCO NOTE Its unfortunate that we need to + // construct element here + element* const p (new_element ( + std::forward (args)...)); + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (extract (p->value), + std::cref (m_config.key_compare()), d)); + if (result.second) + { + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return std::make_pair (iterator (iter), true); + } + delete_element (p); + return std::make_pair (iterator (result.first), false); +} + +// multiset, multimap +template +template +auto +aged_ordered_container :: +emplace (Args&&... args) -> + typename std::enable_if ::type +{ + element* const p (new_element ( + std::forward (args)...)); + auto const before (m_cont.upper_bound (extract (p->value), + std::cref (m_config.key_compare()))); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_before (before, *p)); + return iterator (iter); +} + +// map, set +template +template +auto +aged_ordered_container :: +emplace_hint (const_iterator const& hint, Args&&... args) -> + typename std::enable_if >::type +{ + // VFALCO NOTE Its unfortunate that we need to + // construct element here + element* const p (new_element ( + std::forward (args)...)); + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (hint.iterator(), + extract (p->value), std::cref (m_config.key_compare()), d)); + if (result.second) + { + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return std::make_pair (iterator (iter), true); + } + delete_element (p); + return std::make_pair (iterator (result.first), false); +} + +template +template +auto +aged_ordered_container :: +erase (detail::aged_container_iterator < + is_const, Iterator, Base> const& pos) -> + detail::aged_container_iterator +{ + auto iter (pos.iterator()); + auto p (&*iter++); + unlink_and_delete_element (p); + return detail::aged_container_iterator < + false, Iterator, Base> (iter); +} + +template +template +auto +aged_ordered_container :: +erase (detail::aged_container_iterator < + is_const, Iterator, Base> first, + detail::aged_container_iterator < + is_const, Iterator, Base> const& last) -> + detail::aged_container_iterator +{ + for (; first != last;) + { + auto p (&*first++); + unlink_and_delete_element (p); + } + return detail::aged_container_iterator < + false, Iterator, Base> (first.iterator()); +} + +template +template +auto +aged_ordered_container :: +erase (K const& k) -> + size_type +{ + auto iter (m_cont.find (k, + std::cref (m_config.key_compare()))); + if (iter == m_cont.end()) + return 0; + size_type n (0); + for (;;) + { + auto p (&*iter++); + bool const done ( + m_config (*p, extract (iter->value))); + unlink_and_delete_element (p); + ++n; + if (done) + break; + } + return n; +} + +template +void +aged_ordered_container :: +swap (aged_ordered_container& other) noexcept +{ + swap_data (other); + std::swap (chronological, other.chronological); + std::swap (m_cont, other.m_cont); +} + +//------------------------------------------------------------------------------ + +template +template +auto +aged_ordered_container :: +touch (K const& k) -> + size_type +{ + auto const now (clock().now()); + size_type n (0); + auto const range (equal_range (k)); + for (auto iter : range) + { + touch (iter, now); + ++n; + } + return n; +} + +//------------------------------------------------------------------------------ + +template +template +bool +aged_ordered_container :: +operator== ( + aged_ordered_container const& other) const +{ + typedef aged_ordered_container Other; + if (size() != other.size()) + return false; + std::equal_to eq; + return std::equal (cbegin(), cend(), other.cbegin(), other.cend(), + [&eq, &other](value_type const& lhs, + typename Other::value_type const& rhs) + { + return eq (extract (lhs), other.extract (rhs)); + }); +} + +//------------------------------------------------------------------------------ + +template +template +void +aged_ordered_container :: +touch (detail::aged_container_iterator < + is_const, Iterator, Base> const& pos, + typename clock_type::time_point const& now) +{ + auto& e (*pos.iterator()); + e.when = now; + chronological.list.erase (chronological.list.iterator_to (e)); + chronological.list.push_back (e); +} + +template +template +typename std::enable_if ::type +aged_ordered_container :: +swap_data (aged_ordered_container& other) noexcept +{ + std::swap (m_config.key_compare(), other.m_config.key_compare()); + std::swap (m_config.alloc(), other.m_config.alloc()); + std::swap (m_config.clock, other.m_config.clock); +} + +template +template +typename std::enable_if ::type +aged_ordered_container :: +swap_data (aged_ordered_container& other) noexcept +{ + std::swap (m_config.key_compare(), other.m_config.key_compare()); + std::swap (m_config.clock, other.m_config.clock); +} + +} + +//------------------------------------------------------------------------------ + +template +struct is_aged_container > + : std::true_type +{ +}; + +// Free functions + +template +void swap ( + detail::aged_ordered_container & lhs, + detail::aged_ordered_container & rhs) noexcept +{ + lhs.swap (rhs); +} + +/** Expire aged container items past the specified age. */ +template +std::size_t expire (detail::aged_ordered_container < + IsMulti, IsMap, Key, T, Duration, Compare, Allocator>& c, + std::chrono::duration const& age) +{ + std::size_t n (0); + auto const expired (c.clock().now() - age); + for (auto iter (c.chronological.cbegin()); + iter != c.chronological.cend() && + iter.when() <= expired;) + { + iter = c.erase (iter); + ++n; + } + return n; +} + +} + +#endif diff --git a/beast/container/detail/aged_unordered_container.h b/beast/container/detail/aged_unordered_container.h new file mode 100644 index 000000000..f5e3ec3de --- /dev/null +++ b/beast/container/detail/aged_unordered_container.h @@ -0,0 +1,2485 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONTAINER_AGED_UNORDERED_CONTAINER_H_INCLUDED +#define BEAST_CONTAINER_AGED_UNORDERED_CONTAINER_H_INCLUDED + +#include "aged_container_iterator.h" +#include "aged_associative_container.h" + +#include "../aged_container.h" + +#include "../../chrono/abstract_clock.h" +#include "../../equal.h" +#include "../../equal_to.h" +#include "../../is_constructible.h" +#include "../../utility/empty_base_optimization.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + +TODO + +- Add constructor variations that take a bucket count + +- Review for noexcept and exception guarantees + +- Call the safe version of is_permutation that takes 4 iterators + +*/ + +#ifndef BEAST_NO_CXX14_IS_PERMUTATION +#define BEAST_NO_CXX14_IS_PERMUTATION 1 +#endif + +namespace beast { +namespace detail { + +/** Associative container where each element is also indexed by time. + + This container mirrors the interface of the standard library unordered + associative containers, with the addition that each element is associated + with a `when` `time_point` which is obtained from the value of the clock's + `now`. The function `touch` updates the time for an element to the current + time as reported by the clock. + + An extra set of iterator types and member functions are provided in the + `chronological` memberspace that allow traversal in temporal or reverse + temporal order. This container is useful as a building block for caches + whose items expire after a certain amount of time. The chronological + iterators allow for fully customizable expiration strategies. + + @see aged_unordered_set, aged_unordered_multiset + @see aged_unordered_map, aged_unordered_multimap +*/ +template < + bool IsMulti, + bool IsMap, + class Key, + class T, + class Duration = std::chrono::seconds, + class Hash = std::hash , + class KeyEqual = std::equal_to , + class Allocator = std::allocator < + typename std::conditional , + Key>::type> +> +class aged_unordered_container +{ +public: + typedef abstract_clock clock_type; + typedef typename clock_type::time_point time_point; + typedef typename clock_type::duration duration; + typedef Key key_type; + typedef T mapped_type; + typedef typename std::conditional , + Key>::type value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + // Introspection (for unit tests) + typedef std::true_type is_unordered; + typedef std::integral_constant is_multi; + typedef std::integral_constant is_map; + + // VFALCO TODO How can we reorder the declarations to keep + // all the public things together contiguously? + +private: + static Key const& extract (value_type const& value) + { + return aged_associative_container_extract_t () (value); + } + + // VFALCO TODO hoist to remove template argument dependencies + struct element + : boost::intrusive::unordered_set_base_hook < + boost::intrusive::link_mode < + boost::intrusive::normal_link> + > + , boost::intrusive::list_base_hook < + boost::intrusive::link_mode < + boost::intrusive::normal_link> + > + { + // Stash types here so the iterator doesn't + // need to see the container declaration. + struct stashed + { + typedef typename aged_unordered_container::value_type value_type; + typedef typename aged_unordered_container::time_point time_point; + }; + + element ( + time_point const& when_, + value_type const& value_) + : value (value_) + , when (when_) + { + } + + element ( + time_point const& when_, + value_type&& value_) + : value (std::move (value_)) + , when (when_) + { + } + + template < + class... Args, + class = typename std::enable_if < + std::is_constructible ::value>::type + > + element (time_point const& when_, Args&&... args) + : value (std::forward (args)...) + , when (when_) + { + } + + value_type value; + time_point when; + }; + + // VFALCO TODO hoist to remove template argument dependencies + class ValueHash + : private empty_base_optimization + , public std::unary_function + { + public: + ValueHash () + { + } + + ValueHash (Hash const& hash) + : empty_base_optimization (hash) + { + } + + std::size_t operator() (element const& e) const + { + return this->member() (extract (e.value)); + } + + Hash& hash_function() + { + return this->member(); + } + + Hash const& hash_function() const + { + return this->member(); + } + }; + + // Compares value_type against element, used in find/insert_check + // VFALCO TODO hoist to remove template argument dependencies + class KeyValueEqual + : private empty_base_optimization + , public std::binary_function + { + public: + KeyValueEqual () + { + } + + KeyValueEqual (KeyEqual const& keyEqual) + : empty_base_optimization (keyEqual) + { + } + + // VFALCO NOTE WE might want only to enable these overloads + // if KeyEqual has is_transparent +#if 0 + template + bool operator() (K const& k, element const& e) const + { + return this->member() (k, extract (e.value)); + } + + template + bool operator() (element const& e, K const& k) const + { + return this->member() (extract (e.value), k); + } +#endif + + bool operator() (Key const& k, element const& e) const + { + return this->member() (k, extract (e.value)); + } + + bool operator() (element const& e, Key const& k) const + { + return this->member() (extract (e.value), k); + } + + bool operator() (element const& lhs, element const& rhs) const + { + return this->member() (extract (lhs.value), extract (rhs.value)); + } + + KeyEqual& key_eq() + { + return this->member(); + } + + KeyEqual const& key_eq() const + { + return this->member(); + } + }; + + typedef typename boost::intrusive::make_list + >::type list_type; + + typedef typename std::conditional < + IsMulti, + typename boost::intrusive::make_unordered_multiset , + boost::intrusive::hash , + boost::intrusive::equal , + boost::intrusive::cache_begin + >::type, + typename boost::intrusive::make_unordered_set , + boost::intrusive::hash , + boost::intrusive::equal , + boost::intrusive::cache_begin + >::type + >::type cont_type; + + typedef typename cont_type::bucket_type bucket_type; + typedef typename cont_type::bucket_traits bucket_traits; + + typedef typename std::allocator_traits < + Allocator>::template rebind_alloc ElementAllocator; + + using ElementAllocatorTraits = std::allocator_traits ; + + typedef typename std::allocator_traits < + Allocator>::template rebind_alloc BucketAllocator; + + using BucketAllocatorTraits = std::allocator_traits ; + + class config_t + : private ValueHash + , private KeyValueEqual + , private empty_base_optimization + { + public: + explicit config_t ( + clock_type& clock_) + : clock (clock_) + { + } + + config_t ( + clock_type& clock_, + Hash const& hash) + : ValueHash (hash) + , clock (clock_) + { + } + + config_t ( + clock_type& clock_, + KeyEqual const& keyEqual) + : KeyValueEqual (keyEqual) + , clock (clock_) + { + } + + config_t ( + clock_type& clock_, + Allocator const& alloc_) + : empty_base_optimization (alloc_) + , clock (clock_) + { + } + + config_t ( + clock_type& clock_, + Hash const& hash, + KeyEqual const& keyEqual) + : ValueHash (hash) + , KeyValueEqual (keyEqual) + , clock (clock_) + { + } + + config_t ( + clock_type& clock_, + Hash const& hash, + Allocator const& alloc_) + : ValueHash (hash) + , empty_base_optimization (alloc_) + , clock (clock_) + { + } + + config_t ( + clock_type& clock_, + KeyEqual const& keyEqual, + Allocator const& alloc_) + : KeyValueEqual (keyEqual) + , empty_base_optimization (alloc_) + , clock (clock_) + { + } + + config_t ( + clock_type& clock_, + Hash const& hash, + KeyEqual const& keyEqual, + Allocator const& alloc_) + : ValueHash (hash) + , KeyValueEqual (keyEqual) + , empty_base_optimization (alloc_) + , clock (clock_) + { + } + + config_t (config_t const& other) + : ValueHash (other.hash_function()) + , KeyValueEqual (other.key_eq()) + , empty_base_optimization ( + ElementAllocatorTraits:: + select_on_container_copy_construction ( + other.alloc())) + , clock (other.clock) + { + } + + config_t (config_t const& other, Allocator const& alloc) + : ValueHash (other.hash_function()) + , KeyValueEqual (other.key_eq()) + , empty_base_optimization (alloc) + , clock (other.clock) + { + } + + config_t (config_t&& other) + : ValueHash (std::move (other.hash_function())) + , KeyValueEqual (std::move (other.key_eq())) + , empty_base_optimization ( + std::move (other.alloc())) + , clock (other.clock) + { + } + + config_t (config_t&& other, Allocator const& alloc) + : ValueHash (std::move (other.hash_function())) + , KeyValueEqual (std::move (other.key_eq())) + , empty_base_optimization (alloc) + , clock (other.clock) + { + } + + config_t& operator= (config_t const& other) + { + hash_function() = other.hash_function(); + key_eq() = other.key_eq(); + alloc() = other.alloc(); + clock = other.clock; + return *this; + } + + config_t& operator= (config_t&& other) + { + hash_function() = std::move (other.hash_function()); + key_eq() = std::move (other.key_eq()); + alloc() = std::move (other.alloc()); + clock = other.clock; + return *this; + } + + ValueHash& value_hash() + { + return *this; + } + + ValueHash const& value_hash() const + { + return *this; + } + + Hash& hash_function() + { + return ValueHash::hash_function(); + } + + Hash const& hash_function() const + { + return ValueHash::hash_function(); + } + + KeyValueEqual& key_value_equal() + { + return *this; + } + + KeyValueEqual const& key_value_equal() const + { + return *this; + } + + KeyEqual& key_eq() + { + return key_value_equal().key_eq(); + } + + KeyEqual const& key_eq() const + { + return key_value_equal().key_eq(); + } + + ElementAllocator& alloc() + { + return empty_base_optimization < + ElementAllocator>::member(); + } + + ElementAllocator const& alloc() const + { + return empty_base_optimization < + ElementAllocator>::member(); + } + + std::reference_wrapper clock; + }; + + class Buckets + { + public: + typedef std::vector < + bucket_type, + typename std::allocator_traits :: + template rebind_alloc > vec_type; + + Buckets () + : m_max_load_factor (1.f) + , m_vec () + { + m_vec.resize ( + cont_type::suggested_upper_bucket_count (0)); + } + + Buckets (Allocator const& alloc) + : m_max_load_factor (1.f) + , m_vec (alloc) + { + m_vec.resize ( + cont_type::suggested_upper_bucket_count (0)); + } + + operator bucket_traits() + { + return bucket_traits (&m_vec[0], m_vec.size()); + } + + void clear() + { + m_vec.clear(); + } + + size_type max_bucket_count() const + { + return m_vec.max_size(); + } + + float& max_load_factor() + { + return m_max_load_factor; + } + + float const& max_load_factor() const + { + return m_max_load_factor; + } + + // count is the number of buckets + template + void rehash (size_type count, Container& c) + { + size_type const size (m_vec.size()); + if (count == size) + return; + if (count > m_vec.capacity()) + { + // Need two vectors otherwise we + // will destroy non-empty buckets. + vec_type vec (m_vec.get_allocator()); + std::swap (m_vec, vec); + m_vec.resize (count); + c.rehash (bucket_traits ( + &m_vec[0], m_vec.size())); + return; + } + // Rehash in place. + if (count > size) + { + // This should not reallocate since + // we checked capacity earlier. + m_vec.resize (count); + c.rehash (bucket_traits ( + &m_vec[0], count)); + return; + } + // Resize must happen after rehash otherwise + // we might destroy non-empty buckets. + c.rehash (bucket_traits ( + &m_vec[0], count)); + m_vec.resize (count); + } + + // Resize the buckets to accomodate at least n items. + template + void resize (size_type n, Container& c) + { + size_type const suggested ( + cont_type::suggested_upper_bucket_count (n)); + rehash (suggested, c); + } + + private: + float m_max_load_factor; + vec_type m_vec; + }; + + template + element* new_element (Args&&... args) + { + element* const p ( + ElementAllocatorTraits::allocate (m_config.alloc(), 1)); + ElementAllocatorTraits::construct (m_config.alloc(), + p, clock().now(), std::forward (args)...); + return p; + } + + void delete_element (element* p) + { + ElementAllocatorTraits::destroy (m_config.alloc(), p); + ElementAllocatorTraits::deallocate (m_config.alloc(), p, 1); + } + + void unlink_and_delete_element (element* p) + { + chronological.list.erase ( + chronological.list.iterator_to (*p)); + m_cont.erase (m_cont.iterator_to (*p)); + delete_element (p); + } + +public: + typedef Hash hasher; + typedef KeyEqual key_equal; + typedef Allocator allocator_type; + typedef value_type& reference; + typedef value_type const& const_reference; + typedef typename std::allocator_traits < + Allocator>::pointer pointer; + typedef typename std::allocator_traits < + Allocator>::const_pointer const_pointer; + + typedef detail::aged_container_iterator iterator; + typedef detail::aged_container_iterator const_iterator; + + typedef detail::aged_container_iterator local_iterator; + typedef detail::aged_container_iterator const_local_iterator; + + //-------------------------------------------------------------------------- + // + // Chronological ordered iterators + // + // "Memberspace" + // http://accu.org/index.php/journals/1527 + // + //-------------------------------------------------------------------------- + + class chronological_t + { + public: + typedef detail::aged_container_iterator iterator; + typedef detail::aged_container_iterator const_iterator; + typedef detail::aged_container_iterator reverse_iterator; + typedef detail::aged_container_iterator const_reverse_iterator; + + iterator begin () + { + return iterator (list.begin()); + } + + const_iterator begin () const + { + return const_iterator (list.begin ()); + } + + const_iterator cbegin() const + { + return const_iterator (list.begin ()); + } + + iterator end () + { + return iterator (list.end ()); + } + + const_iterator end () const + { + return const_iterator (list.end ()); + } + + const_iterator cend () const + { + return const_iterator (list.end ()); + } + + reverse_iterator rbegin () + { + return reverse_iterator (list.rbegin()); + } + + const_reverse_iterator rbegin () const + { + return const_reverse_iterator (list.rbegin ()); + } + + const_reverse_iterator crbegin() const + { + return const_reverse_iterator (list.rbegin ()); + } + + reverse_iterator rend () + { + return reverse_iterator (list.rend ()); + } + + const_reverse_iterator rend () const + { + return const_reverse_iterator (list.rend ()); + } + + const_reverse_iterator crend () const + { + return const_reverse_iterator (list.rend ()); + } + + iterator iterator_to (value_type& value) + { + static_assert (std::is_standard_layout ::value, + "must be standard layout"); + return list.iterator_to (*reinterpret_cast ( + reinterpret_cast(&value)-((std::size_t) + std::addressof(((element*)0)->member)))); + } + + const_iterator iterator_to (value_type const& value) const + { + static_assert (std::is_standard_layout ::value, + "must be standard layout"); + return list.iterator_to (*reinterpret_cast ( + reinterpret_cast(&value)-((std::size_t) + std::addressof(((element*)0)->member)))); + } + + private: + chronological_t () + { + } + + chronological_t (chronological_t const&) = delete; + chronological_t (chronological_t&&) = delete; + + friend class aged_unordered_container; + list_type mutable list; + } chronological; + + //-------------------------------------------------------------------------- + // + // Construction + // + //-------------------------------------------------------------------------- + + explicit aged_unordered_container (clock_type& clock); + + aged_unordered_container (clock_type& clock, Hash const& hash); + + aged_unordered_container (clock_type& clock, + KeyEqual const& key_eq); + + aged_unordered_container (clock_type& clock, + Allocator const& alloc); + + aged_unordered_container (clock_type& clock, + Hash const& hash, KeyEqual const& key_eq); + + aged_unordered_container (clock_type& clock, + Hash const& hash, Allocator const& alloc); + + aged_unordered_container (clock_type& clock, + KeyEqual const& key_eq, Allocator const& alloc); + + aged_unordered_container ( + clock_type& clock, Hash const& hash, KeyEqual const& key_eq, + Allocator const& alloc); + + template + aged_unordered_container (InputIt first, InputIt last, + clock_type& clock); + + template + aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, Hash const& hash); + + template + aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, KeyEqual const& key_eq); + + template + aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, Allocator const& alloc); + + template + aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, Hash const& hash, KeyEqual const& key_eq); + + template + aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, Hash const& hash, Allocator const& alloc); + + template + aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, KeyEqual const& key_eq, + Allocator const& alloc); + + template + aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, Hash const& hash, KeyEqual const& key_eq, + Allocator const& alloc); + + aged_unordered_container (aged_unordered_container const& other); + + aged_unordered_container (aged_unordered_container const& other, + Allocator const& alloc); + + aged_unordered_container (aged_unordered_container&& other); + + aged_unordered_container (aged_unordered_container&& other, + Allocator const& alloc); + + aged_unordered_container (std::initializer_list init, + clock_type& clock); + + aged_unordered_container (std::initializer_list init, + clock_type& clock, Hash const& hash); + + aged_unordered_container (std::initializer_list init, + clock_type& clock, KeyEqual const& key_eq); + + aged_unordered_container (std::initializer_list init, + clock_type& clock, Allocator const& alloc); + + aged_unordered_container (std::initializer_list init, + clock_type& clock, Hash const& hash, KeyEqual const& key_eq); + + aged_unordered_container (std::initializer_list init, + clock_type& clock, Hash const& hash, Allocator const& alloc); + + aged_unordered_container (std::initializer_list init, + clock_type& clock, KeyEqual const& key_eq, Allocator const& alloc); + + aged_unordered_container (std::initializer_list init, + clock_type& clock, Hash const& hash, KeyEqual const& key_eq, + Allocator const& alloc); + + ~aged_unordered_container(); + + aged_unordered_container& operator= (aged_unordered_container const& other); + + aged_unordered_container& operator= (aged_unordered_container&& other); + + aged_unordered_container& operator= (std::initializer_list init); + + allocator_type get_allocator() const + { + return m_config.alloc(); + } + + clock_type& clock() + { + return m_config.clock; + } + + clock_type const& clock() const + { + return m_config.clock; + } + + //-------------------------------------------------------------------------- + // + // Element access (maps) + // + //-------------------------------------------------------------------------- + + template < + class K, + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if ::type> + typename std::conditional ::type& + at (K const& k); + + template < + class K, + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if ::type> + typename std::conditional ::type const& + at (K const& k) const; + + template < + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if ::type> + typename std::conditional ::type& + operator[] (Key const& key); + + template < + bool maybe_multi = IsMulti, + bool maybe_map = IsMap, + class = typename std::enable_if ::type> + typename std::conditional ::type& + operator[] (Key&& key); + + //-------------------------------------------------------------------------- + // + // Iterators + // + //-------------------------------------------------------------------------- + + iterator + begin () + { + return iterator (m_cont.begin()); + } + + const_iterator + begin () const + { + return const_iterator (m_cont.begin ()); + } + + const_iterator + cbegin() const + { + return const_iterator (m_cont.begin ()); + } + + iterator + end () + { + return iterator (m_cont.end ()); + } + + const_iterator + end () const + { + return const_iterator (m_cont.end ()); + } + + const_iterator + cend () const + { + return const_iterator (m_cont.end ()); + } + + iterator + iterator_to (value_type& value) + { + static_assert (std::is_standard_layout ::value, + "must be standard layout"); + return m_cont.iterator_to (*reinterpret_cast ( + reinterpret_cast(&value)-((std::size_t) + std::addressof(((element*)0)->member)))); + } + + const_iterator + iterator_to (value_type const& value) const + { + static_assert (std::is_standard_layout ::value, + "must be standard layout"); + return m_cont.iterator_to (*reinterpret_cast ( + reinterpret_cast(&value)-((std::size_t) + std::addressof(((element*)0)->member)))); + } + + //-------------------------------------------------------------------------- + // + // Capacity + // + //-------------------------------------------------------------------------- + + bool empty() const noexcept + { + return m_cont.empty(); + } + + size_type size() const noexcept + { + return m_cont.size(); + } + + size_type max_size() const noexcept + { + return m_config.max_size(); + } + + //-------------------------------------------------------------------------- + // + // Modifiers + // + //-------------------------------------------------------------------------- + + void clear(); + + // map, set + template + auto + insert (value_type const& value) -> + typename std::enable_if >::type; + + // multimap, multiset + template + auto + insert (value_type const& value) -> + typename std::enable_if ::type; + + // map, set + template + auto + insert (value_type&& value) -> + typename std::enable_if >::type; + + // multimap, multiset + template + auto + insert (value_type&& value) -> + typename std::enable_if ::type; + + // map, set + template + typename std::enable_if ::type + insert (const_iterator /*hint*/, value_type const& value) + { + // Hint is ignored but we provide the interface so + // callers may use ordered and unordered interchangeably. + return insert (value).first; + } + + // multimap, multiset + template + typename std::enable_if ::type + insert (const_iterator const& /*hint*/, value_type const& value) + { + // VFALCO TODO The hint could be used to let + // the client order equal ranges + return insert (value); + } + + // map, set + template + typename std::enable_if ::type + insert (const_iterator /*hint*/, value_type&& value) + { + // Hint is ignored but we provide the interface so + // callers may use ordered and unordered interchangeably. + return insert (std::move (value)).first; + } + + // multimap, multiset + template + typename std::enable_if ::type + insert (const_iterator const& /*hint*/, value_type&& value) + { + // VFALCO TODO The hint could be used to let + // the client order equal ranges + return insert (std::move (value)); + } + + // map, multimap + template < + class P, + bool maybe_map = IsMap + > + typename std::enable_if ::value, + typename std::conditional + >::type + >::type + insert (P&& value) + { + return emplace (std::forward

(value)); + } + + // map, multimap + template < + class P, + bool maybe_map = IsMap + > + typename std::enable_if ::value, + typename std::conditional + >::type + >::type + insert (const_iterator hint, P&& value) + { + return emplace_hint (hint, std::forward

(value)); + } + + template + void insert (InputIt first, InputIt const& last) + { + insert (first, last, + typename std::iterator_traits < + InputIt>::iterator_category()); + } + + void + insert (std::initializer_list init) + { + insert (init.begin(), init.end()); + } + + // set, map + template + auto + emplace (Args&&... args) -> + typename std::enable_if >::type; + + // multiset, multimap + template + auto + emplace (Args&&... args) -> + typename std::enable_if ::type; + + // set, map + template + auto + emplace_hint (const_iterator const& /*hint*/, Args&&... args) -> + typename std::enable_if >::type; + + // multiset, multimap + template + typename std::enable_if ::type + emplace_hint (const_iterator const& /*hint*/, Args&&... args) + { + // VFALCO TODO The hint could be used for multi, to let + // the client order equal ranges + return emplace ( + std::forward (args)...); + } + + template + detail::aged_container_iterator + erase (detail::aged_container_iterator < + is_const, Iterator, Base> const& pos); + + template + detail::aged_container_iterator + erase (detail::aged_container_iterator < + is_const, Iterator, Base> first, + detail::aged_container_iterator < + is_const, Iterator, Base> const& last); + + template + auto + erase (K const& k) -> + size_type; + + void + swap (aged_unordered_container& other) noexcept; + + template + void + touch (detail::aged_container_iterator < + is_const, Iterator, Base> const& pos) + { + touch (pos, clock().now()); + } + + template + auto + touch (K const& k) -> + size_type; + + //-------------------------------------------------------------------------- + // + // Lookup + // + //-------------------------------------------------------------------------- + + // VFALCO TODO Respect is_transparent (c++14) + template + size_type + count (K const& k) const + { + return m_cont.count (k, std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal())); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + iterator + find (K const& k) + { + return iterator (m_cont.find (k, + std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + const_iterator + find (K const& k) const + { + return const_iterator (m_cont.find (k, + std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()))); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + std::pair + equal_range (K const& k) + { + auto const r (m_cont.equal_range (k, + std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()))); + return std::make_pair (iterator (r.first), + iterator (r.second)); + } + + // VFALCO TODO Respect is_transparent (c++14) + template + std::pair + equal_range (K const& k) const + { + auto const r (m_cont.equal_range (k, + std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()))); + return std::make_pair (const_iterator (r.first), + const_iterator (r.second)); + } + + //-------------------------------------------------------------------------- + // + // Bucket interface + // + //-------------------------------------------------------------------------- + + local_iterator begin (size_type n) + { + return local_iterator (m_cont.begin (n)); + } + + const_local_iterator begin (size_type n) const + { + return const_local_iterator (m_cont.begin (n)); + } + + const_local_iterator cbegin (size_type n) const + { + return const_local_iterator (m_cont.begin (n)); + } + + local_iterator end (size_type n) + { + return local_iterator (m_cont.end (n)); + } + + const_local_iterator end (size_type n) const + { + return const_local_iterator (m_cont.end (n)); + } + + const_local_iterator cend (size_type n) const + { + return const_local_iterator (m_cont.end (n)); + } + + size_type bucket_count() const + { + return m_cont.bucket_count(); + } + + size_type max_bucket_count() const + { + return m_buck.max_bucket_count(); + } + + size_type bucket_size (size_type n) const + { + return m_cont.bucket_size (n); + } + + size_type bucket (Key const& k) const + { + assert (bucket_count() != 0); + return m_cont.bucket (k, + std::cref (m_config.hash_function())); + } + + //-------------------------------------------------------------------------- + // + // Hash policy + // + //-------------------------------------------------------------------------- + + float load_factor() const + { + return size() / + static_cast (m_cont.bucket_count()); + } + + float max_load_factor() const + { + return m_buck.max_load_factor(); + } + + void max_load_factor (float ml) + { + m_buck.max_load_factor () = + std::max (ml, m_buck.max_load_factor()); + } + + void rehash (size_type count) + { + count = std::max (count, + size_type (size() / max_load_factor())); + m_buck.rehash (count, m_cont); + } + + void reserve (size_type count) + { + rehash (std::ceil (count / max_load_factor())); + } + + //-------------------------------------------------------------------------- + // + // Observers + // + //-------------------------------------------------------------------------- + + hasher const& hash_function() const + { + return m_config.hash_function(); + } + + key_equal const& key_eq () const + { + return m_config.key_eq(); + } + + //-------------------------------------------------------------------------- + // + // Comparison + // + //-------------------------------------------------------------------------- + + // This differs from the standard in that the comparison + // is only done on the key portion of the value type, ignoring + // the mapped type. + // + template < + bool OtherIsMap, + class OtherKey, + class OtherT, + class OtherDuration, + class OtherHash, + class OtherAllocator, + bool maybe_multi = IsMulti + > + typename std::enable_if ::type + operator== ( + aged_unordered_container const& other) const + { + if (size() != other.size()) + return false; + for (auto iter (cbegin()), last (cend()), olast (other.cend()); + iter != last; ++iter) + { + auto oiter (other.find (extract (*iter))); + if (oiter == olast) + return false; + } + return true; + } + + template < + bool OtherIsMap, + class OtherKey, + class OtherT, + class OtherDuration, + class OtherHash, + class OtherAllocator, + bool maybe_multi = IsMulti + > + typename std::enable_if ::type + operator== ( + aged_unordered_container const& other) const + { + if (size() != other.size()) + return false; + typedef std::pair EqRng; + for (auto iter (cbegin()), last (cend()); iter != last;) + { + auto const& k (extract (*iter)); + auto const eq (equal_range (k)); + auto const oeq (other.equal_range (k)); +#if BEAST_NO_CXX14_IS_PERMUTATION + if (std::distance (eq.first, eq.second) != + std::distance (oeq.first, oeq.second) || + ! std::is_permutation (eq.first, eq.second, oeq.first)) + return false; +#else + if (! std::is_permutation (eq.first, + eq.second, oeq.first, oeq.second)) + return false; +#endif + iter = eq.second; + } + return true; + } + + template < + bool OtherIsMulti, + bool OtherIsMap, + class OtherKey, + class OtherT, + class OtherDuration, + class OtherHash, + class OtherAllocator + > + bool operator!= ( + aged_unordered_container const& other) const + { + return ! (this->operator== (other)); + } + +private: + bool + would_exceed (size_type additional) const + { + return size() + additional > + bucket_count() * max_load_factor(); + } + + void + maybe_rehash (size_type additional) + { + if (would_exceed (additional)) + m_buck.resize (size() + additional, m_cont); + assert (load_factor() <= max_load_factor()); + } + + // map, set + template + auto + insert_unchecked (value_type const& value) -> + typename std::enable_if >::type; + + // multimap, multiset + template + auto + insert_unchecked (value_type const& value) -> + typename std::enable_if ::type; + + template + void + insert_unchecked (InputIt first, InputIt const& last) + { + for (; first != last; ++first) + insert_unchecked (*first); + } + + template + void + insert (InputIt first, InputIt const& last, + std::input_iterator_tag) + { + for (; first != last; ++first) + insert (*first); + } + + template + void + insert (InputIt first, InputIt const& last, + std::random_access_iterator_tag) + { + auto const n (std::distance (first, last)); + maybe_rehash (n); + insert_unchecked (first, last); + } + + template + void + touch (detail::aged_container_iterator < + is_const, Iterator, Base> const& pos, + typename clock_type::time_point const& now) + { + auto& e (*pos.iterator()); + e.when = now; + chronological.list.erase (chronological.list.iterator_to (e)); + chronological.list.push_back (e); + } + + template ::propagate_on_container_swap::value> + typename std::enable_if ::type + swap_data (aged_unordered_container& other) noexcept + { + std::swap (m_config.key_compare(), other.m_config.key_compare()); + std::swap (m_config.alloc(), other.m_config.alloc()); + std::swap (m_config.clock, other.m_config.clock); + } + + template ::propagate_on_container_swap::value> + typename std::enable_if ::type + swap_data (aged_unordered_container& other) noexcept + { + std::swap (m_config.key_compare(), other.m_config.key_compare()); + std::swap (m_config.clock, other.m_config.clock); + } + +private: + config_t m_config; + Buckets m_buck; + cont_type mutable m_cont; +}; + +//------------------------------------------------------------------------------ + +template +aged_unordered_container :: +aged_unordered_container ( + clock_type& clock) + : m_config (clock) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ +} + +template +aged_unordered_container :: +aged_unordered_container ( + clock_type& clock, + Hash const& hash) + : m_config (clock, hash) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ +} + +template +aged_unordered_container :: +aged_unordered_container ( + clock_type& clock, + KeyEqual const& key_eq) + : m_config (clock, key_eq) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ +} + +template +aged_unordered_container :: +aged_unordered_container ( + clock_type& clock, + Allocator const& alloc) + : m_config (clock, alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ +} + +template +aged_unordered_container :: +aged_unordered_container ( + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq) + : m_config (clock, hash, key_eq) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ +} + +template +aged_unordered_container :: +aged_unordered_container ( + clock_type& clock, + Hash const& hash, + Allocator const& alloc) + : m_config (clock, hash, alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ +} + +template +aged_unordered_container :: +aged_unordered_container ( + clock_type& clock, + KeyEqual const& key_eq, + Allocator const& alloc) + : m_config (clock, key_eq, alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ +} + +template +aged_unordered_container :: +aged_unordered_container ( + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq, + Allocator const& alloc) + : m_config (clock, hash, key_eq, alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ +} + +template +template +aged_unordered_container :: +aged_unordered_container (InputIt first, InputIt last, + clock_type& clock) + : m_config (clock) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (first, last); +} + +template +template +aged_unordered_container :: +aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, + Hash const& hash) + : m_config (clock, hash) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (first, last); +} + +template +template +aged_unordered_container :: +aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, + KeyEqual const& key_eq) + : m_config (clock, key_eq) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (first, last); +} + +template +template +aged_unordered_container :: +aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, + Allocator const& alloc) + : m_config (clock, alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (first, last); +} + +template +template +aged_unordered_container :: +aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq) + : m_config (clock, hash, key_eq) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (first, last); +} + +template +template +aged_unordered_container :: +aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, + Hash const& hash, + Allocator const& alloc) + : m_config (clock, hash, alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (first, last); +} + +template +template +aged_unordered_container :: +aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, + KeyEqual const& key_eq, + Allocator const& alloc) + : m_config (clock, key_eq, alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (first, last); +} + +template +template +aged_unordered_container :: +aged_unordered_container (InputIt first, InputIt last, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq, + Allocator const& alloc) + : m_config (clock, hash, key_eq, alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (first, last); +} + +template +aged_unordered_container :: +aged_unordered_container (aged_unordered_container const& other) + : m_config (other.m_config) + , m_buck (m_config.alloc()) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (other.cbegin(), other.cend()); +} + +template +aged_unordered_container :: +aged_unordered_container (aged_unordered_container const& other, + Allocator const& alloc) + : m_config (other.m_config, alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (other.cbegin(), other.cend()); +} + +template +aged_unordered_container :: +aged_unordered_container (aged_unordered_container&& other) + : m_config (std::move (other.m_config)) + , m_buck (m_config.alloc()) + , m_cont (std::move (other.m_cont)) +{ + chronological.list = std::move (other.chronological.list); +} + +template +aged_unordered_container :: +aged_unordered_container (aged_unordered_container&& other, + Allocator const& alloc) + : m_config (std::move (other.m_config), alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (other.cbegin(), other.cend()); + other.clear (); +} + +template +aged_unordered_container :: +aged_unordered_container (std::initializer_list init, + clock_type& clock) + : m_config (clock) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (init.begin(), init.end()); +} + +template +aged_unordered_container :: +aged_unordered_container (std::initializer_list init, + clock_type& clock, + Hash const& hash) + : m_config (clock, hash) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (init.begin(), init.end()); +} + +template +aged_unordered_container :: +aged_unordered_container (std::initializer_list init, + clock_type& clock, + KeyEqual const& key_eq) + : m_config (clock, key_eq) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (init.begin(), init.end()); +} + +template +aged_unordered_container :: +aged_unordered_container (std::initializer_list init, + clock_type& clock, + Allocator const& alloc) + : m_config (clock, alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (init.begin(), init.end()); +} + +template +aged_unordered_container :: +aged_unordered_container (std::initializer_list init, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq) + : m_config (clock, hash, key_eq) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (init.begin(), init.end()); +} + +template +aged_unordered_container :: +aged_unordered_container (std::initializer_list init, + clock_type& clock, + Hash const& hash, + Allocator const& alloc) + : m_config (clock, hash, alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (init.begin(), init.end()); +} + +template +aged_unordered_container :: +aged_unordered_container (std::initializer_list init, + clock_type& clock, + KeyEqual const& key_eq, + Allocator const& alloc) + : m_config (clock, key_eq, alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (init.begin(), init.end()); +} + +template +aged_unordered_container :: +aged_unordered_container (std::initializer_list init, + clock_type& clock, + Hash const& hash, + KeyEqual const& key_eq, + Allocator const& alloc) + : m_config (clock, hash, key_eq, alloc) + , m_buck (alloc) + , m_cont (m_buck, + std::cref (m_config.value_hash()), + std::cref (m_config.key_value_equal())) +{ + insert (init.begin(), init.end()); +} + +template +aged_unordered_container :: +~aged_unordered_container() +{ + clear(); +} + +template +auto +aged_unordered_container :: +operator= (aged_unordered_container const& other) + -> aged_unordered_container& +{ + if (this != &other) + { + size_type const n (other.size()); + clear(); + m_config = other.m_config; + m_buck = Buckets (m_config.alloc()); + maybe_rehash (n); + insert_unchecked (other.begin(), other.end()); + } + return *this; +} + +template +auto +aged_unordered_container :: +operator= (aged_unordered_container&& other) -> + aged_unordered_container& +{ + size_type const n (other.size()); + clear(); + m_config = std::move (other.m_config); + m_buck = Buckets (m_config.alloc()); + maybe_rehash (n); + insert_unchecked (other.begin(), other.end()); + other.clear(); + return *this; +} + +template +auto +aged_unordered_container :: +operator= (std::initializer_list init) -> + aged_unordered_container& +{ + clear (); + insert (init); + return *this; +} + +//------------------------------------------------------------------------------ + +template +template +typename std::conditional ::type& +aged_unordered_container :: +at (K const& k) +{ + auto const iter (m_cont.find (k, + std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()))); + if (iter == m_cont.end()) + throw std::out_of_range ("key not found"); + return iter->value.second; +} + +template +template +typename std::conditional ::type const& +aged_unordered_container :: +at (K const& k) const +{ + auto const iter (m_cont.find (k, + std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()))); + if (iter == m_cont.end()) + throw std::out_of_range ("key not found"); + return iter->value.second; +} + +template +template +typename std::conditional ::type& +aged_unordered_container :: +operator[] (Key const& key) +{ + maybe_rehash (1); + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (key, + std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()), d)); + if (result.second) + { + element* const p (new_element ( + std::piecewise_construct, + std::forward_as_tuple (key), + std::forward_as_tuple ())); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return p->value.second; + } + return result.first->value.second; +} + +template +template +typename std::conditional ::type& +aged_unordered_container :: +operator[] (Key&& key) +{ + maybe_rehash (1); + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (key, + std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()), d)); + if (result.second) + { + element* const p (new_element ( + std::piecewise_construct, + std::forward_as_tuple (std::move (key)), + std::forward_as_tuple ())); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return p->value.second; + } + return result.first->value.second; +} + +//------------------------------------------------------------------------------ + +template +void +aged_unordered_container :: +clear() +{ + for (auto iter (chronological.list.begin()); + iter != chronological.list.end();) + unlink_and_delete_element (&*iter++); + chronological.list.clear(); + m_cont.clear(); + m_buck.clear(); +} + +// map, set +template +template +auto +aged_unordered_container :: +insert (value_type const& value) -> + typename std::enable_if >::type +{ + maybe_rehash (1); + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (extract (value), + std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()), d)); + if (result.second) + { + element* const p (new_element (value)); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return std::make_pair (iterator (iter), true); + } + return std::make_pair (iterator (result.first), false); +} + +// multimap, multiset +template +template +auto +aged_unordered_container :: +insert (value_type const& value) -> + typename std::enable_if ::type +{ + maybe_rehash (1); + element* const p (new_element (value)); + chronological.list.push_back (*p); + auto const iter (m_cont.insert (*p)); + return iterator (iter); +} + +// map, set +template +template +auto +aged_unordered_container :: +insert (value_type&& value) -> + typename std::enable_if >::type +{ + maybe_rehash (1); + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (extract (value), + std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()), d)); + if (result.second) + { + element* const p (new_element (std::move (value))); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return std::make_pair (iterator (iter), true); + } + return std::make_pair (iterator (result.first), false); +} + +// multimap, multiset +template +template +auto +aged_unordered_container :: +insert (value_type&& value) -> + typename std::enable_if ::type +{ + maybe_rehash (1); + element* const p (new_element (std::move (value))); + chronological.list.push_back (*p); + auto const iter (m_cont.insert (*p)); + return iterator (iter); +} + +// set, map +template +template +auto +aged_unordered_container :: +emplace (Args&&... args) -> + typename std::enable_if >::type +{ + maybe_rehash (1); + // VFALCO NOTE Its unfortunate that we need to + // construct element here + element* const p (new_element ( + std::forward (args)...)); + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (extract (p->value), + std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()), d)); + if (result.second) + { + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return std::make_pair (iterator (iter), true); + } + delete_element (p); + return std::make_pair (iterator (result.first), false); +} + +// multiset, multimap +template +template +auto +aged_unordered_container :: +emplace (Args&&... args) -> + typename std::enable_if ::type +{ + maybe_rehash (1); + element* const p (new_element ( + std::forward (args)...)); + chronological.list.push_back (*p); + auto const iter (m_cont.insert (*p)); + return iterator (iter); +} + +// set, map +template +template +auto +aged_unordered_container :: +emplace_hint (const_iterator const& /*hint*/, Args&&... args) -> + typename std::enable_if >::type +{ + maybe_rehash (1); + // VFALCO NOTE Its unfortunate that we need to + // construct element here + element* const p (new_element ( + std::forward (args)...)); + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (extract (p->value), + std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()), d)); + if (result.second) + { + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return std::make_pair (iterator (iter), true); + } + delete_element (p); + return std::make_pair (iterator (result.first), false); +} + +template +template +detail::aged_container_iterator +aged_unordered_container :: +erase (detail::aged_container_iterator < + is_const, Iterator, Base> const& pos) +{ + auto iter (pos.iterator()); + auto p (&*iter++); + unlink_and_delete_element (p); + return detail::aged_container_iterator < + false, Iterator, Base> (iter); +} + +template +template +detail::aged_container_iterator +aged_unordered_container :: +erase (detail::aged_container_iterator < + is_const, Iterator, Base> first, + detail::aged_container_iterator < + is_const, Iterator, Base> const& last) +{ + size_type n (0); + for (; first != last; ++n) + { + auto p (&*first++); + unlink_and_delete_element (p); + } + return detail::aged_container_iterator < + false, Iterator, Base> (first.iterator()); +} + +template +template +auto +aged_unordered_container :: +erase (K const& k) -> + size_type +{ + auto iter (m_cont.find (k, std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()))); + if (iter == m_cont.end()) + return 0; + size_type n (0); + for (;;) + { + auto p (&*iter++); + bool const done ( + m_config (*p, extract (iter->value))); + unlink_and_delete_element (p); + ++n; + if (done) + break; + } + return n; +} + +template +void +aged_unordered_container :: +swap (aged_unordered_container& other) noexcept +{ + swap_data (other); + std::swap (chronological, other.chronological); + std::swap (m_cont, other.m_cont); +} + +template +template +auto +aged_unordered_container :: +touch (K const& k) -> + size_type +{ + auto const now (clock().now()); + size_type n (0); + auto const range (equal_range (k)); + for (auto iter : range) + { + touch (iter, now); + ++n; + } + return n; +} + +//------------------------------------------------------------------------------ + +// map, set +template +template +auto +aged_unordered_container :: +insert_unchecked (value_type const& value) -> + typename std::enable_if >::type +{ + typename cont_type::insert_commit_data d; + auto const result (m_cont.insert_check (extract (value), + std::cref (m_config.hash_function()), + std::cref (m_config.key_value_equal()), d)); + if (result.second) + { + element* const p (new_element (value)); + chronological.list.push_back (*p); + auto const iter (m_cont.insert_commit (*p, d)); + return std::make_pair (iterator (iter), true); + } + return std::make_pair (iterator (result.first), false); +} + +// multimap, multiset +template +template +auto +aged_unordered_container :: +insert_unchecked (value_type const& value) -> + typename std::enable_if ::type +{ + element* const p (new_element (value)); + chronological.list.push_back (*p); + auto const iter (m_cont.insert (*p)); + return iterator (iter); +} + +//------------------------------------------------------------------------------ + +} + +//------------------------------------------------------------------------------ + +template +struct is_aged_container > + : std::true_type +{ +}; + +// Free functions + +template +void swap ( + detail::aged_unordered_container & lhs, + detail::aged_unordered_container & rhs) noexcept +{ + lhs.swap (rhs); +} + +/** Expire aged container items past the specified age. */ +template +std::size_t expire (detail::aged_unordered_container < + IsMulti, IsMap, Key, T, Duration, Hash, KeyEqual, Allocator>& c, + std::chrono::duration const& age) noexcept +{ + std::size_t n (0); + auto const expired (c.clock().now() - age); + for (auto iter (c.chronological.cbegin()); + iter != c.chronological.cend() && + iter.when() <= expired;) + { + iter = c.erase (iter); + ++n; + } + return n; +} + +} + +#endif diff --git a/beast/container/impl/aged_associative_container.cpp b/beast/container/impl/aged_associative_container.cpp new file mode 100644 index 000000000..bb2cd715f --- /dev/null +++ b/beast/container/impl/aged_associative_container.cpp @@ -0,0 +1,1461 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "../../../modules/beast_core/beast_core.h" // for UnitTest +#include "../../chrono/manual_clock.h" +#include "../../equal.h" +#include "../aged_set.h" +#include "../aged_map.h" +#include "../aged_multiset.h" +#include "../aged_multimap.h" +#include "../aged_unordered_set.h" +#include "../aged_unordered_map.h" +#include "../aged_unordered_multiset.h" +#include "../aged_unordered_multimap.h" + +#ifndef BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR +# ifdef _MSC_VER +# define BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR 0 +# else +# define BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR 1 +# endif +#endif + +#ifndef BEAST_CONTAINER_EXTRACT_NOREF +# ifdef _MSC_VER +# define BEAST_CONTAINER_EXTRACT_NOREF 1 +# else +# define BEAST_CONTAINER_EXTRACT_NOREF 1 +# endif +#endif + +namespace beast { + +class aged_associative_container_TestsBase : public UnitTest +{ +public: + template + struct CompT + { + explicit CompT (int) + { + } + + CompT (CompT const&) + { + } + + bool operator() (T const& lhs, T const& rhs) const + { + return m_less (lhs, rhs); + } + + private: + CompT () = delete; + std::less m_less; + }; + + template + class HashT + { + public: + explicit HashT (int) + { + } + + std::size_t operator() (T const& t) const + { + return m_hash (t); + } + + private: + HashT() = delete; + std::hash m_hash; + }; + + template + struct EqualT + { + public: + explicit EqualT (int) + { + } + + bool operator() (T const& lhs, T const& rhs) const + { + return m_eq (lhs, rhs); + } + + private: + EqualT() = delete; + std::equal_to m_eq; + }; + + template + struct AllocT + { + typedef T value_type; + + //typedef propagate_on_container_swap : std::true_type::type; + + template + struct rebind + { + typedef AllocT other; + }; + + explicit AllocT (int) + { + } + + AllocT (AllocT const&) + { + } + + template + AllocT (AllocT const&) + { + } + + template + bool operator== (AllocT const&) const + { + return true; + } + + T* allocate (std::size_t n, T const* = 0) + { + return static_cast ( + ::operator new (n * sizeof(T))); + } + + void deallocate (T* p, std::size_t) + { + ::operator delete (p); + } + +#if ! BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR + AllocT () + { + } +#else + private: + AllocT() = delete; +#endif + }; + + //-------------------------------------------------------------------------- + + // ordered + template + class MaybeUnordered : public Base + { + public: + typedef std::less Comp; + typedef CompT MyComp; + + protected: + static std::string name_ordered_part() + { + return ""; + } + }; + + // unordered + template + class MaybeUnordered : public Base + { + public: + typedef std::hash Hash; + typedef std::equal_to Equal; + typedef HashT MyHash; + typedef EqualT MyEqual; + + protected: + static std::string name_ordered_part() + { + return "unordered_"; + } + }; + + // unique + template + class MaybeMulti : public Base + { + public: + protected: + static std::string name_multi_part() + { + return ""; + } + }; + + // multi + template + class MaybeMulti : public Base + { + public: + protected: + static std::string name_multi_part() + { + return "multi"; + } + }; + + // set + template + class MaybeMap : public Base + { + public: + typedef void T; + typedef typename Base::Key Value; + typedef std::vector Values; + + static typename Base::Key const& extract (Value const& value) + { + return value; + } + + static Values values() + { + Values v { + "apple", + "banana", + "cherry", + "grape", + "orange", + }; + return v; + }; + + protected: + static std::string name_map_part() + { + return "set"; + } + }; + + // map + template + class MaybeMap : public Base + { + public: + typedef int T; + typedef std::pair Value; + typedef std::vector Values; + + static typename Base::Key const& extract (Value const& value) + { + return value.first; + } + + static Values values() + { + Values v { + std::make_pair ("apple", 1), + std::make_pair ("banana", 2), + std::make_pair ("cherry", 3), + std::make_pair ("grape", 4), + std::make_pair ("orange", 5) + }; + return v; + }; + + protected: + static std::string name_map_part() + { + return "map"; + } + }; + + //-------------------------------------------------------------------------- + + // ordered + template < + class Base, + bool IsUnordered = Base::is_unordered::value + > + struct ContType + { + template < + class Compare = std::less , + class Allocator = std::allocator + > + using Cont = detail::aged_ordered_container < + Base::is_multi::value, Base::is_map::value, typename Base::Key, + typename Base::T, typename Base::Dur, Compare, Allocator>; + }; + + // unordered + template < + class Base + > + struct ContType + { + template < + class Hash = std::hash , + class KeyEqual = std::equal_to , + class Allocator = std::allocator + > + using Cont = detail::aged_unordered_container < + Base::is_multi::value, Base::is_map::value, + typename Base::Key, typename Base::T, typename Base::Dur, + Hash, KeyEqual, Allocator>; + }; + + //-------------------------------------------------------------------------- + + struct TestTraitsBase + { + typedef std::string Key; + typedef std::chrono::seconds Dur; + typedef manual_clock Clock; + }; + + template + struct TestTraitsHelper + : MaybeUnordered , IsMulti>, IsUnordered> + { + private: + typedef MaybeUnordered , IsMulti>, IsUnordered> Base; + + public: + using typename Base::Key; + + typedef std::integral_constant is_unordered; + typedef std::integral_constant is_multi; + typedef std::integral_constant is_map; + + typedef std::allocator Alloc; + typedef AllocT MyAlloc; + + static std::string name() + { + return std::string ("aged_") + + Base::name_ordered_part() + + Base::name_multi_part() + + Base::name_map_part(); + } + }; + + template + struct TestTraits + : TestTraitsHelper + , ContType > + { + }; + + template + static std::string name (Cont const&) + { + return TestTraits < + Cont::is_unordered, + Cont::is_multi, + Cont::is_map>::name(); + } + + template + struct equal_value + { + bool operator() (typename Traits::Value const& lhs, + typename Traits::Value const& rhs) + { + return Traits::extract (lhs) == Traits::extract (rhs); + } + }; + + template + static + std::list + make_list (Cont const& c) + { + return std::list ( + c.begin(), c.end()); + } + + //-------------------------------------------------------------------------- + + // Compile time checks + // + void checkAliases () + { + typedef std::string Key; + typedef int T; + + static_assert (std::is_same < + aged_set , + detail::aged_ordered_container >::value, + "bad alias: aged_set"); + + static_assert (std::is_same < + aged_multiset , + detail::aged_ordered_container >::value, + "bad alias: aged_multiset"); + + static_assert (std::is_same < + aged_map , + detail::aged_ordered_container >::value, + "bad alias: aged_map"); + + static_assert (std::is_same < + aged_multimap , + detail::aged_ordered_container >::value, + "bad alias: aged_multimap"); + + static_assert (std::is_same < + aged_unordered_set , + detail::aged_unordered_container >::value, + "bad alias: aged_unordered_set"); + + static_assert (std::is_same < + aged_unordered_multiset , + detail::aged_unordered_container >::value, + "bad alias: aged_unordered_multiset"); + + static_assert (std::is_same < + aged_unordered_map , + detail::aged_unordered_container >::value, + "bad alias: aged_unordered_map"); + + static_assert (std::is_same < + aged_unordered_multimap , + detail::aged_unordered_container >::value, + "bad alias: aged_unordered_multimap"); + } + + //-------------------------------------------------------------------------- + + template < + class Container, + class Values + > + typename std::enable_if < + Container::is_map::value && ! Container::is_multi::value>::type + checkMapContents (Container& c, Values const& v); + + template < + class Container, + class Values + > + typename std::enable_if ::type + checkMapContents (Container, Values const&) + { + } + + // unordered + template < + class C, + class Values + > + typename std::enable_if < + std::remove_reference ::type::is_unordered::value>::type + checkUnorderedContentsRefRef (C&& c, Values const& v); + + template < + class C, + class Values + > + typename std::enable_if ::type::is_unordered::value>::type + checkUnorderedContentsRefRef (C&&, Values const&) + { + } + + template + void checkContentsRefRef (C&& c, Values const& v); + + template + void checkContents (Cont& c, Values const& v); + + template + void checkContents (Cont& c); + + //-------------------------------------------------------------------------- + + // ordered + template + typename std::enable_if ::type + testConstructEmpty (); + + // unordered + template + typename std::enable_if ::type + testConstructEmpty (); + + // ordered + template + typename std::enable_if ::type + testConstructRange (); + + // unordered + template + typename std::enable_if ::type + testConstructRange (); + + // ordered + template + typename std::enable_if ::type + testConstructInitList (); + + // unordered + template + typename std::enable_if ::type + testConstructInitList (); + + //-------------------------------------------------------------------------- + + template + void + testCopyMove (); + + //-------------------------------------------------------------------------- + + template + void checkInsertCopy (Container& c, Values const& v); + + template + void checkInsertMove (Container& c, Values const& v); + + template + void checkInsertHintCopy (Container& c, Values const& v); + + template + void checkInsertHintMove (Container& c, Values const& v); + + template + void checkEmplace (Container& c, Values const& v); + + template + void checkEmplaceHint (Container& c, Values const& v); + + template + void testModifiers(); + + //-------------------------------------------------------------------------- + + template + void + testChronological (); + + //-------------------------------------------------------------------------- + + // map, unordered_map + template + typename std::enable_if ::type + testArrayCreate(); + + template + typename std::enable_if ::type + testArrayCreate() + { + } + + //-------------------------------------------------------------------------- + + // ordered + template + typename std::enable_if ::type + testCompare (); + + template + typename std::enable_if ::type + testCompare () + { + } + + //-------------------------------------------------------------------------- + + // ordered + template + typename std::enable_if ::type + testObservers(); + + // unordered + template + typename std::enable_if ::type + testObservers(); + + //-------------------------------------------------------------------------- + + template + void testMaybeUnorderedMultiMap (); + + template + void testMaybeUnorderedMulti(); + + template + void testMaybeUnordered(); + + aged_associative_container_TestsBase () : UnitTest ( + "aged_associative_container", "beast") + { + } +}; + +//------------------------------------------------------------------------------ + +// Check contents via at() and operator[] +// map, unordered_map +template < + class Container, + class Values +> +typename std::enable_if < + Container::is_map::value && ! Container::is_multi::value>::type +aged_associative_container_TestsBase:: +checkMapContents (Container& c, Values const& v) +{ + if (v.empty()) + { + expect (c.empty()); + expect (c.size() == 0); + return; + } + + try + { + // Make sure no exception is thrown + for (auto const& e : v) + c.at (e.first); + for (auto const& e : v) + expect (c.operator[](e.first) == e.second); + } + catch (std::out_of_range const&) + { + fail ("caught exception"); + } +} + +// unordered +template < + class C, + class Values +> +typename std::enable_if < + std::remove_reference ::type::is_unordered::value>::type +aged_associative_container_TestsBase:: +checkUnorderedContentsRefRef (C&& c, Values const& v) +{ + typedef typename std::remove_reference ::type Cont; + typedef TestTraits < + Cont::is_unordered::value, + Cont::is_multi::value, + Cont::is_map::value + > Traits; + typedef typename Cont::size_type size_type; + auto const hash (c.hash_function()); + auto const key_eq (c.key_eq()); + for (size_type i (0); i < c.bucket_count(); ++i) + { + auto const last (c.end(i)); + for (auto iter (c.begin (i)); iter != last; ++iter) + { + auto const match (std::find_if (v.begin(), v.end(), + [iter](typename Values::value_type const& e) + { + return Traits::extract (*iter) == + Traits::extract (e); + })); + expect (match != v.end()); + expect (key_eq (Traits::extract (*iter), + Traits::extract (*match))); + expect (hash (Traits::extract (*iter)) == + hash (Traits::extract (*match))); + } + } +} + +template +void +aged_associative_container_TestsBase:: +checkContentsRefRef (C&& c, Values const& v) +{ + typedef typename std::remove_reference ::type Cont; + typedef TestTraits < + Cont::is_unordered::value, + Cont::is_multi::value, + Cont::is_map::value + > Traits; + typedef typename Cont::size_type size_type; + + expect (c.size() == v.size()); + expect (size_type (std::distance ( + c.begin(), c.end())) == v.size()); + expect (size_type (std::distance ( + c.cbegin(), c.cend())) == v.size()); + expect (size_type (std::distance ( + c.chronological.begin(), c.chronological.end())) == v.size()); + expect (size_type (std::distance ( + c.chronological.cbegin(), c.chronological.cend())) == v.size()); + expect (size_type (std::distance ( + c.chronological.rbegin(), c.chronological.rend())) == v.size()); + expect (size_type (std::distance ( + c.chronological.crbegin(), c.chronological.crend())) == v.size()); + + checkUnorderedContentsRefRef (c, v); +} + +template +void +aged_associative_container_TestsBase:: +checkContents (Cont& c, Values const& v) +{ + checkContentsRefRef (c, v); + checkContentsRefRef (const_cast (c), v); + checkMapContents (c, v); +} + +template +void +aged_associative_container_TestsBase:: +checkContents (Cont& c) +{ + typedef TestTraits < + Cont::is_unordered::value, + Cont::is_multi::value, + Cont::is_map::value + > Traits; + typedef typename Traits::Values Values; + checkContents (c, Values()); +} + +//------------------------------------------------------------------------------ +// +// Construction +// +//------------------------------------------------------------------------------ + +// ordered +template +typename std::enable_if ::type +aged_associative_container_TestsBase:: +testConstructEmpty () +{ + typedef TestTraits Traits; + typedef typename Traits::Value Value; + typedef typename Traits::Key Key; + typedef typename Traits::T T; + typedef typename Traits::Dur Dur; + typedef typename Traits::Comp Comp; + typedef typename Traits::Alloc Alloc; + typedef typename Traits::MyComp MyComp; + typedef typename Traits::MyAlloc MyAlloc; + typename Traits::Clock clock; + + beginTestCase (Traits::name() + " empty"); + + { + typename Traits::template Cont c ( + clock); + checkContents (c); + } + + { + typename Traits::template Cont c ( + clock, MyComp(1)); + checkContents (c); + } + + { + typename Traits::template Cont c ( + clock, MyAlloc(1)); + checkContents (c); + } + + { + typename Traits::template Cont c ( + clock, MyComp(1), MyAlloc(1)); + checkContents (c); + } +} + +// unordered +template +typename std::enable_if ::type +aged_associative_container_TestsBase:: +testConstructEmpty () +{ + typedef TestTraits Traits; + typedef typename Traits::Value Value; + typedef typename Traits::Key Key; + typedef typename Traits::T T; + typedef typename Traits::Dur Dur; + typedef typename Traits::Hash Hash; + typedef typename Traits::Equal Equal; + typedef typename Traits::Alloc Alloc; + typedef typename Traits::MyHash MyHash; + typedef typename Traits::MyEqual MyEqual; + typedef typename Traits::MyAlloc MyAlloc; + typename Traits::Clock clock; + + beginTestCase (Traits::name() + " empty"); + + { + typename Traits::template Cont c ( + clock); + checkContents (c); + } + + { + typename Traits::template Cont c ( + clock, MyHash(1)); + checkContents (c); + } + + { + typename Traits::template Cont c ( + clock, MyEqual (1)); + checkContents (c); + } + + { + typename Traits::template Cont c ( + clock, MyAlloc (1)); + checkContents (c); + } + + { + typename Traits::template Cont c ( + clock, MyHash(1), MyEqual(1)); + checkContents (c); + } + + { + typename Traits::template Cont c ( + clock, MyHash(1), MyAlloc(1)); + checkContents (c); + } + + { + typename Traits::template Cont c ( + clock, MyEqual(1), MyAlloc(1)); + checkContents (c); + } + + { + typename Traits::template Cont c ( + clock, MyHash(1), MyEqual(1), MyAlloc(1)); + checkContents (c); + } +} + +// ordered +template +typename std::enable_if ::type +aged_associative_container_TestsBase:: +testConstructRange () +{ + typedef TestTraits Traits; + typedef typename Traits::Value Value; + typedef typename Traits::Key Key; + typedef typename Traits::T T; + typedef typename Traits::Dur Dur; + typedef typename Traits::Comp Comp; + typedef typename Traits::Alloc Alloc; + typedef typename Traits::MyComp MyComp; + typedef typename Traits::MyAlloc MyAlloc; + typename Traits::Clock clock; + auto const v (Traits::values()); + + beginTestCase (Traits::name() + " range"); + + { + typename Traits::template Cont c ( + v.begin(), v.end(), + clock); + checkContents (c, v); + } + + { + typename Traits::template Cont c ( + v.begin(), v.end(), + clock, MyComp(1)); + checkContents (c, v); + } + + { + typename Traits::template Cont c ( + v.begin(), v.end(), + clock, MyAlloc(1)); + checkContents (c, v); + } + + { + typename Traits::template Cont c ( + v.begin(), v.end(), + clock, MyComp(1), MyAlloc(1)); + checkContents (c, v); + + } + + // swap + + { + typename Traits::template Cont c1 ( + v.begin(), v.end(), + clock); + typename Traits::template Cont c2 ( + clock); + std::swap (c1, c2); + checkContents (c2, v); + } +} + +// unordered +template +typename std::enable_if ::type +aged_associative_container_TestsBase:: +testConstructRange () +{ + typedef TestTraits Traits; + typedef typename Traits::Value Value; + typedef typename Traits::Key Key; + typedef typename Traits::T T; + typedef typename Traits::Dur Dur; + typedef typename Traits::Hash Hash; + typedef typename Traits::Equal Equal; + typedef typename Traits::Alloc Alloc; + typedef typename Traits::MyHash MyHash; + typedef typename Traits::MyEqual MyEqual; + typedef typename Traits::MyAlloc MyAlloc; + typename Traits::Clock clock; + auto const v (Traits::values()); + + beginTestCase (Traits::name() + " range"); + + { + typename Traits::template Cont c ( + v.begin(), v.end(), + clock); + checkContents (c, v); + } + + { + typename Traits::template Cont c ( + v.begin(), v.end(), + clock, MyHash(1)); + checkContents (c, v); + } + + { + typename Traits::template Cont c ( + v.begin(), v.end(), + clock, MyEqual (1)); + checkContents (c, v); + } + + { + typename Traits::template Cont c ( + v.begin(), v.end(), + clock, MyAlloc (1)); + checkContents (c, v); + } + + { + typename Traits::template Cont c ( + v.begin(), v.end(), + clock, MyHash(1), MyEqual(1)); + checkContents (c, v); + } + + { + typename Traits::template Cont c ( + v.begin(), v.end(), + clock, MyHash(1), MyAlloc(1)); + checkContents (c, v); + } + + { + typename Traits::template Cont c ( + v.begin(), v.end(), + clock, MyEqual(1), MyAlloc(1)); + checkContents (c, v); + } + + { + typename Traits::template Cont c ( + v.begin(), v.end(), + clock, MyHash(1), MyEqual(1), MyAlloc(1)); + checkContents (c, v); + } +} + +// ordered +template +typename std::enable_if ::type +aged_associative_container_TestsBase:: +testConstructInitList () +{ + typedef TestTraits Traits; + typedef typename Traits::Value Value; + typedef typename Traits::Key Key; + typedef typename Traits::T T; + typedef typename Traits::Dur Dur; + typedef typename Traits::Comp Comp; + typedef typename Traits::Alloc Alloc; + typedef typename Traits::MyComp MyComp; + typedef typename Traits::MyAlloc MyAlloc; + typename Traits::Clock clock; + + beginTestCase (Traits::name() + " init-list"); + + // VFALCO TODO + + pass(); +} + +// unordered +template +typename std::enable_if ::type +aged_associative_container_TestsBase:: +testConstructInitList () +{ + typedef TestTraits Traits; + typedef typename Traits::Value Value; + typedef typename Traits::Key Key; + typedef typename Traits::T T; + typedef typename Traits::Dur Dur; + typedef typename Traits::Hash Hash; + typedef typename Traits::Equal Equal; + typedef typename Traits::Alloc Alloc; + typedef typename Traits::MyHash MyHash; + typedef typename Traits::MyEqual MyEqual; + typedef typename Traits::MyAlloc MyAlloc; + typename Traits::Clock clock; + + beginTestCase (Traits::name() + " init-list"); + // VFALCO TODO + pass(); +} + +//------------------------------------------------------------------------------ +// +// Copy/Move construction and assign +// +//------------------------------------------------------------------------------ + +template +void +aged_associative_container_TestsBase:: +testCopyMove () +{ + typedef TestTraits Traits; + typedef typename Traits::Value Value; + typedef typename Traits::Alloc Alloc; + typename Traits::Clock clock; + auto const v (Traits::values()); + + beginTestCase (Traits::name() + " copy/move"); + + // copy + + { + typename Traits::template Cont <> c ( + v.begin(), v.end(), clock); + typename Traits::template Cont <> c2 (c); + checkContents (c, v); + checkContents (c2, v); + expect (c == c2); + unexpected (c != c2); + } + + { + typename Traits::template Cont <> c ( + v.begin(), v.end(), clock); + typename Traits::template Cont <> c2 (c, Alloc()); + checkContents (c, v); + checkContents (c2, v); + expect (c == c2); + unexpected (c != c2); + } + + { + typename Traits::template Cont <> c ( + v.begin(), v.end(), clock); + typename Traits::template Cont <> c2 ( + clock); + c2 = c; + checkContents (c, v); + checkContents (c2, v); + expect (c == c2); + unexpected (c != c2); + } + + // move + + { + typename Traits::template Cont <> c ( + v.begin(), v.end(), clock); + typename Traits::template Cont <> c2 ( + std::move (c)); + checkContents (c2, v); + } + + { + typename Traits::template Cont <> c ( + v.begin(), v.end(), clock); + typename Traits::template Cont <> c2 ( + std::move (c), Alloc()); + checkContents (c2, v); + } + + { + typename Traits::template Cont <> c ( + v.begin(), v.end(), clock); + typename Traits::template Cont <> c2 ( + clock); + c2 = std::move (c); + checkContents (c2, v); + } +} + +//------------------------------------------------------------------------------ +// +// Modifiers +// +//------------------------------------------------------------------------------ + + +template +void +aged_associative_container_TestsBase:: +checkInsertCopy (Container& c, Values const& v) +{ + for (auto const& e : v) + c.insert (e); + checkContents (c, v); +} + +template +void +aged_associative_container_TestsBase:: +checkInsertMove (Container& c, Values const& v) +{ + Values v2 (v); + for (auto& e : v2) + c.insert (std::move (e)); + checkContents (c, v); +} + +template +void +aged_associative_container_TestsBase:: +checkInsertHintCopy (Container& c, Values const& v) +{ + for (auto const& e : v) + c.insert (c.cend(), e); + checkContents (c, v); +} + +template +void +aged_associative_container_TestsBase:: +checkInsertHintMove (Container& c, Values const& v) +{ + Values v2 (v); + for (auto& e : v2) + c.insert (c.cend(), std::move (e)); + checkContents (c, v); +} + +template +void +aged_associative_container_TestsBase:: +checkEmplace (Container& c, Values const& v) +{ + for (auto const& e : v) + c.emplace (e); + checkContents (c, v); +} + +template +void +aged_associative_container_TestsBase:: +checkEmplaceHint (Container& c, Values const& v) +{ + for (auto const& e : v) + c.emplace_hint (c.cend(), e); + checkContents (c, v); +} + +template +void +aged_associative_container_TestsBase:: +testModifiers() +{ + typedef TestTraits Traits; + typename Traits::Clock clock; + auto const v (Traits::values()); + auto const l (make_list (v)); + + beginTestCase (Traits::name() + " modify"); + + { + typename Traits::template Cont <> c (clock); + checkInsertCopy (c, v); + } + + { + typename Traits::template Cont <> c (clock); + checkInsertCopy (c, l); + } + + { + typename Traits::template Cont <> c (clock); + checkInsertMove (c, v); + } + + { + typename Traits::template Cont <> c (clock); + checkInsertMove (c, l); + } + + { + typename Traits::template Cont <> c (clock); + checkInsertHintCopy (c, v); + } + + { + typename Traits::template Cont <> c (clock); + checkInsertHintCopy (c, l); + } + + { + typename Traits::template Cont <> c (clock); + checkInsertHintMove (c, v); + } + + { + typename Traits::template Cont <> c (clock); + checkInsertHintMove (c, l); + } +} + +//------------------------------------------------------------------------------ +// +// Chronological ordering +// +//------------------------------------------------------------------------------ + +template +void +aged_associative_container_TestsBase:: +testChronological () +{ + typedef TestTraits Traits; + typedef typename Traits::Value Value; + typename Traits::Clock clock; + auto const v (Traits::values()); + + beginTestCase (Traits::name() + " chronological"); + + typename Traits::template Cont <> c ( + v.begin(), v.end(), clock); + + expect (std::equal ( + c.chronological.cbegin(), c.chronological.cend(), + v.begin(), v.end(), equal_value ())); + + for (auto iter (v.rbegin()); iter != v.rend(); ++iter) + { + auto found (c.find (Traits::extract (*iter))); + expect (found != c.cend()); + if (found == c.cend()) + return; + c.touch (found); + } + + expect (std::equal ( + c.chronological.cbegin(), c.chronological.cend(), + v.rbegin(), v.rend(), equal_value ())); +} + +//------------------------------------------------------------------------------ +// +// Element creation via operator[] +// +//------------------------------------------------------------------------------ + +// map, unordered_map +template +typename std::enable_if ::type +aged_associative_container_TestsBase:: +testArrayCreate() +{ + typedef TestTraits Traits; + typename Traits::Clock clock; + auto v (Traits::values()); + + beginTestCase (Traits::name() + " array create"); + + { + // Copy construct key + typename Traits::template Cont <> c (clock); + for (auto e : v) + c [e.first] = e.second; + checkContents (c, v); + } + + { + // Move construct key + typename Traits::template Cont <> c (clock); + for (auto e : v) + c [std::move (e.first)] = e.second; + checkContents (c, v); + } +} + +//------------------------------------------------------------------------------ +// +// Container-wide comparison +// +//------------------------------------------------------------------------------ + +// ordered +template +typename std::enable_if ::type +aged_associative_container_TestsBase:: +testCompare () +{ + typedef TestTraits Traits; + typedef typename Traits::Value Value; + typename Traits::Clock clock; + auto const v (Traits::values()); + + beginTestCase (Traits::name() + " array create"); + + typename Traits::template Cont <> c1 ( + v.begin(), v.end(), clock); + + typename Traits::template Cont <> c2 ( + v.begin(), v.end(), clock); + c2.erase (c2.cbegin()); + + expect (c1 != c2); + unexpected (c1 == c2); + expect (c1 < c2); + expect (c1 <= c2); + unexpected (c1 > c2); + unexpected (c1 >= c2); +} + +//------------------------------------------------------------------------------ +// +// Observers +// +//------------------------------------------------------------------------------ + +// ordered +template +typename std::enable_if ::type +aged_associative_container_TestsBase:: +testObservers() +{ + typedef TestTraits Traits; + typename Traits::Clock clock; + + beginTestCase (Traits::name() + " observers"); + + typename Traits::template Cont <> c (clock); + c.key_comp(); + c.value_comp(); + + pass(); +} + +// unordered +template +typename std::enable_if ::type +aged_associative_container_TestsBase:: +testObservers() +{ + typedef TestTraits Traits; + typename Traits::Clock clock; + + beginTestCase (Traits::name() + " observers"); + + typename Traits::template Cont <> c (clock); + c.hash_function(); + c.key_eq(); + + pass(); +} + +//------------------------------------------------------------------------------ +// +// Matrix +// +//------------------------------------------------------------------------------ + +template +void +aged_associative_container_TestsBase:: +testMaybeUnorderedMultiMap () +{ + typedef TestTraits Traits; + + testConstructEmpty (); + testConstructRange (); + testConstructInitList (); + testCopyMove (); + testModifiers (); + testChronological (); + testArrayCreate (); + testCompare (); + testObservers (); +} + +template +void +aged_associative_container_TestsBase:: +testMaybeUnorderedMulti() +{ + testMaybeUnorderedMultiMap (); + testMaybeUnorderedMultiMap (); +} + +template +void +aged_associative_container_TestsBase:: +testMaybeUnordered() +{ + testMaybeUnorderedMulti (); + testMaybeUnorderedMulti (); +} + +//------------------------------------------------------------------------------ + +class aged_associative_container_Tests : + public aged_associative_container_TestsBase +{ +public: + void runTest () + { + checkAliases (); + testMaybeUnordered (); + testMaybeUnordered (); + } +}; + +static aged_associative_container_Tests aged_associative_container_tests; + +} diff --git a/beast/equal.h b/beast/equal.h new file mode 100644 index 000000000..e8593382c --- /dev/null +++ b/beast/equal.h @@ -0,0 +1,90 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_EQUAL_H_INCLUDED +#define BEAST_EQUAL_H_INCLUDED + +#include "equal_to.h" + +#include +#include + +namespace std { + +namespace detail { + +template +bool equal (FwdIt1 first1, FwdIt1 last1, + FwdIt2 first2, FwdIt2 last2, Pred pred, + std::input_iterator_tag, std::input_iterator_tag) +{ + for (; first1 != last1 && first2 != last2; ++first1, ++first2) + if (! pred (*first1, *first2)) + return false; + return first1 == last1 && first2 == last2; +} + +template +bool equal (RanIt1 first1, RanIt1 last1, + RanIt2 first2, RanIt2 last2, Pred pred, + random_access_iterator_tag, + random_access_iterator_tag ) +{ + if (std::distance (first1, last1) != + std::distance (first2, last2)) + return false; + for (; first1 != last1; ++first1, ++first2) + if (! pred (*first1, *first2)) + return false; + return true; +} + +} + +/** C++14 implementation of std::equal. */ +/** @{ */ +template +bool equal (FwdIt1 first1, FwdIt1 last1, + FwdIt2 first2, FwdIt2 last2) +{ + return std::detail::equal (first1, last1, + first2, last2, std::equal_to (), + typename std::iterator_traits < + FwdIt1>::iterator_category(), + typename std::iterator_traits < + FwdIt2>::iterator_category()); +} + +template +bool equal (FwdIt1 first1, FwdIt1 last1, + FwdIt2 first2, FwdIt2 last2, Pred pred) +{ + return std::detail::equal < + typename std::add_lvalue_reference ::type> ( + first1, last1, first2, last2, pred, + typename std::iterator_traits < + FwdIt1>::iterator_category(), + typename std::iterator_traits < + FwdIt2>::iterator_category()); +} +/** @} */ + +} + +#endif diff --git a/beast/equal_to.h b/beast/equal_to.h new file mode 100644 index 000000000..8e66f9b2b --- /dev/null +++ b/beast/equal_to.h @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_EQUAL_TO_H_INCLUDED +#define BEAST_EQUAL_TO_H_INCLUDED + +#include +#include + +namespace std { + +#ifndef _MSC_VER + +/** C++14 implementation of std::equal_to specialization. + This supports heterogeneous comparisons. +*/ +template <> +struct equal_to +{ + // VFALCO NOTE Its not clear how to support is_transparent pre c++14 + typedef std::true_type is_transparent; + + template + auto operator() (T&& lhs, U&& rhs) const -> + decltype (std::forward (lhs) == std::forward (rhs)) + { + return std::forward (lhs) == std::forward (rhs); + } +}; + +#endif + +} + +#endif diff --git a/beast/is_constructible.h b/beast/is_constructible.h new file mode 100644 index 000000000..de8fd6870 --- /dev/null +++ b/beast/is_constructible.h @@ -0,0 +1,76 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Howard Hinnant , + Vinnie Falco + + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_IS_CONSTRUCTIBLE_H_INCLUDED +#define BEAST_IS_CONSTRUCTIBLE_H_INCLUDED + +#include +#include +#include + +namespace std { + +// Ideas from Howard Hinnant +// +// Specializations of is_constructible for pair and tuple which +// work around an apparent defect in the standard that causes well +// formed expressions involving pairs or tuples of non default-constructible +// types to generate compile errors. +// +template +struct is_constructible > + : integral_constant ::value && + is_default_constructible ::value> +{ +}; + +namespace detail { + +template +struct compile_time_all; + +template <> +struct compile_time_all <> +{ + static const bool value = true; +}; + +template +struct compile_time_all +{ + static const bool value = + Arg0 && compile_time_all ::value; +}; + +} + +template +struct is_constructible > + : integral_constant ::value...>::value> +{ +}; + +} + +#endif diff --git a/beast/type_traits/maybe_const.h b/beast/type_traits/maybe_const.h new file mode 100644 index 000000000..b72d08e72 --- /dev/null +++ b/beast/type_traits/maybe_const.h @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_TYPE_TRAITS_MAYBE_CONST_H_INCLUDED +#define BEAST_TYPE_TRAITS_MAYBE_CONST_H_INCLUDED + +#include + +namespace beast { + +/** Makes T const or non const depending on a bool. */ +template +struct maybe_const +{ + typedef typename std::conditional ::type const, + typename std::remove_const ::type>::type type; +}; + +} + +#endif diff --git a/beast/utility/empty_base_optimization.h b/beast/utility/empty_base_optimization.h new file mode 100644 index 000000000..fd8bffa3b --- /dev/null +++ b/beast/utility/empty_base_optimization.h @@ -0,0 +1,160 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_UTILITY_EMPTY_BASE_OPTIMIZATION_H_INCLUDED +#define BEAST_UTILITY_EMPTY_BASE_OPTIMIZATION_H_INCLUDED + +#include +#include + +#ifndef BEAST_NO_EMPTY_BASE_OPTIMIZATION +# if defined _MSC_VER +# define BEAST_NO_EMPTY_BASE_OPTIMIZATION 1 +# else +# define BEAST_NO_EMPTY_BASE_OPTIMIZATION 1 +# endif +#endif + +namespace beast { + +namespace detail { + +#if ! BEAST_NO_EMPTY_BASE_OPTIMIZATION + +template +struct empty_base_optimization_decide + : std::integral_constant ::value +#ifdef __clang__ + && !__is_final(T) +#endif + > +{ +}; + +#else + +template +struct empty_base_optimization_decide + : std::false_type +{ +}; + +#endif + +} + +//------------------------------------------------------------------------------ + +template < + class T, + int UniqueID = 0, + bool ShouldDeriveFrom = + detail::empty_base_optimization_decide ::value +> +class empty_base_optimization : private T +{ +public: + template < + class... Args, + class = typename std::enable_if < + std::is_constructible ::value>::type + > + explicit /*constexpr*/ empty_base_optimization ( + Args&&... args) + /*noexcept (std::is_nothrow_constructible ::value);*/ + : T (std::forward (args)...) + { + } + +#if 1 + empty_base_optimization (T const& t) + : T (t) + { + } + + empty_base_optimization (T&& t) + : T (std::move (t)) + { + } + + empty_base_optimization& operator= ( + empty_base_optimization const& other) + { + *this = other; + return *this; + } + + empty_base_optimization& operator= ( + empty_base_optimization&& other) + { + *this = std::move (other); + return *this; + } +#endif + + T& member() noexcept + { + return *this; + } + + T const& member() const noexcept + { + return *this; + } +}; + +//------------------------------------------------------------------------------ + +template < + class T, + int UniqueID +> +class empty_base_optimization +{ +public: + template < + class... Args, + class = typename std::enable_if < + std::is_constructible ::value>::type + > + explicit /*constexpr*/ empty_base_optimization ( + Args&&... args) + /*noexcept (std::is_nothrow_constructible ::value);*/ + : m_t (std::forward (args)...) + { + } + + T& member() noexcept + { + return m_t; + } + + T const& member() const noexcept + { + return m_t; + } + +private: + T m_t; +}; + +} + +#endif diff --git a/beast/utility/impl/PropertyStream.cpp b/beast/utility/impl/PropertyStream.cpp index ba33f982d..f3b6e7509 100644 --- a/beast/utility/impl/PropertyStream.cpp +++ b/beast/utility/impl/PropertyStream.cpp @@ -336,9 +336,9 @@ PropertyStream::Source* PropertyStream::Source::find_one_deep (std::string const if (found != nullptr) return found; SharedState::Access state (this->m_state); - for (auto iter : state->children) + for (auto& s : state->children) { - found = iter.source().find_one_deep (name); + found = s.source().find_one_deep (name); if (found != nullptr) return found; } @@ -366,10 +366,10 @@ PropertyStream::Source* PropertyStream::Source::find_path (std::string path) PropertyStream::Source* PropertyStream::Source::find_one (std::string const& name) { SharedState::Access state (this->m_state); - for (auto iter : state->children) + for (auto& s : state->children) { - if (iter.source().m_name == name) - return &iter.source(); + if (s.source().m_name == name) + return &s.source(); } return nullptr; }