Replace MCore::SmallArray usage with AZStd::vector

Signed-off-by: Chris Burel <burelc@amazon.com>
monroegm-disable-blank-issue-2
Chris Burel 4 years ago
parent adaeb7c203
commit 0953a75a94

@ -41,15 +41,15 @@ namespace CommandSystem
void MetaData::GenerateNodeGroupMetaData(EMotionFX::Actor* actor, AZStd::string& outMetaDataString)
{
AZStd::string nodeNameList;
const AZ::u32 numNodeGroups = actor->GetNumNodeGroups();
for (uint32 i = 0; i < numNodeGroups; ++i)
const size_t numNodeGroups = actor->GetNumNodeGroups();
for (size_t i = 0; i < numNodeGroups; ++i)
{
EMotionFX::NodeGroup* nodeGroup = actor->GetNodeGroup(i);
outMetaDataString += AZStd::string::format("AddNodeGroup -actorID $(ACTORID) -name \"%s\"\n", nodeGroup->GetName());
nodeNameList.clear();
const AZ::u16 numNodes = nodeGroup->GetNumNodes();
for (AZ::u16 n = 0; n < numNodes; ++n)
const size_t numNodes = nodeGroup->GetNumNodes();
for (size_t n = 0; n < numNodes; ++n)
{
const AZ::u16 nodeIndex = nodeGroup->GetNode(n);
EMotionFX::Node* node = actor->GetSkeleton()->GetNode(nodeIndex);

@ -80,7 +80,7 @@ namespace CommandSystem
{
if (*m_nodeAction == NodeAction::Replace)
{
nodeGroup->GetNodeArray().Clear();
nodeGroup->GetNodeArray().clear();
}
for (const AZStd::string& nodeName : *m_nodeNames)
{
@ -146,12 +146,12 @@ namespace CommandSystem
if (m_nodeNames.has_value())
{
// clear previous nodes
nodeGroup->GetNodeArray().Clear();
const uint16 numNodes = m_oldNodeGroup->GetNumNodes();
nodeGroup->GetNodeArray().clear();
const size_t numNodes = m_oldNodeGroup->GetNumNodes();
nodeGroup->SetNumNodes(numNodes);
// add all nodes to the group
for (uint16 i = 0; i < numNodes; ++i)
for (size_t i = 0; i < numNodes; ++i)
{
nodeGroup->SetNode(i, m_oldNodeGroup->GetNode(i));
}

@ -249,7 +249,7 @@ namespace ExporterLib
{
chunkHeader.m_sizeInBytes += sizeof(EMotionFX::FileFormat::Actor_NodeGroup);
chunkHeader.m_sizeInBytes += GetStringChunkSize(nodeGroup->GetNameString());
chunkHeader.m_sizeInBytes += sizeof(uint16) * nodeGroup->GetNumNodes();
chunkHeader.m_sizeInBytes += sizeof(uint16) * aznumeric_cast<uint32>(nodeGroup->GetNumNodes());
}
// endian conversion
@ -277,14 +277,14 @@ namespace ExporterLib
MCORE_ASSERT(actor);
// get the number of node groups
const uint32 numGroups = actor->GetNumNodeGroups();
const size_t numGroups = actor->GetNumNodeGroups();
// create the node group array and reserve some elements
AZStd::vector<EMotionFX::NodeGroup*> nodeGroups;
nodeGroups.reserve(numGroups);
// iterate through the node groups and add them to the array
for (uint32 i = 0; i < numGroups; ++i)
for (size_t i = 0; i < numGroups; ++i)
{
nodeGroups.emplace_back(actor->GetNodeGroup(i));
}

@ -142,9 +142,9 @@ namespace EMotionFX
result->RecursiveAddDependencies(this);
// clone all nodes groups
for (uint32 i = 0; i < m_nodeGroups.GetLength(); ++i)
for (const NodeGroup* nodeGroup : m_nodeGroups)
{
result->AddNodeGroup(aznew NodeGroup(*m_nodeGroups[i]));
result->AddNodeGroup(aznew NodeGroup(*nodeGroup));
}
// clone the materials
@ -948,12 +948,11 @@ namespace EMotionFX
// remove all node groups
void Actor::RemoveAllNodeGroups()
{
const uint32 numGroups = m_nodeGroups.GetLength();
for (uint32 i = 0; i < numGroups; ++i)
for (NodeGroup*& nodeGroup : m_nodeGroups)
{
delete m_nodeGroups[i];
delete nodeGroup;
}
m_nodeGroups.Clear();
m_nodeGroups.clear();
}
@ -1965,13 +1964,13 @@ namespace EMotionFX
}
uint32 Actor::GetNumNodeGroups() const
size_t Actor::GetNumNodeGroups() const
{
return m_nodeGroups.GetLength();
return m_nodeGroups.size();
}
NodeGroup* Actor::GetNodeGroup(uint32 index) const
NodeGroup* Actor::GetNodeGroup(size_t index) const
{
return m_nodeGroups[index];
}
@ -1979,90 +1978,76 @@ namespace EMotionFX
void Actor::AddNodeGroup(NodeGroup* newGroup)
{
m_nodeGroups.Add(newGroup);
m_nodeGroups.emplace_back(newGroup);
}
void Actor::RemoveNodeGroup(uint32 index, bool delFromMem)
void Actor::RemoveNodeGroup(size_t index, bool delFromMem)
{
if (delFromMem)
{
delete m_nodeGroups[index];
}
m_nodeGroups.Remove(index);
m_nodeGroups.erase(AZStd::next(begin(m_nodeGroups), index));
}
void Actor::RemoveNodeGroup(NodeGroup* group, bool delFromMem)
{
m_nodeGroups.RemoveByValue(group);
if (delFromMem)
const auto found = AZStd::find(begin(m_nodeGroups), end(m_nodeGroups), group);
if (found != end(m_nodeGroups))
{
delete group;
m_nodeGroups.erase(found);
if (delFromMem)
{
delete group;
}
}
}
// find a group index by its name
uint32 Actor::FindNodeGroupIndexByName(const char* groupName) const
size_t Actor::FindNodeGroupIndexByName(const char* groupName) const
{
const uint32 numGroups = m_nodeGroups.GetLength();
for (uint32 i = 0; i < numGroups; ++i)
const auto found = AZStd::find_if(begin(m_nodeGroups), end(m_nodeGroups), [groupName](const NodeGroup* nodeGroup)
{
if (m_nodeGroups[i]->GetNameString() == groupName)
{
return i;
}
}
return MCORE_INVALIDINDEX32;
return nodeGroup->GetNameString() == groupName;
});
return found != end(m_nodeGroups) ? AZStd::distance(begin(m_nodeGroups), found) : InvalidIndex;
}
// find a group index by its name, but not case sensitive
uint32 Actor::FindNodeGroupIndexByNameNoCase(const char* groupName) const
size_t Actor::FindNodeGroupIndexByNameNoCase(const char* groupName) const
{
const uint32 numGroups = m_nodeGroups.GetLength();
for (uint32 i = 0; i < numGroups; ++i)
const auto found = AZStd::find_if(begin(m_nodeGroups), end(m_nodeGroups), [groupName](const NodeGroup* nodeGroup)
{
if (AzFramework::StringFunc::Equal(m_nodeGroups[i]->GetNameString().c_str(), groupName, false /* no case */))
{
return i;
}
}
return MCORE_INVALIDINDEX32;
return AzFramework::StringFunc::Equal(nodeGroup->GetNameString(), groupName, false /* no case */);
});
return found != end(m_nodeGroups) ? AZStd::distance(begin(m_nodeGroups), found) : InvalidIndex;
}
// find a group by its name
NodeGroup* Actor::FindNodeGroupByName(const char* groupName) const
{
const uint32 numGroups = m_nodeGroups.GetLength();
for (uint32 i = 0; i < numGroups; ++i)
const auto found = AZStd::find_if(begin(m_nodeGroups), end(m_nodeGroups), [groupName](const NodeGroup* nodeGroup)
{
if (m_nodeGroups[i]->GetNameString() == groupName)
{
return m_nodeGroups[i];
}
}
return nullptr;
return nodeGroup->GetNameString() == groupName;
});
return found != end(m_nodeGroups) ? *found : nullptr;
}
// find a group by its name, but without case sensitivity
NodeGroup* Actor::FindNodeGroupByNameNoCase(const char* groupName) const
{
const uint32 numGroups = m_nodeGroups.GetLength();
for (uint32 i = 0; i < numGroups; ++i)
const auto found = AZStd::find_if(begin(m_nodeGroups), end(m_nodeGroups), [groupName](const NodeGroup* nodeGroup)
{
if (AzFramework::StringFunc::Equal(m_nodeGroups[i]->GetNameString().c_str(), groupName, false /* no case */))
{
return m_nodeGroups[i];
}
}
return nullptr;
return AzFramework::StringFunc::Equal(nodeGroup->GetNameString(), groupName, false /* no case */);
});
return found != end(m_nodeGroups) ? *found : nullptr;
}

@ -23,7 +23,6 @@
// include MCore related files
#include <MCore/Source/Vector.h>
#include <AzCore/std/containers/vector.h>
#include <MCore/Source/SmallArray.h>
#include <MCore/Source/Distance.h>
// include required headers
@ -567,13 +566,13 @@ namespace EMotionFX
* Get the number of node groups inside this actor object.
* @result The number of node groups.
*/
uint32 GetNumNodeGroups() const;
size_t GetNumNodeGroups() const;
/**
* Get a pointer to a given node group.
* @param index The node group index, which must be in range of [0..GetNumNodeGroups()-1].
*/
NodeGroup* GetNodeGroup(uint32 index) const;
NodeGroup* GetNodeGroup(size_t index) const;
/**
* Add a node group.
@ -586,7 +585,7 @@ namespace EMotionFX
* @param index The node group number to remove. This value must be in range of [0..GetNumNodeGroups()-1].
* @param delFromMem Set to true (default) when you wish to also delete the specified group from memory.
*/
void RemoveNodeGroup(uint32 index, bool delFromMem = true);
void RemoveNodeGroup(size_t index, bool delFromMem = true);
/**
* Remove a given node group by its pointer.
@ -601,14 +600,14 @@ namespace EMotionFX
* @param groupName The name of the group to search for. This is case sensitive.
* @result The group number, or MCORE_INVALIDINDEX32 when it cannot be found.
*/
uint32 FindNodeGroupIndexByName(const char* groupName) const;
size_t FindNodeGroupIndexByName(const char* groupName) const;
/**
* Find a group index by its name, on a non-case sensitive way.
* @param groupName The name of the group to search for. This is NOT case sensitive.
* @result The group number, or MCORE_INVALIDINDEX32 when it cannot be found.
*/
uint32 FindNodeGroupIndexByNameNoCase(const char* groupName) const;
size_t FindNodeGroupIndexByNameNoCase(const char* groupName) const;
/**
* Find a node group by its name.
@ -925,7 +924,7 @@ namespace EMotionFX
AZStd::vector<NodeMirrorInfo> m_nodeMirrorInfos; /**< The array of node mirror info. */
AZStd::vector< AZStd::vector< Material* > > m_materials; /**< A collection of materials (for each lod). */
AZStd::vector< MorphSetup* > m_morphSetups; /**< A morph setup for each geometry LOD. */
MCore::SmallArray<NodeGroup*> m_nodeGroups; /**< The set of node groups. */
AZStd::vector<NodeGroup*> m_nodeGroups; /**< The set of node groups. */
AZStd::shared_ptr<PhysicsSetup> m_physicsSetup; /**< Hit detection, ragdoll and cloth colliders, joint limits and rigid bodies. */
AZStd::shared_ptr<SimulatedObjectSetup> m_simulatedObjectSetup; /**< Setup for simulated objects */
MCore::Distance::EUnitType m_unitType; /**< The unit type used on export. */

@ -84,8 +84,8 @@ namespace EMotionFX
EnableAllNodes();
// apply actor node group default states (disable groups of nodes that are disabled on default)
const uint32 numGroups = m_actor->GetNumNodeGroups();
for (uint32 i = 0; i < numGroups; ++i)
const size_t numGroups = m_actor->GetNumNodeGroups();
for (size_t i = 0; i < numGroups; ++i)
{
if (m_actor->GetNodeGroup(i)->GetIsEnabledOnDefault() == false) // if this group is disabled on default
{

@ -17,7 +17,7 @@ namespace EMotionFX
AZ_CLASS_ALLOCATOR_IMPL(NodeGroup, NodeAllocator, 0)
NodeGroup::NodeGroup(const AZStd::string& groupName, uint16 numNodes, bool enabledOnDefault)
NodeGroup::NodeGroup(const AZStd::string& groupName, size_t numNodes, bool enabledOnDefault)
: m_name(groupName)
, m_nodes(numNodes)
, m_enabledOnDefault(enabledOnDefault)
@ -47,28 +47,28 @@ namespace EMotionFX
// set the number of nodes
void NodeGroup::SetNumNodes(const uint16 numNodes)
void NodeGroup::SetNumNodes(const size_t numNodes)
{
m_nodes.Resize(numNodes);
m_nodes.resize(numNodes);
}
// get the number of nodes
uint16 NodeGroup::GetNumNodes() const
size_t NodeGroup::GetNumNodes() const
{
return static_cast<uint16>(m_nodes.GetLength());
return m_nodes.size();
}
// set a given node to a given node number
void NodeGroup::SetNode(uint16 index, uint16 nodeIndex)
void NodeGroup::SetNode(size_t index, uint16 nodeIndex)
{
m_nodes[index] = nodeIndex;
}
// get the node number of a given index
uint16 NodeGroup::GetNode(uint16 index) const
uint16 NodeGroup::GetNode(size_t index) const
{
return m_nodes[index];
}
@ -77,10 +77,9 @@ namespace EMotionFX
// enable all nodes in the group inside a given actor instance
void NodeGroup::EnableNodes(ActorInstance* targetActorInstance)
{
const uint16 numNodes = static_cast<uint16>(m_nodes.GetLength());
for (uint16 i = 0; i < numNodes; ++i)
for (uint16 node : m_nodes)
{
targetActorInstance->EnableNode(m_nodes[i]);
targetActorInstance->EnableNode(node);
}
}
@ -88,10 +87,9 @@ namespace EMotionFX
// disable all nodes in the group inside a given actor instance
void NodeGroup::DisableNodes(ActorInstance* targetActorInstance)
{
const uint16 numNodes = static_cast<uint16>(m_nodes.GetLength());
for (uint16 i = 0; i < numNodes; ++i)
for (uint16 node : m_nodes)
{
targetActorInstance->DisableNode(m_nodes[i]);
targetActorInstance->DisableNode(node);
}
}
@ -99,26 +97,29 @@ namespace EMotionFX
// add a given node to the group (performs a realloc internally)
void NodeGroup::AddNode(uint16 nodeIndex)
{
m_nodes.Add(nodeIndex);
m_nodes.emplace_back(nodeIndex);
}
// remove a given node by its node number
void NodeGroup::RemoveNodeByNodeIndex(uint16 nodeIndex)
{
m_nodes.RemoveByValue(nodeIndex);
if (const auto found = AZStd::find(begin(m_nodes), end(m_nodes), nodeIndex); found)
{
m_nodes.erase(found);
}
}
// remove a given array element from the list of nodes
void NodeGroup::RemoveNodeByGroupIndex(uint16 index)
void NodeGroup::RemoveNodeByGroupIndex(size_t index)
{
m_nodes.Remove(index);
m_nodes.erase(AZStd::next(begin(m_nodes), index));
}
// get the node array directly
MCore::SmallArray<uint16>& NodeGroup::GetNodeArray()
AZStd::vector<uint16>& NodeGroup::GetNodeArray()
{
return m_nodes;
}

@ -11,8 +11,8 @@
// include required files
#include "EMotionFXConfig.h"
#include "BaseObject.h"
#include <MCore/Source/SmallArray.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/containers/vector.h>
namespace EMotionFX
@ -34,7 +34,7 @@ namespace EMotionFX
public:
AZ_CLASS_ALLOCATOR_DECL
NodeGroup(const AZStd::string& groupName = {}, uint16 numNodes = 0, bool enabledOnDefault = true);
NodeGroup(const AZStd::string& groupName = {}, size_t numNodes = 0, bool enabledOnDefault = true);
NodeGroup(const NodeGroup& aOther);
NodeGroup& operator=(const NodeGroup& aOther);
@ -61,13 +61,13 @@ namespace EMotionFX
* This will resize the array of node indices. Don't forget to initialize the node values after increasing the number of nodes though.
* @param numNodes The number of nodes that are inside this group.
*/
void SetNumNodes(const uint16 numNodes);
void SetNumNodes(size_t numNodes);
/**
* Get the number of nodes that remain inside this group.
* @result The number of nodes inside this group.
*/
uint16 GetNumNodes() const;
size_t GetNumNodes() const;
/**
* Set the value of a given node.
@ -75,14 +75,14 @@ namespace EMotionFX
* @param nodeIndex The value for the given node. This is the node index which points inside the Actor object where this group will belong to.
* To get access to the actual node object use Actor::GetNode( nodeIndex ).
*/
void SetNode(uint16 index, uint16 nodeIndex);
void SetNode(size_t index, uint16 nodeIndex);
/**
* Get the node index for a given node inside the group.
* @param index The node number inside this group, which must be in range of [0..GetNumNodes()-1].
* @result The node number, which points inside the Actor object. Use Actor::GetNode( returnValue ) to get access to the node information.
*/
uint16 GetNode(uint16 index) const;
uint16 GetNode(size_t index) const;
/**
* Enable all nodes that remain inside this group, for a given actor instance.
@ -127,13 +127,13 @@ namespace EMotionFX
* @param index The node index in the group. So for example an index value of 5 will remove the sixth node from the group.
* The index value must be in range of [0..GetNumNodes() - 1].
*/
void RemoveNodeByGroupIndex(uint16 index);
void RemoveNodeByGroupIndex(size_t index);
/**
* Get direct access to the array of node indices that are part of this group.
* @result A reference to the array of nodes inside this group. Please use this with care.
*/
MCore::SmallArray<uint16>& GetNodeArray();
AZStd::vector<uint16>& GetNodeArray();
/**
* Check whether this group is enabled after actor instance creation time.
@ -155,7 +155,7 @@ namespace EMotionFX
private:
AZStd::string m_name; /**< The name of the group. */
MCore::SmallArray<uint16> m_nodes; /**< The node index numbers that are inside this group. */
AZStd::vector<uint16> m_nodes; /**< The node index numbers that are inside this group. */
bool m_enabledOnDefault; /**< Specifies whether this group is enabled on default (true) or disabled (false). With on default we mean after directly after the actor instance using this group has been created. */
};
} // namespace EMotionFX

@ -262,11 +262,11 @@ namespace EMStudio
m_clearButton->setDisabled(disableButtons);
// set the row count
m_nodeGroupsTable->setRowCount(m_actor->GetNumNodeGroups());
m_nodeGroupsTable->setRowCount(aznumeric_caster(m_actor->GetNumNodeGroups()));
// fill the table with the existing node groups
const uint32 numNodeGroups = m_actor->GetNumNodeGroups();
for (uint32 i = 0; i < numNodeGroups; ++i)
const size_t numNodeGroups = m_actor->GetNumNodeGroups();
for (size_t i = 0; i < numNodeGroups; ++i)
{
// get the nodegroup
EMotionFX::NodeGroup* nodeGroup = m_actor->GetNodeGroup(i);
@ -287,16 +287,16 @@ namespace EMStudio
// create table items
QTableWidgetItem* tableItemGroupName = new QTableWidgetItem(nodeGroup->GetName());
AZStd::string numGroupString = AZStd::string::format("%i", nodeGroup->GetNumNodes());
AZStd::string numGroupString = AZStd::string::format("%zu", nodeGroup->GetNumNodes());
QTableWidgetItem* tableItemNumNodes = new QTableWidgetItem(numGroupString.c_str());
// add items to the table
m_nodeGroupsTable->setCellWidget(i, 0, checkbox);
m_nodeGroupsTable->setItem(i, 1, tableItemGroupName);
m_nodeGroupsTable->setItem(i, 2, tableItemNumNodes);
m_nodeGroupsTable->setCellWidget(aznumeric_caster(i), 0, checkbox);
m_nodeGroupsTable->setItem(aznumeric_caster(i), 1, tableItemGroupName);
m_nodeGroupsTable->setItem(aznumeric_caster(i), 2, tableItemNumNodes);
// set the row height
m_nodeGroupsTable->setRowHeight(i, 21);
m_nodeGroupsTable->setRowHeight(aznumeric_caster(i), 21);
}
// set the old selected row if any one

@ -150,17 +150,17 @@ namespace EMStudio
m_removeNodesButton->setEnabled((m_nodeTable->rowCount() != 0) && (m_nodeTable->selectedItems().size() != 0));
// clear the table widget
m_nodeTable->setRowCount(m_nodeGroup->GetNumNodes());
m_nodeTable->setRowCount(aznumeric_caster(m_nodeGroup->GetNumNodes()));
// set header items for the table
AZStd::string headerText = AZStd::string::format("%s Nodes (%i / %zu)", ((m_nodeGroup->GetIsEnabledOnDefault()) ? "Enabled" : "Disabled"), m_nodeGroup->GetNumNodes(), m_actor->GetNumNodes());
AZStd::string headerText = AZStd::string::format("%s Nodes (%zu / %zu)", ((m_nodeGroup->GetIsEnabledOnDefault()) ? "Enabled" : "Disabled"), m_nodeGroup->GetNumNodes(), m_actor->GetNumNodes());
QTableWidgetItem* nameHeaderItem = new QTableWidgetItem(headerText.c_str());
nameHeaderItem->setTextAlignment(Qt::AlignVCenter | Qt::AlignCenter);
m_nodeTable->setHorizontalHeaderItem(0, nameHeaderItem);
// fill the table with content
const uint16 numNodes = m_nodeGroup->GetNumNodes();
for (uint16 i = 0; i < numNodes; ++i)
const size_t numNodes = m_nodeGroup->GetNumNodes();
for (size_t i = 0; i < numNodes; ++i)
{
// get the nodegroup
EMotionFX::Node* node = m_actor->GetSkeleton()->GetNode(m_nodeGroup->GetNode(i));
@ -173,10 +173,10 @@ namespace EMStudio
// create table items
QTableWidgetItem* tableItemNodeName = new QTableWidgetItem(node->GetName());
m_nodeTable->setItem(i, 0, tableItemNodeName);
m_nodeTable->setItem(aznumeric_caster(i), 0, tableItemNodeName);
// set the row height
m_nodeTable->setRowHeight(i, 21);
m_nodeTable->setRowHeight(aznumeric_caster(i), 21);
}
// resize to contents and adjust header
@ -257,11 +257,9 @@ namespace EMStudio
m_nodeSelectionList.Clear();
if (senderWidget == m_selectNodesButton)
{
MCore::SmallArray<uint16>& nodes = m_nodeGroup->GetNodeArray();
const uint16 numNodes = nodes.GetLength();
for (uint16 i = 0; i < numNodes; ++i)
for (const uint16 i : m_nodeGroup->GetNodeArray())
{
EMotionFX::Node* node = m_actor->GetSkeleton()->GetNode(nodes[i]);
EMotionFX::Node* node = m_actor->GetSkeleton()->GetNode(i);
m_nodeSelectionList.AddNode(node);
}
}

@ -32,9 +32,9 @@ namespace EMStudio
m_nodeCount = actor->GetNumNodes();
// node groups
const uint32 numNodeGroups = actor->GetNumNodeGroups();
const size_t numNodeGroups = actor->GetNumNodeGroups();
m_nodeGroups.reserve(numNodeGroups);
for (uint32 i = 0; i < numNodeGroups; ++i)
for (size_t i = 0; i < numNodeGroups; ++i)
{
m_nodeGroups.emplace_back(actor, actor->GetNodeGroup(i));
}

@ -23,8 +23,8 @@ namespace EMStudio
m_name = nodeGroup->GetNameString();
// iterate over the nodes inside the node group
const uint32 numGroupNodes = nodeGroup->GetNumNodes();
for (uint32 j = 0; j < numGroupNodes; ++j)
const size_t numGroupNodes = nodeGroup->GetNumNodes();
for (size_t j = 0; j < numGroupNodes; ++j)
{
const uint16 nodeIndex = nodeGroup->GetNode(j);
const EMotionFX::Node* node = actor->GetSkeleton()->GetNode(nodeIndex);

@ -1,414 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include "StandardHeaders.h"
#include "MCoreSystem.h"
#include "Algorithms.h"
#include "MemoryManager.h"
namespace MCore
{
/**
* Dynamic array template with a maximum of 65536 items.
* It also doesn't store a memory category and maximum number of elements like the MCore::Array template.
*/
template <class T>
class SmallArray
{
public:
/**
* The memory block ID, used inside the memory manager.
* This will make all arrays remain in the same memory blocks, which is more efficient in a lot of cases.
* However, array data can still remain in other blocks.
*/
enum { MEMORYBLOCK_ID = 2 };
/**
* Default constructor.
* Initializes the array so it's empty and has no memory allocated.
*/
MCORE_INLINE SmallArray() : m_data(nullptr), m_length(0) {}
/**
* Constructor which creates a given number of elements.
* @param elems The element data.
* @param num The number of elements in 'elems'.
*/
MCORE_INLINE explicit SmallArray(T* elems, uint32 num) : m_length(num) { m_data = (T*)MCore::Allocate(m_length * sizeof(T), MCORE_MEMCATEGORY_SMALLARRAY, MEMORYBLOCK_ID, MCORE_FILE, MCORE_LINE); for (uint32 i=0; i<m_length; ++i) Construct(i, elems[i]); }
/**
* Constructor which initializes the length of the array on a given number.
* @param initSize The number of ellements to allocate space for.
*/
MCORE_INLINE explicit SmallArray(uint32 initSize) : m_data(nullptr), m_length(initSize) { if (m_length > 0) { m_data = (T*)MCore::Allocate(m_length * sizeof(T), MCORE_MEMCATEGORY_SMALLARRAY, MEMORYBLOCK_ID, MCORE_FILE, MCORE_LINE); for (uint32 i=0; i<m_length; ++i) Construct(i); } }
/**
* Copy constructor.
* @param other The other array to copy the data from.
*/
SmallArray(const SmallArray<T>& other) : m_data(nullptr), m_length(0) { *this = other; }
/**
* Move constructor.
* @param other The array to move the data from.
*/
SmallArray(SmallArray<T>&& other) { m_data=other.m_data; m_length=other.m_length; other.m_data=nullptr; other.m_length=0; }
/**
* Destructor. Deletes all entry data.
* However, if you store pointers to objects, these objects won't be deleted.<br>
* Example:<br>
* <pre>
* SmallArray< Object* > data;
* for (uint32 i=0; i<10; i++)
* data.Add( new Object() );
* </pre>
* Now when the array 'data' will be destructed, it will NOT free up the memory of the integers which you allocated by hand, using new.
* In order to free up this memory, you can do this:
* <pre>
* for (uint32 i=0; i<data.GetLength(); ++i)
* delete data[i];
* data.Clear();
* </pre>
*/
~SmallArray() { for (uint32 i=0; i<m_length; ++i) Destruct(i); if (m_data) MCore::Free(m_data); }
/**
* Get a pointer to the first element.
* @result A pointer to the first element.
*/
MCORE_INLINE T* GetPtr() { return m_data; }
/**
* Get a given item/element.
* @param pos The item/element number.
* @result A reference to the element.
*/
MCORE_INLINE T& GetItem(uint32 pos) { return m_data[pos]; }
/**
* Get the first element.
* @result A reference to the first element.
*/
MCORE_INLINE T& GetFirst() { return m_data[0]; }
/**
* Get the last element.
* @result A reference to the last element.
*/
MCORE_INLINE T& GetLast() { return m_data[m_length-1]; }
/**
* Get a read-only pointer to the first element.
* @result A read-only pointer to the first element.
*/
MCORE_INLINE const T* GetReadPtr() const { return m_data; }
/**
* Get a read-only reference to a given element number.
* @param pos The element number.
* @result A read-only reference to the given element.
*/
MCORE_INLINE const T& GetItem(uint32 pos) const { return m_data[pos]; }
/**
* Get a read-only reference to the first element.
* @result A read-only reference to the first element.
*/
MCORE_INLINE const T& GetFirst() const { return m_data[0]; }
/**
* Get a read-only reference to the last element.
* @result A read-only reference to the last element.
*/
MCORE_INLINE const T& GetLast() const { return m_data[m_length-1]; }
/**
* Check if the array is empty or not.
* @result Returns true when there are no elements in the array, otherwise false is returned.
*/
MCORE_INLINE bool GetIsEmpty() const { return (m_length == 0); }
/**
* Checks if the passed index is in the array's range.
* @param index The index to check.
* @return True if the passed index is valid, false if not.
*/
MCORE_INLINE bool GetIsValidIndex(uint32 index) const { return (index < m_length); }
/**
* Get the number of elements in the array.
* @result The number of elements in the array.
*/
MCORE_INLINE uint32 GetLength() const { return m_length; }
/**
* Calculates the memory usage used by this array.
* @param includeMembers Include the class members in the calculation? (default=true).
* @result The number of bytes allocated by this array.
*/
MCORE_INLINE uint32 CalcMemoryUsage(bool includeMembers=true) const { uint32 result = m_length*sizeof(T); if (includeMembers) result+=sizeof(MCore::SmallArray<T>); return result; }
/**
* Set a given element to a given value.
* @param pos The element number.
* @param value The value to store at that element number.
*/
MCORE_INLINE void SetElem(uint32 pos, const T& value) { m_data[pos] = value; }
/**
* Add a given element to the back of the array.
* @param x The element to add.
*/
MCORE_INLINE void Add(const T& x) { Grow(++m_length); Construct(m_length-1, x); }
/**
* Add a given array to the back of this array.
* @param a The array to add.
*/
MCORE_INLINE void Add(const SmallArray<T>& a) { uint32 l=m_length; Grow(m_length+a.m_length); for (uint32 i=0; i<a.GetLength(); ++i) Construct(l+i, a[i]); } // TODO: a.GetLength() can be precaled before loop?
/**
* Add an empty (default constructed) element to the back of the array.
*/
MCORE_INLINE void AddEmpty() { Grow(++m_length); Construct(m_length-1); }
/**
* Remove the first array element.
*/
MCORE_INLINE void RemoveFirst() { if (m_length > 0) Remove((uint32)0); }
/**
* Remove the last array element.
*/
MCORE_INLINE void RemoveLast() { if (m_length > 0) Destruct(--m_length); }
/**
* Insert an empty element (default constructed) at a given position in the array.
* @param pos The position to create the empty element.
*/
MCORE_INLINE void Insert(uint32 pos) { Grow(m_length+1); MoveElements(pos+1, pos, m_length-pos-1); Construct(pos); }
/**
* Insert a given element at a given position in the array.
* @param pos The position to insert the empty element.
* @param x The element to store at this position.
*/
MCORE_INLINE void Insert(uint32 pos, const T& x) { Grow(m_length+1); MoveElements(pos+1, pos, m_length-pos-1); Construct(pos, x); }
/**
* Remove an element at a given position.
* @param pos The element number to remove.
*/
MCORE_INLINE void Remove(uint32 pos) { Destruct(pos); MoveElements(pos, pos+1, m_length-pos-1); m_length--; }
/**
* Remove a given number of elements starting at a given position in the array.
* @param pos The start element, so to start removing from.
* @param num The number of elements to remove from this position.
*/
MCORE_INLINE void Remove(uint32 pos, uint32 num) { for (uint32 i=pos; i<pos+num; ++i) Destruct(i); MoveElements(pos, pos+num, m_length-pos-num); m_length-=num; }
/**
* Remove a given element with a given value.
* Only the first element with the given value will be removed.
* @param item The item/element to remove.
*/
MCORE_INLINE bool RemoveByValue(const T& item) { uint32 index = Find(item); if (index==MCORE_INVALIDINDEX32) return false; Remove(index); return true; }
/**
* Remove a given element in the array and place the last element in the array at the created empty position.
* So if we have an array with the following characters : ABCDEFG<br>
* And we perform a SwapRemove(2), we will remove element C and place the last element (G) at the empty created position where C was located.
* So we will get this:<br>
* AB.DEFG [where . is empty, after we did the SwapRemove(2)]<br>
* ABGDEF [this is the result. G has been moved to the empty position].
*/
MCORE_INLINE void SwapRemove(uint32 pos) { Destruct(pos); if (pos != m_length-1) { Construct(pos, m_data[m_length-1]); Destruct(m_length-1); } m_length--; } // remove element at <pos> and place the last element of the array in that position
/**
* Swap two elements.
* @param pos1 The first element number.
* @param pos2 The second element number.
*/
MCORE_INLINE void Swap(uint32 pos1, uint32 pos2) { if (pos1 != pos2) MCore::Swap(GetItem(pos1), GetItem(pos2)); }
/**
* Clear the array contents. So GetLength() will return 0 after performing this method.
* @param clearMem If set to true (default) the allocated memory will also be released. If set to false, GetMaxLength() will still return the number of elements
* which the array contained before calling the Clear() method.
*/
MCORE_INLINE void Clear(bool clearMem=true) { for (uint32 i=0; i<m_length; ++i) Destruct(i); m_length=0; if (clearMem) Free(); }
/**
* Make sure the array has enough space to store a given number of elements.
* @param newLength The number of elements we want to make sure that will fit in the array.
*/
MCORE_INLINE void AssureSize(uint32 newLength) { if (m_length >= newLength) return; uint32 oldLen=m_length; Grow(newLength); for (uint32 i=oldLen; i<newLength; ++i) Construct(i); }
/**
* Make sure this array has enough allocated storage to grow to a given number of elements elements without having to realloc.
* @param minLength The minimum length the array should have.
*/
MCORE_INLINE void Reserve(uint32 minLength) { if (m_length < minLength) Realloc(minLength); }
/**
* Check if the array contains a given element.
* @param x The element to check.
* @result Returns true when the array contains the element, otherwise false is returned.
*/
MCORE_INLINE bool Contains(const T& x) const { return (Find(x) != MCORE_INVALIDINDEX32); }
/**
* Find the position of a given element.
* @param x The element to find.
* @result Returns the index in the array, ranging from [0 to GetLength()-1] when found, otherwise MCORE_INVALIDINDEX32 is returned.
*/
MCORE_INLINE uint32 Find(const T& x) const { for (uint32 i=0; i<m_length; ++i) { if (m_data[i] == x) return i; } return MCORE_INVALIDINDEX32; }
// sort function and standard sort function
typedef int32 (MCORE_CDECL *CmpFunc)(const T& itemA, const T& itemB);
static int32 MCORE_CDECL StdCmp(const T& itemA, const T& itemB) { if (itemA < itemB) return -1; else if (itemA == itemB) return 0; else return 1; }
static int32 MCORE_CDECL StdPtrObjCmp(const T& itemA, const T& itemB) { if (*itemA < *itemB) return -1; else if (*itemA == *itemB) return 0; else return 1; }
/**
* Sort the complete array using a given sort function.
* @param cmp The sort function to use.
*/
MCORE_INLINE void Sort(CmpFunc cmp) { InnerSort(0, m_length-1, cmp); }
/**
* Sort a given part of the array using a given sort function.
* The default parameters are set so that it will sort the complete array with a default compare function (which uses the < and > operators).
* The method will sort all elements between the given 'first' and 'last' element (first and last are also included in the sort).
* @param first The first element to start sorting.
* @param last The last element to sort (when set to MCORE_INVALIDINDEX32, GetLength()-1 will be used).
* @param cmp The compare function.
*/
MCORE_INLINE void Sort(uint32 first=0, uint32 last=MCORE_INVALIDINDEX32, CmpFunc cmp=StdCmp) { if (last==MCORE_INVALIDINDEX32) last=m_length-1; InnerSort(first, last, cmp); }
/**
* Performs a sort on a given part of the array.
* @param first The first element to start the sorting at.
* @param last The last element to end the sorting.
* @param cmp The compare function.
*/
MCORE_INLINE void InnerSort(int32 first, int32 last, CmpFunc cmp) { if (first >= last) return; int32 split=Partition(first, last, cmp); InnerSort(first, split-1, cmp); InnerSort(split+1, last, cmp); }
/**
* Resize the array to a given size.
* This does not mean an actual realloc will be made. This will only happen when the new length is bigger than the maxLength of the array.
* @param newLength The new length the array should be.
* @result returns false if the allocation/reallocation of the array failed
*/
bool Resize(uint32 newLength)
{
// check for growing or shrinking array
if (newLength > m_length)
{
// growing array, construct empty elements at end of array
uint32 oldLen = m_length;
GrowExact(newLength);
if (m_data == nullptr)
{
return false;
}
for (uint32 i=oldLen; i<newLength; ++i)
Construct(i);
}
else
{
// shrinking array, destruct elements at end of array
for (uint32 i=newLength; i<m_length; ++i)
Destruct(i);
m_length = newLength;
}
return true;
}
/**
* Move "numElements" elements starting from the source index, to the dest index.
* Please note thate the array has to be large enough. You can't move data past the end of the array.
* @param destIndex The destination index.
* @param sourceIndex The source index, where the source elements start.
* @param numElements The number of elements to move.
*/
MCORE_INLINE void MoveElements(uint32 destIndex, uint32 sourceIndex, uint32 numElements)
{
if (numElements > 0)
MCore::MemMove(m_data+destIndex, m_data+sourceIndex, numElements * sizeof(T));
}
// operators
bool operator==(const SmallArray<T>& other) const { if (m_length != other.m_length) return false; for (uint32 i=0; i<m_length; ++i) if (m_data[i] != other.m_data[i]) return false; return true; }
SmallArray<T>& operator= (const SmallArray<T>& other) { if (&other != this) { Clear(); Grow(other.m_length); for (uint32 i=0; i<m_length; ++i) Construct(i, other.m_data[i]); } return *this; }
SmallArray<T>& operator= (SmallArray<T>&& other) { MCORE_ASSERT(&other != this); if (m_data!=nullptr) MCore::Free(m_data); m_data=other.m_data; m_length=other.m_length; other.m_data=nullptr; other.m_length=0; return *this; }
SmallArray<T>& operator+=(const T& other) { Add(other); return *this; }
SmallArray<T>& operator+=(const SmallArray<T>& other) { Add(other); return *this; }
MCORE_INLINE T& operator[](const uint32 index) { MCORE_ASSERT(index<m_length); return m_data[index]; } // TODO: add safety assert to make sure the index is valid?
MCORE_INLINE const T& operator[](const uint32 index) const { MCORE_ASSERT(index<m_length); return m_data[index]; }
private:
T* m_data; /**< The element data. */
uint32 m_length; /**< The number of used elements in the array. */
// private functions
MCORE_INLINE void Grow(uint32 newLength) { m_length = newLength; Realloc( newLength ); }
MCORE_INLINE void GrowExact(uint32 newLength) { m_length = newLength; Realloc( newLength ); }
MCORE_INLINE uint32 AllocSize(uint32 num) { return num; }
MCORE_INLINE void Alloc(uint32 num) { m_data = (T*)MCore::Allocate(num * sizeof(T), MCORE_MEMCATEGORY_SMALLARRAY, MEMORYBLOCK_ID, MCORE_FILE, MCORE_LINE); }
MCORE_INLINE void Realloc(uint32 newSize)
{
if (newSize == 0) { this->Free(); return; }
if (m_data)
m_data = (T*)MCore::Realloc(m_data, newSize * sizeof(T), MCORE_MEMCATEGORY_SMALLARRAY, MEMORYBLOCK_ID, MCORE_FILE, MCORE_LINE);
else
m_data = (T*)MCore::Allocate(newSize * sizeof(T), MCORE_MEMCATEGORY_SMALLARRAY, MEMORYBLOCK_ID, MCORE_FILE, MCORE_LINE);
}
MCORE_INLINE void Free() { m_length=0; if (m_data) MCore::Free(m_data); m_data=nullptr; }
MCORE_INLINE void Construct(uint32 index, const T& original) { ::new(m_data+index) T(original); } // copy-construct an element at <index> which is a copy of <original>
MCORE_INLINE void Construct(uint32 index) { ::new(m_data+index) T; } // construct an element at place <index>
MCORE_INLINE void Destruct(uint32 index)
{
#if (MCORE_COMPILER == MCORE_COMPILER_MSVC) // work around a compiler bug, marking this index parameter as unused
MCORE_UNUSED(index);
#endif
(m_data+index)->~T();
} // destruct an element at <index>
// partition part of array (for sorting)
int32 Partition(int32 left, int32 right, CmpFunc cmp)
{
::MCore::Swap(m_data[left], m_data[ (left+right)>>1 ]);
T& target = m_data[right];
int32 i = left-1;
int32 j = right;
bool neverQuit = true; // workaround to disable a "warning C4127: conditional expression is constant"
while (neverQuit)
{
while (i < j) { if (cmp(m_data[++i], target) >= 0) break; }
while (j > i) { if (cmp(m_data[--j], target) <= 0) break; }
if (i >= j) break;
::MCore::Swap(m_data[i], m_data[j]);
}
::MCore::Swap(m_data[i], m_data[right]);
return i;
}
};
} // namespace MCore

@ -106,7 +106,6 @@ set(FILES
Source/StaticAllocator.cpp
Source/StaticAllocator.h
Source/StaticString.h
Source/SmallArray.h
Source/StandardHeaders.h
Source/Stream.h
Source/StringConversions.cpp

Loading…
Cancel
Save