Fixed the emplace function implementations for stack and queue (#2657)

* Fixed the emplace function implementations for stack and queue

Cleaned up several functions in the stack, queue and priority_queue
classes that were non-standard or weren't needed.

Updated the "style" of the code to use more modern concepts: "typedef" ->
"using", empty constructor body -> default keyword.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Replaced the custom implementations of AZStd stack, (proirity)queue

Theses classes now have a template alias to the standard library version
of the classes

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
This commit is contained in:
lumberyard-employee-dm
2021-07-30 18:20:21 -05:00
committed by GitHub
parent 0318419932
commit bb372f05cd
11 changed files with 55 additions and 317 deletions
+3 -3
View File
@@ -268,7 +268,7 @@ namespace AZ
m_messages.pop();
if (numMessages == 1)
{
m_messages.get_container().clear(); // If it was the last message, free all memory.
m_messages = {};
}
}
//////////////////////////////////////////////////////////////////////////
@@ -280,7 +280,7 @@ namespace AZ
void Clear()
{
AZStd::lock_guard<MutexType> lock(m_messagesMutex);
m_messages.get_container().clear();
m_messages = {};
}
void SetActive(bool isActive)
@@ -289,7 +289,7 @@ namespace AZ
m_isActive = isActive;
if (!m_isActive)
{
m_messages.get_container().clear();
m_messages = {};
}
};
@@ -42,8 +42,6 @@ namespace AZStd
class unordered_multiset;
template<AZStd::size_t NumBits>
class bitset;
template<class T, class Container/* = AZStd::deque<T>*/ >
class stack;
template<class T>
class intrusive_ptr;
@@ -5,206 +5,17 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef AZSTD_QUEUE_H
#define AZSTD_QUEUE_H 1
#pragma once
#include <AzCore/std/containers/deque.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/functional_basic.h>
#include <queue>
namespace AZStd
{
/**
* FIFO queue complaint with \ref CStd (23.2.3.1)
* The only extension we have is that we allow access
* to the underlying container via: get_container function.
* Check the queue \ref AZStdExamples.
*/
template<class T, class Container = AZStd::deque<T> >
class queue
{
enum
{
CONTAINER_VERSION = 1
};
public:
typedef queue<T, Container> this_type;
typedef Container container_type;
typedef typename Container::value_type value_type;
typedef typename Container::size_type size_type;
typedef typename Container::reference reference;
typedef typename Container::const_reference const_reference;
AZ_FORCE_INLINE queue() {}
AZ_FORCE_INLINE explicit queue(const container_type& container)
: m_container(container) {}
AZ_FORCE_INLINE bool empty() const { return m_container.empty(); }
AZ_FORCE_INLINE size_type size() const { return m_container.size(); }
AZ_FORCE_INLINE reference front() { return m_container.front(); }
AZ_FORCE_INLINE const_reference front() const { return m_container.front(); }
AZ_FORCE_INLINE reference back() { return m_container.back(); }
AZ_FORCE_INLINE const_reference back() const { return m_container.back(); }
AZ_FORCE_INLINE void push(const value_type& value) { m_container.push_back(value); }
AZ_FORCE_INLINE void pop() { m_container.pop_front(); }
AZ_FORCE_INLINE void push() { m_container.push_back(); }
AZ_FORCE_INLINE queue(this_type&& rhs)
: m_container(AZStd::move(rhs.m_container)) {}
AZ_FORCE_INLINE explicit queue(Container&& container)
: m_container(AZStd::move(container)) {}
this_type& operator=(this_type&& rhs)
{
m_container = AZStd::move(rhs.m_container);
return (*this);
}
void push(value_type&& value) { m_container.push_back(AZStd::move(value)); }
template<class... Args>
void emplace(Args&&... args) { m_container.emplace_back(AZStd::forward<Args>(args)...); }
void swap(this_type& rhs) { AZStd::swap(m_container, rhs.m_container); }
AZ_FORCE_INLINE Container& get_container() { return m_container; }
AZ_FORCE_INLINE const Container& get_container() const { return m_container; }
protected:
Container m_container;
};
// queue TEMPLATE FUNCTIONS
template<class T, class Container>
AZ_FORCE_INLINE bool operator==(const AZStd::queue<T, Container>& left, const AZStd::queue<T, Container>& right)
{
return left.get_container() == right.get_container();
}
template<class T, class Container>
AZ_FORCE_INLINE bool operator!=(const AZStd::queue<T, Container>& left, const AZStd::queue<T, Container>& right)
{
return left.get_container() != right.get_container();
}
/* template<class T, class Container>
AZ_FORCE_INLINE bool operator<(const queue<T,Container>& left, const queue<T,Container>& right)
{
return left.get_container() < right.get_container();
}
template<class T, class Container>
AZ_FORCE_INLINE bool operator>(const queue<T,Container>& left, const queue<T,Container>& right)
{
return left.get_container() > right.get_container();
}
template<class T, class Container>
AZ_FORCE_INLINE operator<=(const queue<T,Container>& left, const queue<T,Container>& right)
{
return left.get_container() <= right.get_container();
}
template<class T, class Container>
AZ_FORCE_INLINE bool operator>=(const queue<T,Container>& left, const queue<T,Container>& right)
{
return left.get_container() >= right.get_container();
}*/
/**
* Priority queue is complaint with \ref CStd (23.2.3.2)
* The only extension we have is that we allow access
* to the underlying container via: get_container function.
* Check the priority_queue \ref AZStdExamples.
*/
template<class T, class Container = AZStd::vector<T>, class Predicate = AZStd::less<typename Container::value_type> >
class priority_queue
{
enum
{
CONTAINER_VERSION = 1
};
public:
typedef priority_queue<T, Container, Predicate> this_type;
typedef Container container_type;
typedef typename Container::value_type value_type;
typedef typename Container::size_type size_type;
typedef typename Container::reference reference;
typedef typename Container::const_reference const_reference;
AZ_FORCE_INLINE priority_queue() {}
AZ_FORCE_INLINE explicit priority_queue(const Predicate& comp)
: m_comp(comp) {}
AZ_FORCE_INLINE priority_queue(const Predicate& comp, const container_type& container)
: m_container(container)
, m_comp(comp)
{
// construct by copying specified container, comparator
AZStd::make_heap(m_container.begin(), m_container.end(), comp);
}
template<class InputIterator>
AZ_FORCE_INLINE priority_queue(InputIterator first, InputIterator last)
: m_container(first, last)
, m_comp()
{
AZStd::make_heap(m_container.begin(), m_container.end(), m_comp);
}
template<class InputIterator>
AZ_FORCE_INLINE priority_queue(InputIterator first, InputIterator last, const Predicate& comp)
: m_container(first, last)
, m_comp(comp)
{ // construct by copying [_First, _Last), specified comparator
AZStd::make_heap(m_container.begin(), m_container.end(), m_comp);
}
template<class InputIterator>
AZ_FORCE_INLINE priority_queue(InputIterator first, InputIterator last, const Predicate& comp, const container_type& container)
: m_container(container)
, m_comp(comp)
{ // construct by copying [_First, _Last), container, and comparator
m_container.insert(m_container.end(), first, last);
AZStd::make_heap(m_container.begin(), m_container.end(), m_comp);
}
AZ_FORCE_INLINE bool empty() const { return m_container.empty(); }
AZ_FORCE_INLINE size_type size() const { return m_container.size(); }
AZ_FORCE_INLINE const_reference top() const { return m_container.front(); }
AZ_FORCE_INLINE reference top() { return m_container.front(); }
AZ_FORCE_INLINE void push(const value_type& value)
{
m_container.push_back(value);
AZStd::push_heap(m_container.begin(), m_container.end(), m_comp);
}
AZ_FORCE_INLINE void pop()
{
AZStd::pop_heap(m_container.begin(), m_container.end(), m_comp);
m_container.pop_back();
}
AZ_FORCE_INLINE priority_queue(this_type&& rhs)
: m_container(AZStd::move(rhs.m_container))
, m_comp(AZStd::move(rhs.m_comp)) {}
AZ_FORCE_INLINE explicit priority_queue(const Predicate& pred, Container&& container)
: m_container(AZStd::move(container))
, m_comp(pred) {}
this_type& operator=(this_type&& rhs)
{
m_container = AZStd::move(rhs.m_container);
m_comp = AZStd::move(rhs.m_comp);
return (*this);
}
void push(value_type&& value) { m_container.push_back(AZStd::move(value)); AZStd::push_heap(m_container.begin(), m_container.end(), m_comp); }
template<class Args>
void emplace(Args&& args) { m_container.emplace_back(AZStd::forward<Args>(args)); AZStd::push_heap(m_container.begin(), m_container.end(), m_comp); }
void swap(this_type& rhs) { AZStd::swap(m_container, rhs.m_container); AZStd::swap(m_comp, rhs.m_comp); }
AZ_FORCE_INLINE Container& get_container() { return m_container; }
AZ_FORCE_INLINE const Container& get_container() const { return m_container; }
protected:
Container m_container;
Predicate m_comp;
};
template<class T, class Container = AZStd::deque<T>>
using queue = std::queue<T, Container>;
template<class T, class Container = AZStd::vector<T>, class Compare = AZStd::less<typename Container::value_type>>
using priority_queue = std::priority_queue<T, Container, Compare>;
}
#endif // AZSTD_QUEUE_H
#pragma once
@@ -5,103 +5,13 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef AZSTD_STACK_H
#define AZSTD_STACK_H 1
#pragma once
#include <AzCore/std/containers/deque.h>
#include <stack>
namespace AZStd
{
/**
* Stack container is complaint with \ref CStd (23.2.3.3)
* The only extension we have is that we allow access
* to the underlying container via: get_container function.
* Check the stack \ref AZStdExamples.
*/
template<class T, class Container = AZStd::deque<T> >
class stack
{
enum
{
CONTAINER_VERSION = 1
};
public:
typedef stack<T, Container> this_type;
typedef Container container_type;
typedef typename Container::value_type value_type;
typedef typename Container::size_type size_type;
typedef typename Container::reference reference;
typedef typename Container::const_reference const_reference;
AZ_FORCE_INLINE stack() {}
AZ_FORCE_INLINE explicit stack(const container_type& container)
: m_container(container) {}
AZ_FORCE_INLINE bool empty() const { return m_container.empty(); }
AZ_FORCE_INLINE size_type size() const { return m_container.size(); }
AZ_FORCE_INLINE reference top() { return m_container.back(); }
AZ_FORCE_INLINE const_reference top() const { return m_container.back(); }
AZ_FORCE_INLINE reference back() { return m_container.back(); }
AZ_FORCE_INLINE const_reference back() const { return m_container.back(); }
AZ_FORCE_INLINE void push(const value_type& value) { m_container.push_back(value); }
AZ_FORCE_INLINE void pop() { m_container.pop_back(); }
AZ_FORCE_INLINE void push() { m_container.push_back(); }
AZ_FORCE_INLINE stack(this_type&& rhs)
: m_container(AZStd::move(rhs.m_container)) {}
AZ_FORCE_INLINE explicit stack(Container&& container)
: m_container(AZStd::move(container)) {}
this_type& operator=(this_type&& rhs) { m_container = AZStd::move(rhs.m_container); return *this; }
void push(value_type&& value) { m_container.push_back(AZStd::move(value)); }
template<class Args>
void emplace(Args&& args) { m_container.emplace_back(AZStd::forward<Args>(args)); }
void swap(this_type&& rhs) { m_container.swap(AZStd::move(rhs.m_container)); }
void swap(this_type& rhs) { AZStd::swap(m_container, rhs.m_container); }
AZ_FORCE_INLINE Container& get_container() { return m_container; }
AZ_FORCE_INLINE const Container& get_container() const { return m_container; }
protected:
Container m_container;
};
// queue TEMPLATE FUNCTIONS
template<class T, class Container>
AZ_FORCE_INLINE bool operator==(const AZStd::stack<T, Container>& left, const AZStd::stack<T, Container>& right)
{
return left.get_container() == right.get_container();
}
template<class T, class Container>
AZ_FORCE_INLINE bool operator!=(const AZStd::stack<T, Container>& left, const AZStd::stack<T, Container>& right)
{
return left.get_container() != right.get_container();
}
/* template<class T, class Container>
AZ_FORCE_INLINE bool operator<(const queue<T,Container>& left, const queue<T,Container>& right)
{
return left.get_container() < right.get_container();
}
template<class T, class Container>
AZ_FORCE_INLINE bool operator>(const queue<T,Container>& left, const queue<T,Container>& right)
{
return left.get_container() > right.get_container();
}
template<class T, class Container>
AZ_FORCE_INLINE operator<=(const queue<T,Container>& left, const queue<T,Container>& right)
{
return left.get_container() <= right.get_container();
}
template<class T, class Container>
AZ_FORCE_INLINE bool operator>=(const queue<T,Container>& left, const queue<T,Container>& right)
{
return left.get_container() >= right.get_container();
}*/
template<class T, class Container = AZStd::deque<T>>
using stack = std::stack<T, Container>;
}
#endif // AZSTD_STACK_H
#pragma once
@@ -298,7 +298,7 @@ namespace UnitTest
AZ_TEST_ASSERT(int_queue.empty());
AZ_TEST_ASSERT(int_queue.size() == 0);
// Queue uses deque as default container, so try to contruct to queue from a deque.
// Queue uses deque as default container, so try to construct to queue from a deque.
deque<int> container(40, 10);
int_queue_type int_queue2(container);
AZ_TEST_ASSERT(!int_queue2.empty());
@@ -324,7 +324,7 @@ namespace UnitTest
AZ_TEST_ASSERT(int_queue2.size() == 40);
AZ_TEST_ASSERT(int_queue2.back() == 20);
int_queue.push();
int_queue.emplace();
AZ_TEST_ASSERT(!int_queue.empty());
AZ_TEST_ASSERT(int_queue.size() == 1);
@@ -423,7 +423,7 @@ namespace UnitTest
AZ_TEST_ASSERT(int_stack2.size() == 40);
AZ_TEST_ASSERT(int_stack2.top() == 10);
int_stack.push();
int_stack.emplace();
AZ_TEST_ASSERT(!int_stack.empty());
AZ_TEST_ASSERT(int_stack.size() == 1);
// StackContainerTest-End
@@ -669,4 +669,19 @@ namespace UnitTest
++iteration;
}
}
using StackContainerTestFixture = ScopedAllocatorSetupFixture;
TEST_F(StackContainerTestFixture, StackEmplaceOperator_SupportsZeroOrMoreArguments)
{
using TestPairType = AZStd::pair<int, int>;
AZStd::stack<TestPairType> testStack;
testStack.emplace();
testStack.emplace(1);
testStack.emplace(2, 3);
using ContainerType = typename AZStd::stack<TestPairType>::container_type;
AZStd::stack<TestPairType> expectedStack(ContainerType{ TestPairType{ 0, 0 }, TestPairType{ 1, 0 }, TestPairType{ 2, 3 } });
EXPECT_EQ(expectedStack, testStack);
}
}
@@ -32,7 +32,7 @@ namespace UnitTest
void TestDebugDisplayRequests::DrawWireBox(const AZ::Vector3& min, const AZ::Vector3& max)
{
const AZ::Transform& tm = m_transforms.back();
const AZ::Transform& tm = m_transforms.top();
m_points.push_back(tm.TransformPoint(AZ::Vector3(min.GetX(), min.GetY(), min.GetZ())));
m_points.push_back(tm.TransformPoint(AZ::Vector3(min.GetX(), min.GetY(), max.GetZ())));
m_points.push_back(tm.TransformPoint(AZ::Vector3(min.GetX(), max.GetY(), min.GetZ())));
@@ -50,7 +50,7 @@ namespace UnitTest
void TestDebugDisplayRequests::DrawWireQuad(float width, float height)
{
const AZ::Transform& tm = m_transforms.back();
const AZ::Transform& tm = m_transforms.top();
m_points.push_back(tm.TransformPoint(AZ::Vector3(-0.5f * width, 0.0f, -0.5f * height)));
m_points.push_back(tm.TransformPoint(AZ::Vector3(-0.5f * width, 0.0f, 0.5f * height)));
m_points.push_back(tm.TransformPoint(AZ::Vector3(0.5f * width, 0.0f, -0.5f * height)));
@@ -64,7 +64,7 @@ namespace UnitTest
void TestDebugDisplayRequests::DrawPoints(const AZStd::vector<AZ::Vector3>& points)
{
const AZ::Transform& tm = m_transforms.back();
const AZ::Transform& tm = m_transforms.top();
for (const auto& point : points)
{
m_points.push_back(tm.TransformPoint(point));
@@ -100,7 +100,7 @@ namespace UnitTest
void TestDebugDisplayRequests::PushMatrix(const AZ::Transform& tm)
{
m_transforms.push(m_transforms.back() * tm);
m_transforms.push(m_transforms.top() * tm);
}
void TestDebugDisplayRequests::PopMatrix()
@@ -481,7 +481,7 @@ namespace AzFramework
if (!m_freeOctreeNodes.empty())
{
// Take a free block of child nodes from our free list
ExtractPageAndOffsetFromIndex(m_freeOctreeNodes.back(), nextChildPage, nextChildOffset);
ExtractPageAndOffsetFromIndex(m_freeOctreeNodes.top(), nextChildPage, nextChildOffset);
m_freeOctreeNodes.pop();
}
else
@@ -1688,12 +1688,12 @@ namespace GridMate
return; //No connections to update
}
bool updateRate = false;
AZ::u32 minRateBytesPerSecond = m_connByCongestionState.top().m_rate;
AZ::u32 minRateBytesPerSecond = m_connByCongestionState.front().m_rate;
//const AZ::u32 old = minRateBytesPerSecond; //For debugging
auto connIt = AZStd::find(m_connByCongestionState.get_container().begin(), m_connByCongestionState.get_container().end(), id);
auto connIt = AZStd::find(m_connByCongestionState.begin(), m_connByCongestionState.end(), id);
if ( connIt == m_connByCongestionState.get_container().end())
if ( connIt == m_connByCongestionState.end())
{
return; //Already disconnected
}
@@ -1708,11 +1708,11 @@ namespace GridMate
//If new min or old min increased, rebuild the heap and send an update
if (bytesPerSecond < minRateBytesPerSecond
|| (id == m_connByCongestionState.top().m_connection && bytesPerSecond > minRateBytesPerSecond))
|| (id == m_connByCongestionState.front().m_connection && bytesPerSecond > minRateBytesPerSecond))
{
updateRate = true;
minRateBytesPerSecond = bytesPerSecond;
AZStd::make_heap(m_connByCongestionState.get_container().begin(), m_connByCongestionState.get_container().end());
AZStd::make_heap(m_connByCongestionState.begin(), m_connByCongestionState.end());
}
}
@@ -459,7 +459,7 @@ namespace GridMate
}
};
static bool k_enableBackPressure;
AZStd::priority_queue<RateConnectionPair> m_connByCongestionState; ///< Connections priority queue sorted by congestion window
AZStd::vector<RateConnectionPair> m_connByCongestionState; ///< Connections priority queue sorted by congestion window
/***
* Updates connection's rate in priority and updates send limit
*
@@ -479,7 +479,9 @@ namespace GridMate
}
AZ_Assert(carrier, "NULL carrier!");
m_connByCongestionState.emplace(RateConnectionPair(AZ::u32(1500), id)); //default to 1500Bps (ex 1 Ethernet frame/second minimum)
m_connByCongestionState.emplace_back(AZ::u32(1500), id); //default to 1500Bps (ex 1 Ethernet frame/second minimum)
// Restore the heap property after pushing back another element
AZStd::push_heap(m_connByCongestionState.begin(), m_connByCongestionState.end());
}
void OnDisconnect(Carrier* carrier, ConnectionID id, CarrierDisconnectReason reason) override
{
@@ -490,17 +492,17 @@ namespace GridMate
}
AZ_Assert(carrier, "NULL carrier!");
auto connIt = AZStd::find(m_connByCongestionState.get_container().begin(), m_connByCongestionState.get_container().end(), id);
if (connIt != m_connByCongestionState.get_container().end())
auto connIt = AZStd::find(m_connByCongestionState.begin(), m_connByCongestionState.end(), id);
if (connIt != m_connByCongestionState.end())
{
//Since we are using a weakly sorted heap, we need to re-generate when the top is removed
bool remake = (connIt == m_connByCongestionState.get_container().begin());
bool remake = (connIt == m_connByCongestionState.begin());
m_connByCongestionState.get_container().erase(connIt);
m_connByCongestionState.erase(connIt);
if (remake)
{
AZStd::make_heap(m_connByCongestionState.get_container().begin(), m_connByCongestionState.get_container().end());
AZStd::make_heap(m_connByCongestionState.begin(), m_connByCongestionState.end());
}
}
}
@@ -395,7 +395,7 @@ namespace EMotionFX
}
// If new parameter matches the last deleted parameter, we add it back to the parameter mask.
if (!m_deletedParameterNames.empty() && newParameterName == m_deletedParameterNames.back())
if (!m_deletedParameterNames.empty() && newParameterName == m_deletedParameterNames.top())
{
m_parameterNames.push_back(newParameterName);
SortAndRemoveDuplicates(GetAnimGraph(), m_parameterNames); // make sure the mask is sorted correctly.
@@ -107,8 +107,10 @@ namespace Multiplayer
void ServerToClientReplicationWindow::UpdateWindow()
{
// clear the candidate queue, we're going to rebuild it
ReplicationCandidateQueue clearQueue;
clearQueue.get_container().reserve(sv_MaxEntitiesToTrackReplication);
ReplicationCandidateQueue::container_type clearQueueContainer;
clearQueueContainer.reserve(sv_MaxEntitiesToTrackReplication);
// Move the clearQueueContainer into the ReplicationCandidateQueue to maintain the reserved memory
ReplicationCandidateQueue clearQueue(ReplicationCandidateQueue::value_compare{}, AZStd::move(clearQueueContainer));
m_candidateQueue.swap(clearQueue);
m_replicationSet.clear();