From 4825450d01abd63ae86e653f01d919c00641d55a Mon Sep 17 00:00:00 2001 From: bottledlactose <195167582+bottledlactose@users.noreply.github.com> Date: Sun, 16 Feb 2025 17:21:21 +0100 Subject: [PATCH 01/30] Add initial CharacterDef reading (wip for Mikey) --- CMakeLists.txt | 15 +++++++++++- src/formats/CharacterDef.cpp | 26 ++++++++++++++++++++ src/formats/CharacterDef.h | 42 ++++++++++++++++++++++++++++++++ src/formats/primitives/Vector2.h | 9 +++++++ src/formats/primitives/Vector3.h | 10 ++++++++ src/formats/primitives/Vector4.h | 11 +++++++++ tests/serialization.cpp | 11 +++++++++ 7 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 src/formats/CharacterDef.cpp create mode 100644 src/formats/CharacterDef.h create mode 100644 src/formats/primitives/Vector2.h create mode 100644 src/formats/primitives/Vector3.h create mode 100644 src/formats/primitives/Vector4.h create mode 100644 tests/serialization.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d5d51b..710bd35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,8 @@ project(MySimsModLoader) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) +option(BUILD_TESTS "Build tests" ON) + # Disable sigmatch tests to speed up compilation set(SIGMATCH_BUILD_TESTS OFF CACHE BOOL "Disable sigmatch tests" FORCE) @@ -37,6 +39,9 @@ add_library(MySimsModLoader SHARED src/Main.cpp src/util/FNV.h src/signatures/lua.h src/signatures/sigdef.h + # Format + src/formats/CharacterDef.h + src/formats/CharacterDef.cpp ) add_custom_target(version @@ -54,4 +59,12 @@ target_include_directories(MySimsModLoader PRIVATE libs/sigmatch/include) target_link_libraries(MySimsModLoader PRIVATE minhook) target_link_libraries(MySimsModLoader PRIVATE pugixml-static) -set_target_properties(MySimsModLoader PROPERTIES OUTPUT_NAME "dsound") \ No newline at end of file +set_target_properties(MySimsModLoader PROPERTIES OUTPUT_NAME "dsound") + +if (BUILD_TESTS) + add_executable(Tests tests/serialization.cpp + src/formats/CharacterDef.cpp) + target_include_directories(Tests PRIVATE libs/pugixml/src) + target_include_directories(Tests PRIVATE src) + target_link_libraries(Tests PRIVATE pugixml-static) +endif() diff --git a/src/formats/CharacterDef.cpp b/src/formats/CharacterDef.cpp new file mode 100644 index 0000000..1c28b74 --- /dev/null +++ b/src/formats/CharacterDef.cpp @@ -0,0 +1,26 @@ +#include "CharacterDef.h" + +#include "pugixml.hpp" +#include + +void CharacterDef::Read(CharacterDef &instance, const std::string &path) { + + pugi::xml_document doc; + pugi::xml_parse_result result = doc.load_file(path.c_str()); + + // TODO: Add error handling + + instance.Script = doc.child("CharacterDef").child("Script").text().as_string(); + instance.BodyModel = doc.child("CharacterDef").child("BodyModel").text().as_string(); + instance.BodyDM = doc.child("CharacterDef").child("BodyDM").text().as_string(); + instance.HeadModel = doc.child("CharacterDef").child("HeadModel").text().as_string(); + instance.HairIndex = doc.child("CharacterDef").child("HairIndex").text().as_int(); + instance.HatIndex = doc.child("CharacterDef").child("HatIndex").text().as_int(); + instance.EyesModel = doc.child("CharacterDef").child("EyesModel").text().as_string(); + instance.MouthModel = doc.child("CharacterDef").child("MouthModel").text().as_string(); + instance.SkinToneIndex = doc.child("CharacterDef").child("SkinToneIndex").text().as_int(); + instance.MiscOpIndex = doc.child("CharacterDef").child("MiscOpIndex").text().as_int(); + instance.MiscModIndex = doc.child("CharacterDef").child("MiscModIndex").text().as_int(); + + // TODO: Import the rest of the fields +} diff --git a/src/formats/CharacterDef.h b/src/formats/CharacterDef.h new file mode 100644 index 0000000..68155f6 --- /dev/null +++ b/src/formats/CharacterDef.h @@ -0,0 +1,42 @@ +#ifndef CHARACTERDEF_H +#define CHARACTERDEF_H + +#include +#include +#include + +struct LuaData {}; + +struct Interest { + std::string Type; + int Value; +}; + +struct Influences { + std::vector Interests; +}; + +struct CharacterDef { + std::string Script; + std::string BodyModel; + std::string BodyDM; + std::string HeadModel; + int HairIndex; + int HatIndex; + std::string EyesModel; + std::string MouthModel; + int SkinToneIndex; + int MiscOpIndex; + int MiscModIndex; + std::string VoxGroup; + double PitchAdjustment; + std::string Rig; + std::string CollisionInfo; + std::unordered_map Clips; + LuaData LuaData; + Influences Influences; + + static void Read(CharacterDef &instance, const std::string &path); +}; + +#endif // CHARACTERDEF_H diff --git a/src/formats/primitives/Vector2.h b/src/formats/primitives/Vector2.h new file mode 100644 index 0000000..c95feff --- /dev/null +++ b/src/formats/primitives/Vector2.h @@ -0,0 +1,9 @@ +#ifndef VECTOR2_H +#define VECTOR2_H + +struct Vector2 { + float x; + float y; +}; + +#endif // VECTOR2_H diff --git a/src/formats/primitives/Vector3.h b/src/formats/primitives/Vector3.h new file mode 100644 index 0000000..ae05418 --- /dev/null +++ b/src/formats/primitives/Vector3.h @@ -0,0 +1,10 @@ +#ifndef VECTOR3_H +#define VECTOR3_H + +struct Vector3 { + float x; + float y; + float z; +}; + +#endif // VECTOR3_H diff --git a/src/formats/primitives/Vector4.h b/src/formats/primitives/Vector4.h new file mode 100644 index 0000000..5460529 --- /dev/null +++ b/src/formats/primitives/Vector4.h @@ -0,0 +1,11 @@ +#ifndef VECTOR4_H +#define VECTOR4_H + +struct Vector4 { + float x; + float y; + float z; + float w; +}; + +#endif // VECTOR4_H diff --git a/tests/serialization.cpp b/tests/serialization.cpp new file mode 100644 index 0000000..953320d --- /dev/null +++ b/tests/serialization.cpp @@ -0,0 +1,11 @@ +#include + +#include "formats/CharacterDef.h" + +int main() { + // Just testing for now... + // TODO: Find a better way to test this + CharacterDef characterDef; + CharacterDef::Read(characterDef, "C:\\Users\\User\\Downloads\\CharacterDef.xml"); + return 0; +} From 49a4507164266e418e8fd0e0a073ad3d964a8dc8 Mon Sep 17 00:00:00 2001 From: bottledlactose <195167582+bottledlactose@users.noreply.github.com> Date: Sun, 16 Feb 2025 18:49:54 +0100 Subject: [PATCH 02/30] Change file path to void* --- src/formats/CharacterDef.cpp | 4 ++-- src/formats/CharacterDef.h | 2 +- tests/serialization.cpp | 24 ++++++++++++++++++++++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/formats/CharacterDef.cpp b/src/formats/CharacterDef.cpp index 1c28b74..37d42ed 100644 --- a/src/formats/CharacterDef.cpp +++ b/src/formats/CharacterDef.cpp @@ -3,10 +3,10 @@ #include "pugixml.hpp" #include -void CharacterDef::Read(CharacterDef &instance, const std::string &path) { +void CharacterDef::Read(CharacterDef &instance, void *data, size_t size) { pugi::xml_document doc; - pugi::xml_parse_result result = doc.load_file(path.c_str()); + pugi::xml_parse_result result = doc.load_string(static_cast(data), size); // TODO: Add error handling diff --git a/src/formats/CharacterDef.h b/src/formats/CharacterDef.h index 68155f6..2573385 100644 --- a/src/formats/CharacterDef.h +++ b/src/formats/CharacterDef.h @@ -36,7 +36,7 @@ struct CharacterDef { LuaData LuaData; Influences Influences; - static void Read(CharacterDef &instance, const std::string &path); + static void Read(CharacterDef &instance, void *data, size_t size); }; #endif // CHARACTERDEF_H diff --git a/tests/serialization.cpp b/tests/serialization.cpp index 953320d..c8da33f 100644 --- a/tests/serialization.cpp +++ b/tests/serialization.cpp @@ -1,11 +1,31 @@ #include +#include #include "formats/CharacterDef.h" int main() { // Just testing for now... - // TODO: Find a better way to test this + // TODO: Start using Gtest for unit tests like this + + std::ifstream file("C:\\Users\\User\\Downloads\\CharacterDef.xml"); + if (!file.is_open()) { + std::cerr << "Failed to open file" << std::endl; + return 1; + } + + void *buffer = nullptr; + size_t size = 0; + + file.seekg(0, std::ios::end); + size = file.tellg(); + file.seekg(0, std::ios::beg); + + buffer = new char[size]; + file.read(static_cast(buffer), size); + + // Read the data into a CharacterDef instance CharacterDef characterDef; - CharacterDef::Read(characterDef, "C:\\Users\\User\\Downloads\\CharacterDef.xml"); + CharacterDef::Read(characterDef, buffer, size); + return 0; } From d9f9b5da5419a25197ccbd2c8d2972c5226a9717 Mon Sep 17 00:00:00 2001 From: bottledlactose <195167582+bottledlactose@users.noreply.github.com> Date: Sun, 16 Feb 2025 19:13:46 +0100 Subject: [PATCH 03/30] Set up Google Test --- .gitmodules | 3 +++ CMakeLists.txt | 17 +++++++++++++++-- libs/googletest | 1 + tests/Test.cpp | 9 +++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) create mode 160000 libs/googletest create mode 100644 tests/Test.cpp diff --git a/.gitmodules b/.gitmodules index c070a53..5c60a1d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "libs/pugixml"] path = libs/pugixml url = https://github.com/zeux/pugixml.git +[submodule "libs/googletest"] + path = libs/googletest + url = https://github.com/google/googletest.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 710bd35..3e1d4b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,9 +62,22 @@ target_link_libraries(MySimsModLoader PRIVATE pugixml-static) set_target_properties(MySimsModLoader PROPERTIES OUTPUT_NAME "dsound") if (BUILD_TESTS) - add_executable(Tests tests/serialization.cpp + # For Windows: Prevent overriding the parent project's compiler/linker settings + # As per documentation: http://google.github.io/googletest/quickstart-cmake.html + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + add_subdirectory(libs/googletest) + + enable_testing() + + add_executable(Tests + tests/Test.cpp src/formats/CharacterDef.cpp) + target_include_directories(Tests PRIVATE libs/pugixml/src) target_include_directories(Tests PRIVATE src) - target_link_libraries(Tests PRIVATE pugixml-static) + + target_link_libraries(Tests PRIVATE GTest::gtest_main pugixml-static) + + include(GoogleTest) + gtest_discover_tests(Tests) endif() diff --git a/libs/googletest b/libs/googletest new file mode 160000 index 0000000..6910c9d --- /dev/null +++ b/libs/googletest @@ -0,0 +1 @@ +Subproject commit 6910c9d9165801d8827d628cb72eb7ea9dd538c5 diff --git a/tests/Test.cpp b/tests/Test.cpp new file mode 100644 index 0000000..3508766 --- /dev/null +++ b/tests/Test.cpp @@ -0,0 +1,9 @@ +#include + +// Demonstrate some basic assertions. +TEST(HelloTest, BasicAssertions) { + // Expect two strings not to be equal. + EXPECT_STRNE("hello", "world"); + // Expect equality. + EXPECT_EQ(7 * 6, 42); +} From 457fed0f601aee4945245c46ecc95d52ed30e05b Mon Sep 17 00:00:00 2001 From: bottledlactose <195167582+bottledlactose@users.noreply.github.com> Date: Sun, 16 Feb 2025 19:32:41 +0100 Subject: [PATCH 04/30] Add CharacterDef unit test --- CMakeLists.txt | 5 ++- tests/CharacterDefTest.cpp | 85 ++++++++++++++++++++++++++++++++++++++ tests/Test.cpp | 9 ---- tests/serialization.cpp | 31 -------------- 4 files changed, 89 insertions(+), 41 deletions(-) create mode 100644 tests/CharacterDefTest.cpp delete mode 100644 tests/Test.cpp delete mode 100644 tests/serialization.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e1d4b9..a7fc5c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,7 +70,10 @@ if (BUILD_TESTS) enable_testing() add_executable(Tests - tests/Test.cpp + # Tests + tests/CharacterDefTest.cpp + # Format + src/formats/CharacterDef.h src/formats/CharacterDef.cpp) target_include_directories(Tests PRIVATE libs/pugixml/src) diff --git a/tests/CharacterDefTest.cpp b/tests/CharacterDefTest.cpp new file mode 100644 index 0000000..9d0ceca --- /dev/null +++ b/tests/CharacterDefTest.cpp @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include "formats/CharacterDef.h" + +// Mock XML data (simulating CharacterDef.xml) +const std::string MockCharacterDef = R"( + + + + amBodyMock + _white + amHeadHatMock + 0 + 0 + amEyesMock + amMouthMock + 0 + 0 + 0 + F + 0.85 + skeleton-rig + 0 1 0 0.5 2 0.5 + + a-idle-thighSlap + a-idle-wave + + + + + + 5 + -1 + 2 + + +)"; + +// Test case for CharacterDef file reading +TEST(CharacterDefTest, ReadFromStream) { + // Simulating file input using istringstream + std::istringstream file(MockCharacterDef); + + // Ensure stream is valid + ASSERT_TRUE(file.good()) << "Mock file stream failed to open"; + + void *buffer = nullptr; + size_t size = 0; + + // Get size of mock data + file.seekg(0, std::ios::end); + size = static_cast(file.tellg()); + file.seekg(0, std::ios::beg); + + // Allocate memory + buffer = new char[size]; + file.read(static_cast(buffer), size); + + // Ensure the data is read correctly + ASSERT_EQ(file.gcount(), static_cast(size)) << "File read size mismatch"; + + // Create CharacterDef instance and call Read method + CharacterDef characterDef; + CharacterDef::Read(characterDef, buffer, size); + + // Validate that CharacterDef correctly parsed the data (assuming GetName() method exists) + EXPECT_EQ(characterDef.Script, "NPC_Mock"); + EXPECT_EQ(characterDef.BodyModel, "amBodyMock"); + EXPECT_EQ(characterDef.BodyDM, "_white"); + EXPECT_EQ(characterDef.HeadModel, "amHeadHatMock"); + EXPECT_EQ(characterDef.HairIndex, 0); + EXPECT_EQ(characterDef.HatIndex, 0); + EXPECT_EQ(characterDef.EyesModel, "amEyesMock"); + EXPECT_EQ(characterDef.MouthModel, "amMouthMock"); + EXPECT_EQ(characterDef.SkinToneIndex, 0); + EXPECT_EQ(characterDef.MiscOpIndex, 0); + EXPECT_EQ(characterDef.MiscModIndex, 0); + + // TODO: Add missing fields here + + // Cleanup allocated memory + delete[] static_cast(buffer); +} diff --git a/tests/Test.cpp b/tests/Test.cpp deleted file mode 100644 index 3508766..0000000 --- a/tests/Test.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -// Demonstrate some basic assertions. -TEST(HelloTest, BasicAssertions) { - // Expect two strings not to be equal. - EXPECT_STRNE("hello", "world"); - // Expect equality. - EXPECT_EQ(7 * 6, 42); -} diff --git a/tests/serialization.cpp b/tests/serialization.cpp deleted file mode 100644 index c8da33f..0000000 --- a/tests/serialization.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -#include "formats/CharacterDef.h" - -int main() { - // Just testing for now... - // TODO: Start using Gtest for unit tests like this - - std::ifstream file("C:\\Users\\User\\Downloads\\CharacterDef.xml"); - if (!file.is_open()) { - std::cerr << "Failed to open file" << std::endl; - return 1; - } - - void *buffer = nullptr; - size_t size = 0; - - file.seekg(0, std::ios::end); - size = file.tellg(); - file.seekg(0, std::ios::beg); - - buffer = new char[size]; - file.read(static_cast(buffer), size); - - // Read the data into a CharacterDef instance - CharacterDef characterDef; - CharacterDef::Read(characterDef, buffer, size); - - return 0; -} From 17f07df7fd9843e796b15abea15ba767eb3ca2fb Mon Sep 17 00:00:00 2001 From: bottledlactose <195167582+bottledlactose@users.noreply.github.com> Date: Sun, 16 Feb 2025 19:50:44 +0100 Subject: [PATCH 05/30] Finish CharacterDef serialization --- src/formats/CharacterDef.cpp | 17 ++++++++++++++++- tests/CharacterDefTest.cpp | 20 ++++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/formats/CharacterDef.cpp b/src/formats/CharacterDef.cpp index 37d42ed..8aa6139 100644 --- a/src/formats/CharacterDef.cpp +++ b/src/formats/CharacterDef.cpp @@ -21,6 +21,21 @@ void CharacterDef::Read(CharacterDef &instance, void *data, size_t size) { instance.SkinToneIndex = doc.child("CharacterDef").child("SkinToneIndex").text().as_int(); instance.MiscOpIndex = doc.child("CharacterDef").child("MiscOpIndex").text().as_int(); instance.MiscModIndex = doc.child("CharacterDef").child("MiscModIndex").text().as_int(); + instance.VoxGroup = doc.child("CharacterDef").child("VoxGroup").text().as_string(); + instance.PitchAdjustment = doc.child("CharacterDef").child("PitchAdjustment").text().as_double(); + instance.Rig = doc.child("CharacterDef").child("Rig").text().as_string(); + instance.CollisionInfo = doc.child("CharacterDef").child("CollisionInfo").text().as_string(); - // TODO: Import the rest of the fields + // Read clips + for (pugi::xml_node clip : doc.child("CharacterDef").child("Clips").children()) { + instance.Clips[clip.name()] = clip.text().as_string(); + } + + // Read influences + for (pugi::xml_node interest : doc.child("CharacterDef").child("Influences").children()) { + instance.Influences.Interests.push_back(Interest{ + interest.attribute("type").as_string(), + interest.text().as_int() + }); + } } diff --git a/tests/CharacterDefTest.cpp b/tests/CharacterDefTest.cpp index 9d0ceca..e50756d 100644 --- a/tests/CharacterDefTest.cpp +++ b/tests/CharacterDefTest.cpp @@ -77,9 +77,25 @@ TEST(CharacterDefTest, ReadFromStream) { EXPECT_EQ(characterDef.SkinToneIndex, 0); EXPECT_EQ(characterDef.MiscOpIndex, 0); EXPECT_EQ(characterDef.MiscModIndex, 0); + EXPECT_EQ(characterDef.VoxGroup, "F"); + EXPECT_DOUBLE_EQ(characterDef.PitchAdjustment, 0.85); + EXPECT_EQ(characterDef.Rig, "skeleton-rig"); + EXPECT_EQ(characterDef.CollisionInfo, "0 1 0 0.5 2 0.5"); + + // Validate Clips + EXPECT_EQ(characterDef.Clips.size(), 2); + EXPECT_EQ(characterDef.Clips.at("eIDLE2"), "a-idle-thighSlap"); + EXPECT_EQ(characterDef.Clips.at("eIDLE3"), "a-idle-wave"); + + // Validate Influences + EXPECT_EQ(characterDef.Influences.Interests.size(), 3); + EXPECT_EQ(characterDef.Influences.Interests[0].Type, "Food"); + EXPECT_EQ(characterDef.Influences.Interests[0].Value, 5); + EXPECT_EQ(characterDef.Influences.Interests[1].Type, "SciFi"); + EXPECT_EQ(characterDef.Influences.Interests[1].Value, -1); + EXPECT_EQ(characterDef.Influences.Interests[2].Type, "Fun"); + EXPECT_EQ(characterDef.Influences.Interests[2].Value, 2); - // TODO: Add missing fields here - // Cleanup allocated memory delete[] static_cast(buffer); } From 86f8c70d5346e293ba77d64f9005071c317002cc Mon Sep 17 00:00:00 2001 From: MikeyLORR Date: Sun, 16 Feb 2025 14:01:51 -0500 Subject: [PATCH 06/30] Added ObjectDef --- src/formats/ObjectDef.cpp | 24 ++++++++++++++++++++++++ src/formats/ObjectDef.h | 21 +++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/formats/ObjectDef.cpp create mode 100644 src/formats/ObjectDef.h diff --git a/src/formats/ObjectDef.cpp b/src/formats/ObjectDef.cpp new file mode 100644 index 0000000..911f654 --- /dev/null +++ b/src/formats/ObjectDef.cpp @@ -0,0 +1,24 @@ +#include "ObjectDef.h" + +#include "pugixml.hpp" +#include + +void ObjectDef::Read(ObjectDef &instance, void *data, size_t size) { + + pugi::xml_document doc; + pugi::xml_parse_result result = doc.load_string(static_cast(data), size); + + /*std::string Model; + std::string Rig; + std::string Script; + std::string MaxAttachments; + std::string CollisionInfo; + bool NoFootPrint;*/ + instance.Model = doc.child("ObjectDef").child("Model").text().as_string(); + instance.Rig = doc.child("ObjectDef").child("Rig").text().as_string(); + instance.Script = doc.child("ObjectDef").child("Script").text().as_string(); + instance.MaxAttachments = doc.child("ObjectDef").child("MaxAttachments").text().as_string(); + instance.CollisionInfo = doc.child("ObjectDef").child("CollisionInfo").text().as_string(); + instance.NoFootPrint = doc.child("ObjectDef").child("NoFootPrint").text().as_bool(); +} + diff --git a/src/formats/ObjectDef.h b/src/formats/ObjectDef.h new file mode 100644 index 0000000..0c1b089 --- /dev/null +++ b/src/formats/ObjectDef.h @@ -0,0 +1,21 @@ +#ifndef OBJECTDEF_H +#define OBJECTDEF_H + +#include +#include +#include + +struct ObjectDef { + + std::string Model; + std::string Rig; + std::string Script; + std::string MaxAttachments; + std::string CollisionInfo; + bool NoFootPrint; + + static void Read(ObjectDef &instance, void *data, size_t size); + +}; + +#endif // OBJECTDEF_H \ No newline at end of file From b4a72a6e047100e938378b4f4591753a24e13da9 Mon Sep 17 00:00:00 2001 From: MikeyLORR Date: Sun, 16 Feb 2025 15:37:24 -0500 Subject: [PATCH 07/30] Added ObjectDefTest (INCOMPLETE), cleaned up ObjectDef --- src/formats/ObjectDef.cpp | 6 --- tests/ObjectDefTest.cpp | 93 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 tests/ObjectDefTest.cpp diff --git a/src/formats/ObjectDef.cpp b/src/formats/ObjectDef.cpp index 911f654..1cf3713 100644 --- a/src/formats/ObjectDef.cpp +++ b/src/formats/ObjectDef.cpp @@ -8,12 +8,6 @@ void ObjectDef::Read(ObjectDef &instance, void *data, size_t size) { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_string(static_cast(data), size); - /*std::string Model; - std::string Rig; - std::string Script; - std::string MaxAttachments; - std::string CollisionInfo; - bool NoFootPrint;*/ instance.Model = doc.child("ObjectDef").child("Model").text().as_string(); instance.Rig = doc.child("ObjectDef").child("Rig").text().as_string(); instance.Script = doc.child("ObjectDef").child("Script").text().as_string(); diff --git a/tests/ObjectDefTest.cpp b/tests/ObjectDefTest.cpp new file mode 100644 index 0000000..9a51589 --- /dev/null +++ b/tests/ObjectDefTest.cpp @@ -0,0 +1,93 @@ +//INCOMPLETE + +#include +#include +#include +#include +#include "formats/ObjectDef.h" + +// Mock XML data (simulating ObjectDef.xml) +const std::string MockObjectDef = R"( + + flairSymbolMock + essenceSymbolRig-rig + + 2 + 1 + 0 + 2.0f + 0 + + + Mock + flairMock + matSetMock + 1 + uitexture-essence-flair-mock + uitexture-essence-paint-mock + + + 1.428 + + +)"; + + +// Test case for ObjectDef file reading +TEST(ObjectDefTest, ReadFromStream) { + // Simulating file input using istringstream + std::istringstream file(MockObjectDef); + + // Ensure stream is valid + ASSERT_TRUE(file.good()) << "Mock file stream failed to open"; + + void *buffer = nullptr; + size_t size = 0; + + // Get size of mock data + file.seekg(0, std::ios::end); + size = static_cast(file.tellg()); + file.seekg(0, std::ios::beg); + + // Allocate memory + buffer = new char[size]; + file.read(static_cast(buffer), size); + + // Ensure the data is read correctly + ASSERT_EQ(file.gcount(), static_cast(size)) << "File read size mismatch"; + + // Create ObjectDef instance and call Read method + ObjectDef objectDef; + ObjectDef::Read(objectDef, buffer, size); + + // Validate that CharacterDef correctly parsed the data (assuming GetName() method exists) + EXPECT_EQ(objectDef.Model, "flairSymbolMock"); + EXPECT_EQ(objectDef.Rig, "essenceSymbolRig-rig"); + EXPECT_EQ(objectDef.Script, "Essence"); + //EXPECT_EQ(objectDef.HavokInfo, "2"); + EXPECT_EQ(objectDef.NoFootPrint, "1"); + //EXPECT_EQ(objectDef.RotateByHavok, "0"); + //EXPECT_EQ(objectDef.HavokLinearDamping, "2.0f"); + //EXPECT_EQ(objectDef.Shadow, "0"); + + //Commented lines do not exist in original file format? + +/* + + // Validate Clips + EXPECT_EQ(characterDef.Clips.size(), 2); + EXPECT_EQ(characterDef.Clips.at("eIDLE2"), "a-idle-thighSlap"); + EXPECT_EQ(characterDef.Clips.at("eIDLE3"), "a-idle-wave"); + + // Validate Influences + EXPECT_EQ(characterDef.Influences.Interests.size(), 3); + EXPECT_EQ(characterDef.Influences.Interests[0].Type, "Food"); + EXPECT_EQ(characterDef.Influences.Interests[0].Value, 5); + EXPECT_EQ(characterDef.Influences.Interests[1].Type, "SciFi"); + EXPECT_EQ(characterDef.Influences.Interests[1].Value, -1); + EXPECT_EQ(characterDef.Influences.Interests[2].Type, "Fun"); + EXPECT_EQ(characterDef.Influences.Interests[2].Value, 2);*/ + + // Cleanup allocated memory + delete[] static_cast(buffer); +} \ No newline at end of file From a2551207dd2493eacb565f7754f2236209b7f690 Mon Sep 17 00:00:00 2001 From: bottledlactose <195167582+bottledlactose@users.noreply.github.com> Date: Sun, 16 Feb 2025 21:45:09 +0100 Subject: [PATCH 08/30] Add World and related structs --- CMakeLists.txt | 2 ++ src/formats/GameObjectDef.h | 17 ++++++++++ src/formats/GameObjectListHolder.h | 11 +++++++ src/formats/World.cpp | 6 ++++ src/formats/World.h | 51 ++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+) create mode 100644 src/formats/GameObjectDef.h create mode 100644 src/formats/GameObjectListHolder.h create mode 100644 src/formats/World.cpp create mode 100644 src/formats/World.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a7fc5c9..f445f32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,8 @@ add_library(MySimsModLoader SHARED src/Main.cpp # Format src/formats/CharacterDef.h src/formats/CharacterDef.cpp + src/formats/World.h + src/formats/World.cpp ) add_custom_target(version diff --git a/src/formats/GameObjectDef.h b/src/formats/GameObjectDef.h new file mode 100644 index 0000000..cc5eb37 --- /dev/null +++ b/src/formats/GameObjectDef.h @@ -0,0 +1,17 @@ +#ifndef GAMEOBJECTDEF_H +#define GAMEOBJECTDEF_H + +#include + +struct GameObjectDef { + std::string Script; + std::string Translation; + std::string Rotation; + std::string ObjectDef; + std::vector Children; + std::string Guid; + // std::string LuaTable; // TODO: Is an XMLElement in Core + std::string Name; +}; + +#endif // GAMEOBJECTDEF_H diff --git a/src/formats/GameObjectListHolder.h b/src/formats/GameObjectListHolder.h new file mode 100644 index 0000000..1c76433 --- /dev/null +++ b/src/formats/GameObjectListHolder.h @@ -0,0 +1,11 @@ +#ifndef GAMEOBJECTLISTHOLDER_H +#define GAMEOBJECTLISTHOLDER_H + +#include +#include "GameObjectDef.h" + +struct GameObjectListHolder { + std::vector GameObjects; +}; + +#endif // GAMEOBJECTLISTHOLDER_H diff --git a/src/formats/World.cpp b/src/formats/World.cpp new file mode 100644 index 0000000..d440185 --- /dev/null +++ b/src/formats/World.cpp @@ -0,0 +1,6 @@ +#include "World.h" + +bool World::Read(World &instance, void *data, size_t size) { + // TODO: Implement this + return true; +} diff --git a/src/formats/World.h b/src/formats/World.h new file mode 100644 index 0000000..5c21f67 --- /dev/null +++ b/src/formats/World.h @@ -0,0 +1,51 @@ +#ifndef WORLD_H +#define WORLD_H + +#include +#include + +#include "GameObjectDef.h" +#include "GameObjectListHolder.h" + +struct LevelRef { + std::string Name; + std::string BoundingBoxInfoString; + std::string FillLightColorString; + std::string RimLightColorString; + float RimLightAngle; +}; + +struct BuildingDef : public GameObjectDef { + std::string SaveName; + int LotID; +}; + +struct SlotGameObjectDef : public GameObjectDef { + int SlotID; +}; + +struct PortalDef : public GameObjectDef { + bool TeleportPlayerOnCollision; + bool TeleportNPCOnCollision; + bool Locked; +}; + +struct SlotsDef { + std::vector Slots; +}; + +struct ConstructedGameObjectDef : public GameObjectDef { + std::string SaveName; +}; + +struct World : public GameObjectListHolder { + LevelRef Level; + std::vector Buildings; + std::vector ConstructedGameObjects; + std::vector Portals; + SlotsDef Slots; // TODO: This field is optional... std::optional vs SlotsDef*? + + static bool Read(World &instance, void *data, size_t size); +}; + +#endif // WORLD_H From 495ccf22b39f001eda0cbe8ef3a7b42589ec26e6 Mon Sep 17 00:00:00 2001 From: bottledlactose <195167582+bottledlactose@users.noreply.github.com> Date: Sun, 16 Feb 2025 21:47:27 +0100 Subject: [PATCH 09/30] Add XML parsing error handling --- CMakeLists.txt | 8 +++++++- src/formats/CharacterDef.cpp | 11 ++++++++--- src/formats/CharacterDef.h | 2 +- src/formats/ObjectDef.cpp | 11 +++++++++-- src/formats/ObjectDef.h | 5 +---- src/util/Logger.cpp | 15 +++++++++++++-- tests/CharacterDefTest.cpp | 5 ++++- 7 files changed, 43 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f445f32..8e44067 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,13 @@ if (BUILD_TESTS) tests/CharacterDefTest.cpp # Format src/formats/CharacterDef.h - src/formats/CharacterDef.cpp) + src/formats/CharacterDef.cpp + # Utilities + src/util/Logger.h + src/util/Logger.cpp) + + # Set a define to indicate that we are running unit tests + target_compile_definitions(Tests PRIVATE -DUNIT_TESTING) target_include_directories(Tests PRIVATE libs/pugixml/src) target_include_directories(Tests PRIVATE src) diff --git a/src/formats/CharacterDef.cpp b/src/formats/CharacterDef.cpp index 8aa6139..16a374a 100644 --- a/src/formats/CharacterDef.cpp +++ b/src/formats/CharacterDef.cpp @@ -1,14 +1,17 @@ #include "CharacterDef.h" #include "pugixml.hpp" -#include +#include "../util/Logger.h" -void CharacterDef::Read(CharacterDef &instance, void *data, size_t size) { +bool CharacterDef::Read(CharacterDef &instance, void *data, size_t size) { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_string(static_cast(data), size); - // TODO: Add error handling + if (!result) { + MSML_LOG_ERROR("Failed to parse CharacterDef XML: %s", result.description()); + return false; + } instance.Script = doc.child("CharacterDef").child("Script").text().as_string(); instance.BodyModel = doc.child("CharacterDef").child("BodyModel").text().as_string(); @@ -38,4 +41,6 @@ void CharacterDef::Read(CharacterDef &instance, void *data, size_t size) { interest.text().as_int() }); } + + return true; } diff --git a/src/formats/CharacterDef.h b/src/formats/CharacterDef.h index 2573385..3018bc6 100644 --- a/src/formats/CharacterDef.h +++ b/src/formats/CharacterDef.h @@ -36,7 +36,7 @@ struct CharacterDef { LuaData LuaData; Influences Influences; - static void Read(CharacterDef &instance, void *data, size_t size); + static bool Read(CharacterDef &instance, void *data, size_t size); }; #endif // CHARACTERDEF_H diff --git a/src/formats/ObjectDef.cpp b/src/formats/ObjectDef.cpp index 1cf3713..704d7e5 100644 --- a/src/formats/ObjectDef.cpp +++ b/src/formats/ObjectDef.cpp @@ -1,18 +1,25 @@ #include "ObjectDef.h" #include "pugixml.hpp" -#include +#include "../util/Logger.h" -void ObjectDef::Read(ObjectDef &instance, void *data, size_t size) { +bool ObjectDef::Read(ObjectDef &instance, void *data, size_t size) { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_string(static_cast(data), size); + if (!result) { + MSML_LOG_ERROR("Failed to parse ObjectDef XML: %s", result.description()); + return false; + } + instance.Model = doc.child("ObjectDef").child("Model").text().as_string(); instance.Rig = doc.child("ObjectDef").child("Rig").text().as_string(); instance.Script = doc.child("ObjectDef").child("Script").text().as_string(); instance.MaxAttachments = doc.child("ObjectDef").child("MaxAttachments").text().as_string(); instance.CollisionInfo = doc.child("ObjectDef").child("CollisionInfo").text().as_string(); instance.NoFootPrint = doc.child("ObjectDef").child("NoFootPrint").text().as_bool(); + + return true; } diff --git a/src/formats/ObjectDef.h b/src/formats/ObjectDef.h index 0c1b089..e2380c4 100644 --- a/src/formats/ObjectDef.h +++ b/src/formats/ObjectDef.h @@ -2,8 +2,6 @@ #define OBJECTDEF_H #include -#include -#include struct ObjectDef { @@ -14,8 +12,7 @@ struct ObjectDef { std::string CollisionInfo; bool NoFootPrint; - static void Read(ObjectDef &instance, void *data, size_t size); - + static bool Read(ObjectDef &instance, void *data, size_t size); }; #endif // OBJECTDEF_H \ No newline at end of file diff --git a/src/util/Logger.cpp b/src/util/Logger.cpp index e18ee01..fa0dc0c 100644 --- a/src/util/Logger.cpp +++ b/src/util/Logger.cpp @@ -10,8 +10,13 @@ #include #include -#include "../modloader/ModLoader.h" - +// Currently, the logger is depending on the ModLoader class. This is causing trouble +// with unit tests, since it would require the ModLoader to be included along with +// dependencies such as sigmatch, which isn't ideal for unit tests... +// There should be a better solution for this in the future. +#ifndef UNIT_TESTING +# include "../modloader/ModLoader.h" +#endif // UNIT_TESTING void Logger::Log(const LogLevel level, bool cout, const char *file, int line, const char *format, ...) { const std::time_t now = std::time(nullptr); @@ -24,6 +29,7 @@ void Logger::Log(const LogLevel level, bool cout, const char *file, int line, co char timeBuffer[20]; std::strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S", &timeInfo); +#ifndef UNIT_TESTING char dateBuffer[11]; std::strftime(dateBuffer, sizeof(dateBuffer), "%Y-%m-%d", &timeInfo); const std::string logFileName = ModLoader::GetInstance().modulePath + std::string("log_") + dateBuffer + ".txt"; @@ -33,6 +39,7 @@ void Logger::Log(const LogLevel level, bool cout, const char *file, int line, co std::cerr << "Failed to open log file: " << logFileName << std::endl; return; } +#endif // UNIT_TESTING char logMessage[1024]; va_list args; @@ -42,9 +49,13 @@ void Logger::Log(const LogLevel level, bool cout, const char *file, int line, co const std::string logEntry = "[" + std::string(timeBuffer) + "] [" + LogLevelToString(level) + "] (" + file + ":" + std::to_string(line) + ") " + logMessage + "\n"; +#ifndef UNIT_TESTING if (cout) std::cout << logEntry; logFile << logEntry; +#else + std::cout << logEntry; +#endif // UNIT_TESTING } const char * Logger::LogLevelToString(LogLevel level) { diff --git a/tests/CharacterDefTest.cpp b/tests/CharacterDefTest.cpp index e50756d..dcff832 100644 --- a/tests/CharacterDefTest.cpp +++ b/tests/CharacterDefTest.cpp @@ -63,7 +63,10 @@ TEST(CharacterDefTest, ReadFromStream) { // Create CharacterDef instance and call Read method CharacterDef characterDef; - CharacterDef::Read(characterDef, buffer, size); + bool result = CharacterDef::Read(characterDef, buffer, size); + + // Ensure Read method returned true + ASSERT_TRUE(result) << "CharacterDef::Read failed to parse XML data"; // Validate that CharacterDef correctly parsed the data (assuming GetName() method exists) EXPECT_EQ(characterDef.Script, "NPC_Mock"); From e5add55596d2974cc3081527a175ca1044a787ae Mon Sep 17 00:00:00 2001 From: bottledlactose <195167582+bottledlactose@users.noreply.github.com> Date: Sun, 16 Feb 2025 21:55:00 +0100 Subject: [PATCH 10/30] Fix ObjectDef unit test --- CMakeLists.txt | 5 +++++ tests/ObjectDefTest.cpp | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e44067..13e6935 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,8 @@ add_library(MySimsModLoader SHARED src/Main.cpp # Format src/formats/CharacterDef.h src/formats/CharacterDef.cpp + src/formats/ObjectDef.h + src/formats/ObjectDef.cpp src/formats/World.h src/formats/World.cpp ) @@ -74,9 +76,12 @@ if (BUILD_TESTS) add_executable(Tests # Tests tests/CharacterDefTest.cpp + tests/ObjectDefTest.cpp # Format src/formats/CharacterDef.h src/formats/CharacterDef.cpp + src/formats/ObjectDef.h + src/formats/ObjectDef.cpp # Utilities src/util/Logger.h src/util/Logger.cpp) diff --git a/tests/ObjectDefTest.cpp b/tests/ObjectDefTest.cpp index 9a51589..f3812eb 100644 --- a/tests/ObjectDefTest.cpp +++ b/tests/ObjectDefTest.cpp @@ -58,14 +58,17 @@ TEST(ObjectDefTest, ReadFromStream) { // Create ObjectDef instance and call Read method ObjectDef objectDef; - ObjectDef::Read(objectDef, buffer, size); + bool result = ObjectDef::Read(objectDef, buffer, size); + + // Ensure the data is read correctly + ASSERT_TRUE(result) << "ObjectDef::Read failed to parse data"; // Validate that CharacterDef correctly parsed the data (assuming GetName() method exists) EXPECT_EQ(objectDef.Model, "flairSymbolMock"); EXPECT_EQ(objectDef.Rig, "essenceSymbolRig-rig"); EXPECT_EQ(objectDef.Script, "Essence"); //EXPECT_EQ(objectDef.HavokInfo, "2"); - EXPECT_EQ(objectDef.NoFootPrint, "1"); + ASSERT_TRUE(objectDef.NoFootPrint); //EXPECT_EQ(objectDef.RotateByHavok, "0"); //EXPECT_EQ(objectDef.HavokLinearDamping, "2.0f"); //EXPECT_EQ(objectDef.Shadow, "0"); From dfab8ef9d81a5b15277810f3bab1f94c514d40e4 Mon Sep 17 00:00:00 2001 From: bottledlactose <195167582+bottledlactose@users.noreply.github.com> Date: Mon, 17 Feb 2025 18:43:24 +0100 Subject: [PATCH 11/30] Optimize CharacterDef and ObjectDef parsing --- src/formats/CharacterDef.cpp | 36 +++++++++++++++++++----------------- src/formats/ObjectDef.cpp | 14 ++++++++------ 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/formats/CharacterDef.cpp b/src/formats/CharacterDef.cpp index 16a374a..bf81cc1 100644 --- a/src/formats/CharacterDef.cpp +++ b/src/formats/CharacterDef.cpp @@ -13,29 +13,31 @@ bool CharacterDef::Read(CharacterDef &instance, void *data, size_t size) { return false; } - instance.Script = doc.child("CharacterDef").child("Script").text().as_string(); - instance.BodyModel = doc.child("CharacterDef").child("BodyModel").text().as_string(); - instance.BodyDM = doc.child("CharacterDef").child("BodyDM").text().as_string(); - instance.HeadModel = doc.child("CharacterDef").child("HeadModel").text().as_string(); - instance.HairIndex = doc.child("CharacterDef").child("HairIndex").text().as_int(); - instance.HatIndex = doc.child("CharacterDef").child("HatIndex").text().as_int(); - instance.EyesModel = doc.child("CharacterDef").child("EyesModel").text().as_string(); - instance.MouthModel = doc.child("CharacterDef").child("MouthModel").text().as_string(); - instance.SkinToneIndex = doc.child("CharacterDef").child("SkinToneIndex").text().as_int(); - instance.MiscOpIndex = doc.child("CharacterDef").child("MiscOpIndex").text().as_int(); - instance.MiscModIndex = doc.child("CharacterDef").child("MiscModIndex").text().as_int(); - instance.VoxGroup = doc.child("CharacterDef").child("VoxGroup").text().as_string(); - instance.PitchAdjustment = doc.child("CharacterDef").child("PitchAdjustment").text().as_double(); - instance.Rig = doc.child("CharacterDef").child("Rig").text().as_string(); - instance.CollisionInfo = doc.child("CharacterDef").child("CollisionInfo").text().as_string(); + auto CharacterDef = doc.child("CharacterDef"); + + instance.Script = CharacterDef.child("Script").text().as_string(); + instance.BodyModel = CharacterDef.child("BodyModel").text().as_string(); + instance.BodyDM = CharacterDef.child("BodyDM").text().as_string(); + instance.HeadModel = CharacterDef.child("HeadModel").text().as_string(); + instance.HairIndex = CharacterDef.child("HairIndex").text().as_int(); + instance.HatIndex = CharacterDef.child("HatIndex").text().as_int(); + instance.EyesModel = CharacterDef.child("EyesModel").text().as_string(); + instance.MouthModel = CharacterDef.child("MouthModel").text().as_string(); + instance.SkinToneIndex = CharacterDef.child("SkinToneIndex").text().as_int(); + instance.MiscOpIndex = CharacterDef.child("MiscOpIndex").text().as_int(); + instance.MiscModIndex = CharacterDef.child("MiscModIndex").text().as_int(); + instance.VoxGroup = CharacterDef.child("VoxGroup").text().as_string(); + instance.PitchAdjustment = CharacterDef.child("PitchAdjustment").text().as_double(); + instance.Rig = CharacterDef.child("Rig").text().as_string(); + instance.CollisionInfo = CharacterDef.child("CollisionInfo").text().as_string(); // Read clips - for (pugi::xml_node clip : doc.child("CharacterDef").child("Clips").children()) { + for (pugi::xml_node clip : CharacterDef.child("Clips").children()) { instance.Clips[clip.name()] = clip.text().as_string(); } // Read influences - for (pugi::xml_node interest : doc.child("CharacterDef").child("Influences").children()) { + for (pugi::xml_node interest : CharacterDef.child("Influences").children()) { instance.Influences.Interests.push_back(Interest{ interest.attribute("type").as_string(), interest.text().as_int() diff --git a/src/formats/ObjectDef.cpp b/src/formats/ObjectDef.cpp index 704d7e5..516f6ff 100644 --- a/src/formats/ObjectDef.cpp +++ b/src/formats/ObjectDef.cpp @@ -13,12 +13,14 @@ bool ObjectDef::Read(ObjectDef &instance, void *data, size_t size) { return false; } - instance.Model = doc.child("ObjectDef").child("Model").text().as_string(); - instance.Rig = doc.child("ObjectDef").child("Rig").text().as_string(); - instance.Script = doc.child("ObjectDef").child("Script").text().as_string(); - instance.MaxAttachments = doc.child("ObjectDef").child("MaxAttachments").text().as_string(); - instance.CollisionInfo = doc.child("ObjectDef").child("CollisionInfo").text().as_string(); - instance.NoFootPrint = doc.child("ObjectDef").child("NoFootPrint").text().as_bool(); + auto ObjectDef = doc.child("ObjectDef"); + + instance.Model = ObjectDef.child("Model").text().as_string(); + instance.Rig = ObjectDef.child("Rig").text().as_string(); + instance.Script = ObjectDef.child("Script").text().as_string(); + instance.MaxAttachments = ObjectDef.child("MaxAttachments").text().as_string(); + instance.CollisionInfo = ObjectDef.child("CollisionInfo").text().as_string(); + instance.NoFootPrint = ObjectDef.child("NoFootPrint").text().as_bool(); return true; } From 87f5b0eada5c8a5f8b4a90b628177dd63b141fd5 Mon Sep 17 00:00:00 2001 From: bottledlactose <195167582+bottledlactose@users.noreply.github.com> Date: Thu, 20 Feb 2025 14:15:34 +0100 Subject: [PATCH 12/30] Move XML related parsers to subdirectory --- CMakeLists.txt | 20 ++++++++++---------- src/formats/{ => xml}/CharacterDef.cpp | 2 +- src/formats/{ => xml}/CharacterDef.h | 0 src/formats/{ => xml}/GameObjectDef.h | 0 src/formats/{ => xml}/GameObjectListHolder.h | 0 src/formats/{ => xml}/ObjectDef.cpp | 2 +- src/formats/{ => xml}/ObjectDef.h | 0 src/formats/{ => xml}/World.cpp | 0 src/formats/{ => xml}/World.h | 0 tests/CharacterDefTest.cpp | 2 +- tests/ObjectDefTest.cpp | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) rename src/formats/{ => xml}/CharacterDef.cpp (98%) rename src/formats/{ => xml}/CharacterDef.h (100%) rename src/formats/{ => xml}/GameObjectDef.h (100%) rename src/formats/{ => xml}/GameObjectListHolder.h (100%) rename src/formats/{ => xml}/ObjectDef.cpp (96%) rename src/formats/{ => xml}/ObjectDef.h (100%) rename src/formats/{ => xml}/World.cpp (100%) rename src/formats/{ => xml}/World.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 13e6935..262c267 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,12 +40,12 @@ add_library(MySimsModLoader SHARED src/Main.cpp src/signatures/lua.h src/signatures/sigdef.h # Format - src/formats/CharacterDef.h - src/formats/CharacterDef.cpp - src/formats/ObjectDef.h - src/formats/ObjectDef.cpp - src/formats/World.h - src/formats/World.cpp + src/formats/xml/CharacterDef.h + src/formats/xml/CharacterDef.cpp + src/formats/xml/ObjectDef.h + src/formats/xml/ObjectDef.cpp + src/formats/xml/World.h + src/formats/xml/World.cpp ) add_custom_target(version @@ -78,10 +78,10 @@ if (BUILD_TESTS) tests/CharacterDefTest.cpp tests/ObjectDefTest.cpp # Format - src/formats/CharacterDef.h - src/formats/CharacterDef.cpp - src/formats/ObjectDef.h - src/formats/ObjectDef.cpp + src/formats/xml/CharacterDef.h + src/formats/xml/CharacterDef.cpp + src/formats/xml/ObjectDef.h + src/formats/xml/ObjectDef.cpp # Utilities src/util/Logger.h src/util/Logger.cpp) diff --git a/src/formats/CharacterDef.cpp b/src/formats/xml/CharacterDef.cpp similarity index 98% rename from src/formats/CharacterDef.cpp rename to src/formats/xml/CharacterDef.cpp index bf81cc1..d50e06a 100644 --- a/src/formats/CharacterDef.cpp +++ b/src/formats/xml/CharacterDef.cpp @@ -1,7 +1,7 @@ #include "CharacterDef.h" #include "pugixml.hpp" -#include "../util/Logger.h" +#include "../../util/Logger.h" bool CharacterDef::Read(CharacterDef &instance, void *data, size_t size) { diff --git a/src/formats/CharacterDef.h b/src/formats/xml/CharacterDef.h similarity index 100% rename from src/formats/CharacterDef.h rename to src/formats/xml/CharacterDef.h diff --git a/src/formats/GameObjectDef.h b/src/formats/xml/GameObjectDef.h similarity index 100% rename from src/formats/GameObjectDef.h rename to src/formats/xml/GameObjectDef.h diff --git a/src/formats/GameObjectListHolder.h b/src/formats/xml/GameObjectListHolder.h similarity index 100% rename from src/formats/GameObjectListHolder.h rename to src/formats/xml/GameObjectListHolder.h diff --git a/src/formats/ObjectDef.cpp b/src/formats/xml/ObjectDef.cpp similarity index 96% rename from src/formats/ObjectDef.cpp rename to src/formats/xml/ObjectDef.cpp index 516f6ff..a220895 100644 --- a/src/formats/ObjectDef.cpp +++ b/src/formats/xml/ObjectDef.cpp @@ -1,7 +1,7 @@ #include "ObjectDef.h" #include "pugixml.hpp" -#include "../util/Logger.h" +#include "../../util/Logger.h" bool ObjectDef::Read(ObjectDef &instance, void *data, size_t size) { diff --git a/src/formats/ObjectDef.h b/src/formats/xml/ObjectDef.h similarity index 100% rename from src/formats/ObjectDef.h rename to src/formats/xml/ObjectDef.h diff --git a/src/formats/World.cpp b/src/formats/xml/World.cpp similarity index 100% rename from src/formats/World.cpp rename to src/formats/xml/World.cpp diff --git a/src/formats/World.h b/src/formats/xml/World.h similarity index 100% rename from src/formats/World.h rename to src/formats/xml/World.h diff --git a/tests/CharacterDefTest.cpp b/tests/CharacterDefTest.cpp index dcff832..794cc10 100644 --- a/tests/CharacterDefTest.cpp +++ b/tests/CharacterDefTest.cpp @@ -2,7 +2,7 @@ #include #include #include -#include "formats/CharacterDef.h" +#include "formats/xml/CharacterDef.h" // Mock XML data (simulating CharacterDef.xml) const std::string MockCharacterDef = R"( diff --git a/tests/ObjectDefTest.cpp b/tests/ObjectDefTest.cpp index f3812eb..67ad746 100644 --- a/tests/ObjectDefTest.cpp +++ b/tests/ObjectDefTest.cpp @@ -4,7 +4,7 @@ #include #include #include -#include "formats/ObjectDef.h" +#include "formats/xml/ObjectDef.h" // Mock XML data (simulating ObjectDef.xml) const std::string MockObjectDef = R"( From 67c5b00336fab297cccb247c5bc49909e528dd25 Mon Sep 17 00:00:00 2001 From: bottledlactose <195167582+bottledlactose@users.noreply.github.com> Date: Thu, 20 Feb 2025 16:25:30 +0100 Subject: [PATCH 13/30] Add basic material reading --- CMakeLists.txt | 11 +- src/formats/BinaryReader.cpp | 16 ++ src/formats/BinaryReader.h | 34 +++ src/formats/ResourceKey.h | 12 + src/formats/materials/Material.cpp | 46 ++++ src/formats/materials/Material.h | 30 +++ src/formats/materials/MaterialParameter.h | 16 ++ src/formats/materials/MaterialParameterType.h | 221 ++++++++++++++++++ tests/MaterialTest.cpp | 54 +++++ 9 files changed, 439 insertions(+), 1 deletion(-) create mode 100644 src/formats/BinaryReader.cpp create mode 100644 src/formats/BinaryReader.h create mode 100644 src/formats/ResourceKey.h create mode 100644 src/formats/materials/Material.cpp create mode 100644 src/formats/materials/Material.h create mode 100644 src/formats/materials/MaterialParameter.h create mode 100644 src/formats/materials/MaterialParameterType.h create mode 100644 tests/MaterialTest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 262c267..17716c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,10 @@ add_library(MySimsModLoader SHARED src/Main.cpp src/signatures/lua.h src/signatures/sigdef.h # Format + src/formats/BinaryReader.h + src/formats/BinaryReader.cpp + src/formats/materials/Material.h + src/formats/materials/Material.cpp src/formats/xml/CharacterDef.h src/formats/xml/CharacterDef.cpp src/formats/xml/ObjectDef.h @@ -76,15 +80,20 @@ if (BUILD_TESTS) add_executable(Tests # Tests tests/CharacterDefTest.cpp + tests/MaterialTest.cpp tests/ObjectDefTest.cpp # Format src/formats/xml/CharacterDef.h src/formats/xml/CharacterDef.cpp src/formats/xml/ObjectDef.h src/formats/xml/ObjectDef.cpp + src/formats/materials/Material.h + src/formats/materials/Material.cpp # Utilities src/util/Logger.h - src/util/Logger.cpp) + src/util/Logger.cpp + src/formats/BinaryReader.h + src/formats/BinaryReader.cpp) # Set a define to indicate that we are running unit tests target_compile_definitions(Tests PRIVATE -DUNIT_TESTING) diff --git a/src/formats/BinaryReader.cpp b/src/formats/BinaryReader.cpp new file mode 100644 index 0000000..29066be --- /dev/null +++ b/src/formats/BinaryReader.cpp @@ -0,0 +1,16 @@ +#include "BinaryReader.h" + +BinaryReader::BinaryReader(void *data, size_t size) + : data(data), size(size), offset(0) {} + +void BinaryReader::Read(void* buffer, size_t size) { + if (offset + size > this->size) { + throw std::runtime_error("BinaryReader::Read: Attempted to read past end of buffer"); + } + + if (buffer) { + memcpy(buffer, static_cast(data) + offset, size); + } + + offset += size; +} diff --git a/src/formats/BinaryReader.h b/src/formats/BinaryReader.h new file mode 100644 index 0000000..331b640 --- /dev/null +++ b/src/formats/BinaryReader.h @@ -0,0 +1,34 @@ +#ifndef BINARYREADER_HPP +#define BINARYREADER_HPP + +#include + +class BinaryReader { +private: + void *data; + size_t size; + size_t offset; + +public: + BinaryReader(void *data, size_t size); + ~BinaryReader() = default; + + void Read(void* buffer, size_t size); + + template + T Read() { + T value; + Read(&value, sizeof(T)); + return value; + } + + inline size_t GetSize() const { + return size; + } + + inline size_t GetOffset() const { + return offset; + } +}; + +#endif // BINARYREADER_HPP diff --git a/src/formats/ResourceKey.h b/src/formats/ResourceKey.h new file mode 100644 index 0000000..8dc950f --- /dev/null +++ b/src/formats/ResourceKey.h @@ -0,0 +1,12 @@ +#ifndef RESOURCEKEY_H +#define RESOURCEKEY_H + +#include + +struct ResourceKey { + uint64_t instance; + uint32_t type; + uint32_t group; +}; + +#endif // RESOURCEKEY_H \ No newline at end of file diff --git a/src/formats/materials/Material.cpp b/src/formats/materials/Material.cpp new file mode 100644 index 0000000..7334545 --- /dev/null +++ b/src/formats/materials/Material.cpp @@ -0,0 +1,46 @@ +#include "Material.h" + +#include +#include "../BinaryReader.h" +#include + +void Material::Read(Material &instance, void *data, size_t size) { + BinaryReader reader(data, size); + + reader.Read(); // 1 + reader.Read(); // 1 + reader.Read(); // 0 + reader.Read(); // 0 + reader.Read(); // 1 + + // TODO: Give ResourceKey its self-contained Read method + // This requires the current offset to be passed to the Read method + instance.self.instance = reader.Read(); + instance.self.type = reader.Read(); + instance.self.group = reader.Read(); + + instance.headerSize = reader.Read(); + instance.totalSize = reader.Read(); + + reader.Read(nullptr, 4); // MATD + reader.Read(); // MATD version + + instance.materialHash = reader.Read(); + instance.shaderHash = reader.Read(); + + instance.mtrlSize = reader.Read(); + + size_t mtrlOffset = reader.GetOffset(); + + reader.Read(nullptr, 4); // MTRL + reader.Read(); // 0 + + instance.dataSize = reader.Read(); + instance.numParams = reader.Read(); + + for (uint32_t i = 0; i < instance.numParams; i++) { + MaterialParameter parameter; + // TODO: Read material parameter + + } +} diff --git a/src/formats/materials/Material.h b/src/formats/materials/Material.h new file mode 100644 index 0000000..8a5f072 --- /dev/null +++ b/src/formats/materials/Material.h @@ -0,0 +1,30 @@ +#ifndef MATERIAL_H +#define MATERIAL_H + +#include +#include + +#include "../ResourceKey.h" +#include "MaterialParameter.h" + +// TODO: Add shader IDs + +struct Material { + std::vector parameters; + ResourceKey self; + uint32_t totalSize; + uint32_t headerSize; + uint32_t mtrlSize; + uint32_t dataSize; + + uint32_t numParams; + + uint32_t materialHash; + uint32_t shaderHash; + + // TODO: add an easy way to fetch the shader name + + static void Read(Material &instance, void *data, size_t size); +}; + +#endif // MATERIAL_H diff --git a/src/formats/materials/MaterialParameter.h b/src/formats/materials/MaterialParameter.h new file mode 100644 index 0000000..b9baa41 --- /dev/null +++ b/src/formats/materials/MaterialParameter.h @@ -0,0 +1,16 @@ +#ifndef MATERIALPARAMETER_H +#define MATERIALPARAMETER_H + +#include "MaterialParameterType.h" + +struct MaterialParameter { + MaterialParameterType type; + // TODO: Add ExtraParamInfo + uint32_t valueType; + uint32_t valueFieldCount; + uint32_t offset; + + static void Read(MaterialParameter &instance, void *data, size_t size); +}; + +#endif // MATERIALPARAMETER_H diff --git a/src/formats/materials/MaterialParameterType.h b/src/formats/materials/MaterialParameterType.h new file mode 100644 index 0000000..821a8ff --- /dev/null +++ b/src/formats/materials/MaterialParameterType.h @@ -0,0 +1,221 @@ +#ifndef MATERIALPARAMETERTYPE_H +#define MATERIALPARAMETERTYPE_H + +#include + +enum class MaterialParameterType : uint32_t +{ + diffuseColor = 0x7FEE2D1A, + useLights = 0x76F88689, + highlightMultiplier = 0x2616B09A, + diffuseMap = 0x6CC0FD85, + ambientMap = 0x20CB22B7, + specularMap = 0xAD528A60, + alphaMap = 0x2A20E51B, + shadowReceiver = 0xF46B90AE, + blendmode = 0xB2649C2F, + transparency = 0x05D22FD3, + ambient = 0x04A5DAA3, + diffuse = 0x637DAA05, + greenChannelMultiplier = 0xD1F4CB96, + blueChannelMultiplier = 0x7BB10C17, + redChannelMultiplier = 0x99BF82F6, + nightTint = 0x689AEFFE, + dayTint = 0xFBBBB5C2, + overbrightDay = 0x1D17D10F, + negativeColorBiasNight = 0xDB88EC28, + negativeColorBiasDay = 0x29214C0C, + overbrightNight = 0xB779F79B, + specularColor = 0xBF2AD9B3, + specular = 0x2CE11842, + transparent = 0x988403F9, + vNormalWaveSpeed = 0xAB26E148, + emissionMap = 0xF303D152, + vReflectionWaveSpeed = 0xDB319586, + normalMapScale = 0x3C45E334, + jitterScale = 0xA2E40EAB, + waveFrequency = 0x02937388, + uReflectionWaveSpeed = 0x50E0193B, + waterColorBlue = 0x2A93BAFB, + baseAlpha = 0x5916ED3E, + reflectionSharpness = 0xE460597B, + intensity = 0x933E38F4, + waveAmplitude = 0x11EFE2FD, + noiseFrequency = 0x7FD42F11, + ShinyPower = 0xBD237B0D, + VspeedLayer2 = 0x2E18B549, + warpAmp = 0xDB5EBEE7, + VspeedLayer0 = 0x2E18B54B, + VspeedLayer1 = 0x2E18B54A, + UspeedLayer1 = 0x7EEA0C2B, + UspeedLayer0 = 0x7EEA0C2A, + UspeedLayer2 = 0x7EEA0C28, + reflectionIntensity = 0xD552A779, + reflectionAmount = 0xB32A1342, + uNormalWaveSpeed = 0x9F63578D, + diffuseAlpha = 0xF72FCA9B, + contrastSubtractColor = 0x7490C750, + contrastMultiplyColor = 0x6612378C, + amBodyShakespeare = 0x9038F94B, + amHeadHairLongSpikey = 0x1067900C, + auHeadHairBigFro = 0x0923FB40, + afBodyLayeredSkirt = 0x58B2F06D, + afHeadHairFortune = 0x80C83701, + amHeadHairSpikey = 0x75486BDE, + afHeadHairTightBun = 0x6C8C62C9, + afHeadHatPirateGinny = 0x61F36B5B, + auHeadHatCap = 0xE17E380C, + faceSkinTones = 0x0FDC6FDC, + auHeadHairFlowerCrown = 0x9EDA8CF5, + amHeadHatBellhop = 0xF0D0E420, + amHeadHatMagician = 0xC1519BCF, + auHeadHatPilotGoggles = 0x8F0C0492, + afBodyLowPoofSkirt = 0xC5AE022B, + afBodyMayor = 0x383B9128, + auHeadHatCapback = 0xD89AD4D5, + afHeadHairLibrarian = 0x7255E7BE, + afBodyTurtleneckBaggy = 0xE2498117, + auHeadHatBeenie = 0xBCB6F07C, + afHeadHairSmallBraids = 0xFCDF8C6A, + afHeadHairPuffyLayers = 0x359839D2, + amHeadHairIvyLeague = 0xDE545F5E, + afHeadHairMayor = 0x146CB6B6, + amHeadHairNigel = 0xE97A9352, + auHeadHatNinja = 0xB4DE4520, + auHeadHairMidShaggy = 0x7C22B02C, + afBodyShortApron = 0x556E4212, + afHeadHairCurlsRibbons = 0x8CBF470E, + auBodyPantsJacketBag = 0x3B2679D5, + afBodyShortSkirtSweater = 0xD12B0C98, + amHeadHairRay = 0xCF76A1C7, + amHeadHairArcade = 0xE029E90D, + afBodyHighPoofLongSkirt = 0xF434AA77, + afHeadHatBandanaDreads = 0xEA080C69, + auHeadHairFoxEars = 0xC9314483, + afBodyCollarSkirt = 0x7D6FDC4C, + afBodyCoatSkirt = 0xC51BB766, + afHeadHairStylishPeacock = 0xE806C452, + afBodyKimono = 0x5F00B265, + auHeadHatTopHat = 0x16E4CA30, + amHeadHatChef = 0xB7A93AA8, + auBodyKnight = 0x6515EB2C, + amHeadHairEthan = 0xE9CA3E0B, + afHeadHairClara = 0x0A371797, + afHeadHatWendalyn = 0x6E2B178D, + amBodyHauntedHouseBoy = 0xA822B3E8, + auHeadHatMohawk = 0xD59381FB, + auHeadHairSuperShortLayered = 0xE72A5F1C, + amHeadHairTim = 0xEB85D831, + auBodyHoodiePants = 0x79A3B7FF, + afBodyLongSleeveLongDress = 0xD01B0A09, + afHeadHatCowgirl = 0x4A351BDC, + auHeadHatBald = 0x9ED158AB, + amBodyMartialArts = 0xD9DFB575, + propBookClosed = 0xE2B571A9, + amBodyFlipper = 0xE1A22A57, + afBodyLongSkirtLargeCuff = 0x66BA9C80, + auHeadHatPirate = 0xE4F0D787, + auHeadHairShortFlatBangs = 0x26F07855, + auBodyBellhop = 0x2836EA65, + auBodyApronBear = 0xC800D94B, + afBodyKneeLengthSkirt = 0xDD91B6B6, + auHeadHatRasta = 0x8D58D24F, + afBodyLongSkirt = 0x32E0CA0B, + auBodySkinTight = 0x23C6D774, + auBodyCalfLengthPants = 0x7BEBDD19, + plumbobColor = 0xEDDCECE1, + afHeadHairDoubleBuns = 0x455BEF77, + auHeadHairHairspraySpikey = 0xC36D202B, + afHeadHairRaveKimono = 0xAFC8F11B, + auHeadHairBowlCut = 0x40A202A7, + amHeadHairCruise = 0xAD6D2254, + auBodyLongPantsBoots = 0x57059004, + afHeadHatNewspaperCap = 0x791597CA, + afHeadHatBandana = 0x5519CFB6, + afHeadHairAlexa = 0x811F207F, + afHeadHairStreakedLolita = 0x37C3B76C, + afHeadHairPuffyLayersBunny = 0xF8404FFA, + auBodyApronTshirtPants = 0xBE323F01, + auBodyLongPantsShortSleeves = 0xC34A68D0, + amBodyArcade = 0xBCF4239B, + afBodyAlexa = 0xB3F9D3F1, + afBodyAsymmetricalSkirt = 0xCB6A2C62, + auHeadHatCadet = 0x88B04723, + auBodyBear = 0x8157DC19, + auHeadHairDisco = 0x4E053DBD, + afBodyShortSleeveApron = 0xAF284852, + auBodyRolledSleevesLongPants = 0x8804B9B4, + afHeadHairPigTail = 0x4487E3D4, + afHeadHairLooseCurlsLong = 0xEBBB243F, + afHeadHairLong = 0xBBF23C58, + afHeadHairPigTailFlowers = 0xB9642FF0, + afHeadHairLongBraid = 0xAA3CD006, + afHeadHairLongPigtail = 0x804AD79A, + afHeadHatBeaniePigtails = 0x608CAA94, + afBodyChineseDress = 0xC3DD71DA, + amHeadHatCowboy = 0xD987C7AD, + afBodyFloristYoungerSister = 0x667D4E9C, + auHeadHatEarhat = 0x1688F273, + afHeadHairHighSalon = 0x4038B561, + afHeadHairSoftBobBangs = 0xB857A450, + afHeadHairKarine = 0x16229F12, + amBodyGothCoat = 0xE808F034, + afHeadHairBangsHighPonyTail = 0xEBB1363D, + amHeadHatMartialArts = 0x10B11928, + auHeadHairShortFro = 0x31B41A58, + afBodyWendalyn = 0x32FF6934, + amHeadHatShakespeare = 0x172754F2, + auBodyBackpack = 0x4CF48F41, + auHeadHairLongLayered = 0x5E5E0BB5, + afHeadHairBee = 0xDB272B16, + amHeadHairSlickBack = 0x0562A36E, + afHeadHatFedoraHeadset = 0xADF12CDC, + auBodySuitBowTie = 0x206508D6, + amHeadHatNewspaperCap = 0x21EAEAC7, + auBodyNoSleevesLongPants = 0x0568E523, + amHeadHairPompadour = 0x4C34687C, + auBodyPirate = 0x1F8C55E8, + auBodyShortPantsShortSleeves = 0x6293CA92, + amBodyChef = 0x57CFFD77, + afBodyShortSkirtBag = 0x9E77273B, + afHeadHairPuffyLayersTiara = 0x407405F3, + amHeadHairSidePart = 0x61AB1E17, + amBodySamurai = 0x69E3E1A7, + amHeadHairShort = 0xF67D2839, + amHeadHatFlipper = 0x68592352, + afBodyFortuneTeller = 0x1437614B, + auBodyShortSleevApronPants = 0xA8EC7CF0, + auHeadHatVisor = 0x7FD2FD6D, + auHeadHairMuseum = 0x94F2A3F5, + amHeadHatBuzzCut = 0xAB532E19, + auBodyShortJacketClosed = 0xEAE93C5D, + afBodyHighPoofSkirt = 0x115E90E5, + auHeadHatHippieBandana = 0xA66E30F0, + afBodySmallWings = 0xE042258B, + afHeadHairStylish = 0x6C25C854, + afHeadHairLayeredBangsMedium = 0x30872F06, + afHeadHatCrumplebottom = 0x6A7C3EFC, + amHeadHatFedora = 0x0A0BF0F7, + auHeadHairDandelion = 0x5C211319, + auBodyNinja = 0x1514F851, + auHeadHairSushi = 0x018261BD, + afHeadHairLongLayered = 0x2A45864C, + afHeadHairLongPonytail = 0x22DF72CE, + auHeadHairVeryShortSpiky = 0x5A0C9575, + afHeadHairObservatory = 0x8D6F69F2, + auBodyBulkySweaterLongPants = 0x8637DF43, + auHeadHairShortCurly = 0x5FC9D348, + auBodyLongPantsLongSleeve = 0x86769DAF, + amHeadHairScientist = 0x2344A259, + auHeadHatBear = 0x79DBAB9E, + amHeadHatCombOver = 0x1F0050D9, + afBodyMini = 0x04985945, + afHeadHairUpdoRibbons = 0x37A80FC1, + amHeadHatBaker = 0x3D88B8B3, + auBodyLabCoat = 0xBCC02D91, + envmapAlpha = 0x0A345310, + door_archedTopBar = 0x4A1A7937, + unknown = 0x00000000 +}; + +#endif // MATERIALPARAMETERTYPE_H diff --git a/tests/MaterialTest.cpp b/tests/MaterialTest.cpp new file mode 100644 index 0000000..e9dd3db --- /dev/null +++ b/tests/MaterialTest.cpp @@ -0,0 +1,54 @@ +#include +#include +#include "formats/materials/Material.h" + +#include + +const uint8_t MockMaterial[384] = { + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xE1, 0x5D, 0xEA, 0x7D, + 0x00, 0x00, 0x00, 0x00, 0x5D, 0xE7, 0xD0, 0x01, 0x92, 0x42, 0x11, 0x4D, + 0x2C, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x4D, 0x41, 0x54, 0x44, + 0x01, 0x00, 0x00, 0x00, 0xE1, 0x5D, 0xEA, 0x7D, 0x78, 0x35, 0x77, 0x94, + 0x24, 0x01, 0x00, 0x00, 0x4D, 0x54, 0x52, 0x4C, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x2D, 0x53, 0xA9, 0xDA, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xA0, 0x41, 0xD4, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x4D, 0x41, 0x54, 0x45, 0x52, 0x49, 0x41, 0x4C, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x2D, 0x53, 0xA9, 0xDA, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xA0, 0x41, 0xD4, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x4D, 0x41, 0x54, 0x45, 0x52, 0x49, 0x41, 0x4C, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x2D, 0x53, 0xA9, 0xDA, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xA0, 0x41, 0xD4, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x4D, 0x41, 0x54, 0x45, 0x52, 0x49, 0x41, 0x4C, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x2D, 0x53, 0xA9, 0xDA, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xA0, 0x41, 0xD4, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x4D, 0x41, 0x54, 0x45, 0x52, 0x49, 0x41, 0x4C, 0x00, 0x00, 0x00, 0x00 +}; + +// Test case for Material file reading +TEST(MaterialTest, ReadFromStream) { + + Material material; + Material::Read(material, (void *)MockMaterial, sizeof(MockMaterial)); + + ASSERT_EQ(material.self.instance, 0x7DEA5DE1); + ASSERT_EQ(material.self.type, 0x1D0E75D); + ASSERT_EQ(material.self.group, 0x4D114292); + + ASSERT_EQ(material.headerSize, 44); + ASSERT_EQ(material.totalSize, 312); + + ASSERT_EQ(material.materialHash, 0x7DEA5DE1); + ASSERT_EQ(material.shaderHash, 0x94773578); + + ASSERT_EQ(material.mtrlSize, 292); + + ASSERT_EQ(material.dataSize, 100); + ASSERT_EQ(material.numParams, 11); + + // TODO: Test material parameters +} From ed84dc208542553d776b54d788fbd8a19b1fb255 Mon Sep 17 00:00:00 2001 From: ThuverX Date: Tue, 11 Mar 2025 20:23:29 +0100 Subject: [PATCH 14/30] Loading subdirectories, they are loaded but the game doesn't see them as folders yet --- src/assets/Assets.cpp | 118 +++++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 53 deletions(-) diff --git a/src/assets/Assets.cpp b/src/assets/Assets.cpp index c4a9355..ce2cd27 100644 --- a/src/assets/Assets.cpp +++ b/src/assets/Assets.cpp @@ -69,6 +69,63 @@ void Assets::RegisterReplacer(const std::string &path, const EA::ResourceMan::Ke replacers.emplace_back(asset); } +void CreateDatabaseInternal(EA::ResourceMan::Manager::Manager *manager, const std::filesystem::path& path) { + + auto *databaseStruct = static_cast(malloc(0x98)); + auto *database = EA::ResourceMan::DatabaseDirectoryFiles::ctor( + databaseStruct, path.wstring().c_str()); + + MSML_LOG_DEBUG("Creating database at %s", path.string().c_str()); + + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"model", 0x01661233); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"revomodel", 0xf9e50586); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"windowsmodel", 0xb359c791); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"rig", 0x8eaf13de); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"clip", 0x6b20c4f3); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"keynamemap", 0x0166038c); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"geometry", 0x015a1849); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"material", 0x01d0e75d); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"materialset", 0x02019972); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"oldspeedtree", 0x00b552ea); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"speedtree", 0x021d7e8c); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"dds", 0x00b2d882); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"compositetexture", 0x8e342417); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"simoutfit", 0x025ed6f4); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"levelxml", 0x585ee310); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"levelbin", 0x58969018); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"physics", 0xd5988020); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"luascript", 0x474999b4); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"lightsetxml", 0x50182640); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"lightsetbin", 0x50002128); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"xml", 0xdc37e964); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"footprintset", 0x2c81b60a); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"objectconstructionxml", 0xc876c85e); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"objectconstructionbin", 0xc08ec0ee); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"slotxml", 0x4045d294); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"slotbin", 0x487bf9e4); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"swm", 0xcf60795e); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"swarmbin", 0x9752e396); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"xmlbin", 0xe0d83029); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"cabxml", 0xa6856948); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"cabbin", 0xc644f440); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"big", 0x5bca8c06); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"bnk", 0xb6b5c271); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"lua", 0x474999b4); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"luo", 0x2b8e2411); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"lightboxxml", 0xb61215e9); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"lightboxbin", 0xd6215201); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"xmb", 0x1e1e6516); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"ttf", 0xfd72d418); + EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"ttc", 0x35ebb959); + + EA::ResourceMan::Manager::RegisterDatabase(manager, true, database, 1000); + EA::ResourceMan::DatabaseDirectoryFiles::Init(database); + EA::ResourceMan::DatabaseDirectoryFiles::Open(database, IO::AccessFlags::Read, IO::CD::LoadAllFiles, false, + false); + + // Maybe list the keys out here? instead of doing the add file hook? This way we can also programmatically call upon files +} + #pragma optimize("", off) void Assets::CreateDatabase(EA::ResourceMan::Manager::Manager *manager) { if (Mods::GetInstance().mods.empty()) return; @@ -77,59 +134,14 @@ void Assets::CreateDatabase(EA::ResourceMan::Manager::Manager *manager) { std::filesystem::path mod_path(mod->path); std::filesystem::path assets_path(mod->assetsPath); - auto *databaseStruct = static_cast(malloc(0x98)); - auto *database = EA::ResourceMan::DatabaseDirectoryFiles::ctor( - databaseStruct, (mod_path / assets_path).wstring().c_str()); - - MSML_LOG_DEBUG("Creating database at %s", (mod_path / assets_path).string().c_str()); - - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"model", 0x01661233); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"revomodel", 0xf9e50586); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"windowsmodel", 0xb359c791); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"rig", 0x8eaf13de); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"clip", 0x6b20c4f3); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"keynamemap", 0x0166038c); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"geometry", 0x015a1849); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"material", 0x01d0e75d); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"materialset", 0x02019972); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"oldspeedtree", 0x00b552ea); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"speedtree", 0x021d7e8c); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"dds", 0x00b2d882); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"compositetexture", 0x8e342417); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"simoutfit", 0x025ed6f4); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"levelxml", 0x585ee310); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"levelbin", 0x58969018); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"physics", 0xd5988020); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"luascript", 0x474999b4); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"lightsetxml", 0x50182640); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"lightsetbin", 0x50002128); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"xml", 0xdc37e964); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"footprintset", 0x2c81b60a); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"objectconstructionxml", 0xc876c85e); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"objectconstructionbin", 0xc08ec0ee); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"slotxml", 0x4045d294); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"slotbin", 0x487bf9e4); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"swm", 0xcf60795e); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"swarmbin", 0x9752e396); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"xmlbin", 0xe0d83029); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"cabxml", 0xa6856948); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"cabbin", 0xc644f440); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"big", 0x5bca8c06); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"bnk", 0xb6b5c271); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"lua", 0x474999b4); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"luo", 0x2b8e2411); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"lightboxxml", 0xb61215e9); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"lightboxbin", 0xd6215201); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"xmb", 0x1e1e6516); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"ttf", 0xfd72d418); - EA::ResourceMan::DatabaseDirectoryFiles::AddExtensionMapping(database, L"ttc", 0x35ebb959); - - EA::ResourceMan::Manager::RegisterDatabase(manager, true, database, 1000); - EA::ResourceMan::DatabaseDirectoryFiles::Init(database); - EA::ResourceMan::DatabaseDirectoryFiles::Open(database, IO::AccessFlags::Read, IO::CD::LoadAllFiles, false, - false); - - // Maybe list the keys out here? instead of doing the add file hook? This way we can also programmatically call upon files + CreateDatabaseInternal(manager, mod_path / assets_path); + + for (const auto& entry : std::filesystem::directory_iterator(mod_path / assets_path)) { + if (std::filesystem::is_directory(entry.path())) { + CreateDatabaseInternal(manager, entry.path()); + } + } + } } } From 49ffae67cfc23810ccdcc5bb0c0cac1de4f7bdbb Mon Sep 17 00:00:00 2001 From: ThuverX Date: Thu, 20 Mar 2025 21:11:09 +0100 Subject: [PATCH 15/30] x64 now works again --- .gitignore | 6 +- CMakeLists.txt | 29 +- basemod/lua/ea.lua | 35 +- libs/pugixml | 2 +- src/Common.h | 14 + src/Main.cpp | 21 +- src/assets/Asset.cpp | 9 + src/assets/Asset.h | 1 + src/assets/Assets.cpp | 49 ++- src/hashes/Hashes.cpp | 85 +++++ src/hashes/Hashes.h | 28 ++ src/hooks/LuaHook.cpp | 4 +- src/hooks/LuaHook.h | 2 +- src/modloader/ModLoader.cpp | 4 +- src/modloader/ModLoader.h | 2 - src/mods/Mod.cpp | 29 +- src/mods/Mod.h | 11 +- src/mods/Mods.h | 3 +- src/{ => platform/w32}/dsound.h | 2 +- src/platform/w64/wsock.def | 76 +++++ src/platform/w64/wsock.h | 107 ++++++ src/signatures/Signatures.cpp | 8 +- src/signatures/sigdef.h | 370 +++++++++++++++------ src/tweakers/SwarmTweaker/SwarmTweaker.cpp | 17 + src/tweakers/SwarmTweaker/SwarmTweaker.h | 21 ++ src/tweakers/Tweaker.cpp | 6 + src/tweakers/Tweaker.h | 18 + src/util/FNV.cpp | 4 +- src/util/FNV.h | 1 + src/util/Logger.h | 3 + 30 files changed, 823 insertions(+), 144 deletions(-) create mode 100644 src/Common.h create mode 100644 src/hashes/Hashes.cpp create mode 100644 src/hashes/Hashes.h rename src/{ => platform/w32}/dsound.h (98%) create mode 100644 src/platform/w64/wsock.def create mode 100644 src/platform/w64/wsock.h create mode 100644 src/tweakers/SwarmTweaker/SwarmTweaker.cpp create mode 100644 src/tweakers/SwarmTweaker/SwarmTweaker.h create mode 100644 src/tweakers/Tweaker.cpp create mode 100644 src/tweakers/Tweaker.h diff --git a/.gitignore b/.gitignore index 1b68a19..77e91ec 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,10 @@ cmake old run -cmake-build-debug-visual-studio -cmake-build-release-visual-studio +cmake-build-debug64-msvc +cmake-build-release64-msvc +cmake-build-debug32-msvc +cmake-build-release32-msvc src/Version.h .idea build/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ffcc35..eb47966 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,8 +11,8 @@ add_subdirectory(libs/minhook) add_subdirectory(libs/sigmatch) add_subdirectory(libs/pugixml) -add_library(MySimsModLoader SHARED src/Main.cpp - src/dsound.h +set(SOURCES + src/Main.cpp src/modloader/ModLoader.cpp src/modloader/ModLoader.h src/util/Logger.cpp @@ -40,8 +40,27 @@ add_library(MySimsModLoader SHARED src/Main.cpp src/hooks/LuaHook.cpp src/hooks/LuaHook.h src/include/hash_sha256.h + src/hashes/Hashes.cpp + src/hashes/Hashes.h + src/tweakers/SwarmTweaker/SwarmTweaker.cpp + src/tweakers/SwarmTweaker/SwarmTweaker.h + src/tweakers/Tweaker.cpp + src/tweakers/Tweaker.h + src/Common.h ) +if(CMAKE_GENERATOR_PLATFORM STREQUAL "x64") + list(APPEND SOURCES + src/platform/w64/wsock.def + src/platform/w64/wsock.h) + +else () + list(APPEND SOURCES + src/platform/w32/dsound.h) +endif () + +add_library(MySimsModLoader SHARED ${SOURCES}) + add_custom_target(version ${CMAKE_COMMAND} -D SRC=${CMAKE_SOURCE_DIR}/src/Version.h.in -D DST=${CMAKE_SOURCE_DIR}/src/Version.h @@ -57,4 +76,8 @@ target_include_directories(MySimsModLoader PRIVATE libs/sigmatch/include) target_link_libraries(MySimsModLoader PRIVATE minhook) target_link_libraries(MySimsModLoader PRIVATE pugixml-static) -set_target_properties(MySimsModLoader PROPERTIES OUTPUT_NAME "dsound") \ No newline at end of file +set_target_properties(MySimsModLoader PROPERTIES OUTPUT_NAME "dsound") + +if(CMAKE_GENERATOR_PLATFORM STREQUAL "x64") + set_target_properties(MySimsModLoader PROPERTIES OUTPUT_NAME "WSOCK32") +endif() \ No newline at end of file diff --git a/basemod/lua/ea.lua b/basemod/lua/ea.lua index 105bc4e..a8a77f3 100644 --- a/basemod/lua/ea.lua +++ b/basemod/lua/ea.lua @@ -12,7 +12,38 @@ if EA then [251] = "NONE" } - function EA:LogLevel(class, level, ... ) - print("[" .. levels[level] .. "]", unpack(arg)) + function EA:ShouldOutput(class, level) + return true + end + + function LogLevel(class, level, ... ) + if level ~= 25 then + print("[" .. class .. " " .. levels[level] .. "]", unpack(arg)) + end + end + + function EA:Log(class, ... ) + LogLevel(class, self._defaultLogLevel, unpack(arg)) + end + + function EA:Trace( class, ... ) + LogLevel(class, self._defaultLogLevel, unpack(arg)) + end + + function EA:LogI( class, ... ) + LogLevel(class, EA.kLevelInfo, unpack(arg)) + end + + function EA:LogD( class, ... ) + LogLevel(class, EA.kLevelDebug, unpack(arg)) + end + + + function EA:LogW( class, ... ) + LogLevel(class, EA.kLevelWarn, unpack(arg)) + end + + function EA:LogE( class,... ) + LogLevel(class, EA.kLevelError, unpack(arg)) end end \ No newline at end of file diff --git a/libs/pugixml b/libs/pugixml index 066b658..caade5a 160000 --- a/libs/pugixml +++ b/libs/pugixml @@ -1 +1 @@ -Subproject commit 066b6583a4abc3dab675e05380354603049aa2f8 +Subproject commit caade5a28aad86b92a4b5337a9dc70c4ba73c5eb diff --git a/src/Common.h b/src/Common.h new file mode 100644 index 0000000..5e7525a --- /dev/null +++ b/src/Common.h @@ -0,0 +1,14 @@ +// +// Created by exozg on 20/03/2025. +// + +#ifndef COMMON_H +#define COMMON_H + +#ifdef _WIN64 +#define CATCH_ECX +#else +#define CATCH_ECX ,void *_ECX +#endif + +#endif //COMMON_H diff --git a/src/Main.cpp b/src/Main.cpp index af99447..85b30db 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -3,29 +3,28 @@ // #include -#include "dsound.h" #include "modloader/modloader.h" #define SIG_DEFINE #include "signatures/sigdef.h" #undef SIG_DEFINE - -// TODO: This would be nice if it worked -LONG WINAPI CrashHandler(EXCEPTION_POINTERS* exceptionInfo) { - MSML_LOG_ERROR("MySims Crashed!"); - - return EXCEPTION_EXECUTE_HANDLER; -} +#ifdef _WIN64 +#include "platform/w64/wsock.h" +#else +#include "platform/w32/dsound.h" +#endif BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved) { if (reason == DLL_PROCESS_ATTACH) { - SetUnhandledExceptionFilter(CrashHandler); - char bufd[200]; GetSystemDirectoryA(bufd, 200); +#ifdef _WIN64 + strcat_s(bufd, "\\WSOCK32.dll"); +#else strcat_s(bufd, "\\dsound.dll"); +#endif ModLoader::GetInstance().Initialize(); @@ -33,7 +32,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved) { if (!hL) return false; - dsound(hL); + exports(hL); } return TRUE; diff --git a/src/assets/Asset.cpp b/src/assets/Asset.cpp index 68db933..c903b3f 100644 --- a/src/assets/Asset.cpp +++ b/src/assets/Asset.cpp @@ -17,3 +17,12 @@ DDFFileType Asset::GetFileType(const std::string& extension) { } return UNKNOWN; } + +std::string Asset::GetTypeName(const uint32_t value) { + for (const auto& [name, enumValue] : stringToEnum) { + if (static_cast(enumValue) == value) { + return name; + } + } + return "unknown"; +} \ No newline at end of file diff --git a/src/assets/Asset.h b/src/assets/Asset.h index 70d4335..d15e587 100644 --- a/src/assets/Asset.h +++ b/src/assets/Asset.h @@ -107,6 +107,7 @@ class Asset { std::filesystem::path path; static DDFFileType GetFileType(const std::string &extension); + static std::string GetTypeName(uint32_t value); }; diff --git a/src/assets/Assets.cpp b/src/assets/Assets.cpp index ce2cd27..a15c93a 100644 --- a/src/assets/Assets.cpp +++ b/src/assets/Assets.cpp @@ -7,15 +7,16 @@ #include #include -#include "../modloader/ModLoader.h" +#include "../hashes/Hashes.h" #include "../mods/Mods.h" +#include "../Common.h" Assets &Assets::GetInstance() { static Assets instance; return instance; } -void * __fastcall AddFileHooked(EA::ResourceMan::DatabaseDirectoryFiles::DatabaseDirectoryFiles *this_ptr, void *_ECX, +void * __fastcall AddFileHooked(EA::ResourceMan::DatabaseDirectoryFiles::DatabaseDirectoryFiles *this_ptr CATCH_ECX, const EA::ResourceMan::Key *key, const wchar_t *path, const wchar_t *name) { for (const auto asset: Assets::GetInstance().GetReplacersByPath(path)) { @@ -26,10 +27,12 @@ void * __fastcall AddFileHooked(EA::ResourceMan::DatabaseDirectoryFiles::Databas }; } + // MSML_LOG_DEBUG_HIDDEN("Loading %s", Hashes::ToHumanReadable(*key).c_str()); + return EA::ResourceMan::DatabaseDirectoryFiles::AddFileHook.Original(this_ptr, key, path, name); } -void * __fastcall GetResourceSystemResourceHooked(Revo::ResourceSystem::ResourceSystem *this_ptr, void *_ECX, +void * __fastcall GetResourceSystemResourceHooked(Revo::ResourceSystem::ResourceSystem *this_ptr CATCH_ECX, const EA::ResourceMan::Key &key, void **outResource, void *b, void *database, void *factory, const EA::ResourceMan::Key *key2, uint32_t f, uint32_t g, uint32_t h, @@ -47,11 +50,34 @@ void * __fastcall GetResourceSystemResourceHooked(Revo::ResourceSystem::Resource // TODO: if a file is not found, respond with a debug version of the file. So the game doesn't crash // mostly needed for models, materials and textures - return Revo::ResourceSystem::GetResourceHook.Original(this_ptr, modKey, outResource, b, database, factory, key2, f, + const auto ret = Revo::ResourceSystem::GetResourceHook.Original(this_ptr, modKey, outResource, b, database, factory, key2, f, g, h, i); + // if (ret != nullptr) { + // MSML_LOG_DEBUG_HIDDEN("Got: %s", Hashes::ToHumanReadable(modKey).c_str()); + // } + + return ret; } -void __fastcall ResourceSystemInitHooked(Revo::ResourceSystem::ResourceSystem *this_ptr, void *_ECX) { +// uint32_t __fastcall PFRecordReadRead(EA::ResourceMan::PFRecordRead::PFRecordRead* this_ptr, void* _ECX, void* data, uint32_t size) { +// auto ret = EA::ResourceMan::PFRecordRead::ReadHook.Original(this_ptr, data, size); +// auto* basePtr = reinterpret_cast(reinterpret_cast(this_ptr) - 48); +// +// MSML_LOG_DEBUG_HIDDEN("Reading %s", Hashes::ToHumanReadable(basePtr->key).c_str()); +// +// // TODO: How do we change this data?... +// // +// // if (basePtr->key.instance == SwarmTweaker::RootSwarmKey.instance && +// // basePtr->key.group == SwarmTweaker::RootSwarmKey.group && +// // basePtr->key.type == SwarmTweaker::RootSwarmKey.type) { +// // const auto strData = std::string(static_cast(data), size); +// // MSML_LOG_DEBUG("%s", strData.c_str()); +// // } +// +// return ret; +// } + +void __fastcall ResourceSystemInitHooked(Revo::ResourceSystem::ResourceSystem *this_ptr CATCH_ECX) { Assets::GetInstance().CreateDatabase(reinterpret_cast(this_ptr)); Revo::ResourceSystem::InitHook.Original(this_ptr); } @@ -60,6 +86,9 @@ void Assets::Install() { EA::ResourceMan::DatabaseDirectoryFiles::AddFileHook.Install(&AddFileHooked); Revo::ResourceSystem::GetResourceHook.Install(&GetResourceSystemResourceHooked); Revo::ResourceSystem::InitHook.Install(&ResourceSystemInitHooked); + + // EA::ResourceMan::PFRecordRead::ReadHook.Install(&PFRecordReadRead); + // Revo::SwarmResourceFactory::CreateResourceHook.Install(&SwarmResourceFactoryCreateResource); } void Assets::RegisterReplacer(const std::string &path, const EA::ResourceMan::Key *key) { @@ -69,9 +98,15 @@ void Assets::RegisterReplacer(const std::string &path, const EA::ResourceMan::Ke replacers.emplace_back(asset); } +#ifdef _WIN64 +constexpr size_t DATABASE_DIRECTORY_FILES_SIZE = 0xe8; +#else +constexpr size_t DATABASE_DIRECTORY_FILES_SIZE = 0x98; +#endif + void CreateDatabaseInternal(EA::ResourceMan::Manager::Manager *manager, const std::filesystem::path& path) { - auto *databaseStruct = static_cast(malloc(0x98)); + auto *databaseStruct = static_cast(malloc(DATABASE_DIRECTORY_FILES_SIZE)); auto *database = EA::ResourceMan::DatabaseDirectoryFiles::ctor( databaseStruct, path.wstring().c_str()); @@ -120,7 +155,7 @@ void CreateDatabaseInternal(EA::ResourceMan::Manager::Manager *manager, const st EA::ResourceMan::Manager::RegisterDatabase(manager, true, database, 1000); EA::ResourceMan::DatabaseDirectoryFiles::Init(database); - EA::ResourceMan::DatabaseDirectoryFiles::Open(database, IO::AccessFlags::Read, IO::CD::LoadAllFiles, false, + EA::ResourceMan::DatabaseDirectoryFiles::Open(database, EA::IO::AccessFlags::Read, EA::IO::CD::LoadAllFiles, false, false); // Maybe list the keys out here? instead of doing the add file hook? This way we can also programmatically call upon files diff --git a/src/hashes/Hashes.cpp b/src/hashes/Hashes.cpp new file mode 100644 index 0000000..00b0f42 --- /dev/null +++ b/src/hashes/Hashes.cpp @@ -0,0 +1,85 @@ +// +// Created by exozg on 12/03/2025. +// + +#include "Hashes.h" + +#include + +#include "../assets/Asset.h" +#include "../util/Logger.h" + +Hashes & Hashes::GetInstance() { + static Hashes instance; + return instance; +} + +std::string Hashes::GetHash64(const uint64_t hash) { + if (hashes64.contains(hash)) { + return hashes64.at(hash); + } + + return std::format("{:016x}", hash); +} + +std::string Hashes::GetHash32(const uint32_t hash) { + if (hashes32.contains(hash)) { + return hashes32.at(hash); + } + + return std::format("{:08x}", hash); +} + +#define READ_BIN(var) infile.read((char*)&var, sizeof(var)); +#define WRITE_BIN(var) outfile.write((char*)&var, sizeof(var)) + +#define READ_CSTRING(str) { \ + std::vector buffer; \ + char ch; \ + while (infile.read(&ch, 1) && ch != '\0') { \ + buffer.push_back(ch); \ + } \ + buffer.push_back('\0'); /* Ensure null termination */ \ + str = new char[buffer.size()]; \ + memcpy(str, buffer.data(), buffer.size()); \ +} + +#define WRITE_CSTRING(str) { \ + outfile.write(str, strlen(str) + 1); /* Write including null terminator */ \ +} + +void Hashes::Load(const std::string& path) { + std::ifstream infile(path, std::ios::in | std::ios::binary); + if (!infile.good()) { + MSML_LOG_ERROR("Failed to open %s", path.c_str()); + return; + } + hashes32.clear(); + hashes64.clear(); + uint64_t count; + READ_BIN(count); + + for (int i = 0; i < count; i++) { + char* text; + READ_CSTRING(text); + uint32_t fnv32; + READ_BIN(fnv32); + uint64_t fnv64; + READ_BIN(fnv64); + + hashes32.insert(std::pair(fnv32, text)); + hashes64.insert(std::pair(fnv64, text)); + } + + MSML_LOG_INFO("Loaded %d Hashes from %s", hashes32.size(), path.c_str()); +} + +std::string Hashes::ToHumanReadable(const EA::ResourceMan::Key &key) { + const std::string instance = GetInstance().GetHash64(key.instance); + const std::string type = Asset::GetTypeName(key.type); + const std::string group = GetInstance().GetHash32(key.group); + + if (key.group == 0) return instance + "." + type; + + return group + "/" + instance + "." + type; +} diff --git a/src/hashes/Hashes.h b/src/hashes/Hashes.h new file mode 100644 index 0000000..bdc8bc0 --- /dev/null +++ b/src/hashes/Hashes.h @@ -0,0 +1,28 @@ +// +// Created by exozg on 12/03/2025. +// + +#ifndef HASHES_H +#define HASHES_H + +#include +#include + +#include "../signatures/sigdef.h" + + +class Hashes { +public: + static Hashes& GetInstance(); + std::string GetHash64(uint64_t hash); + std::string GetHash32(uint32_t hash); + void Load(const std::string& path); + static std::string ToHumanReadable(const EA::ResourceMan::Key &key); +private: + std::unordered_map hashes32; + std::unordered_map hashes64; +}; + + + +#endif //HASHES_H diff --git a/src/hooks/LuaHook.cpp b/src/hooks/LuaHook.cpp index 3878dd4..24b8fbc 100644 --- a/src/hooks/LuaHook.cpp +++ b/src/hooks/LuaHook.cpp @@ -69,6 +69,8 @@ void __fastcall LuaScriptingSystemStartupHooked(EA::ScriptOs::LuaScriptingSystem lua_setglobal(L, "CodeRequire"); LuaHook::GetInstance().GlobalState = L; + + MSML_LOG_INFO("Lua hooked successfully!"); } void LuaHook::Require(const std::string& path) const { @@ -86,6 +88,6 @@ void LuaHook::Require(const std::string& path) const { } } -void LuaHook::Initialize() { +void LuaHook::Install() { EA::ScriptOs::LuaScriptingSystem::StartupHook.Install(&LuaScriptingSystemStartupHooked); } diff --git a/src/hooks/LuaHook.h b/src/hooks/LuaHook.h index 13c35d7..11e78ac 100644 --- a/src/hooks/LuaHook.h +++ b/src/hooks/LuaHook.h @@ -12,7 +12,7 @@ class LuaHook { public: static LuaHook &GetInstance(); void Require(const std::string& path) const; - void Initialize(); + void Install(); lua_State* GlobalState; }; diff --git a/src/modloader/ModLoader.cpp b/src/modloader/ModLoader.cpp index 1cfa1e4..7100832 100644 --- a/src/modloader/ModLoader.cpp +++ b/src/modloader/ModLoader.cpp @@ -10,6 +10,7 @@ #include "../mods/Mods.h" #include "../Version.h" +#include "../hashes/Hashes.h" #include "../hooks/LuaHook.h" #include "../signatures/sigdef.h" @@ -37,9 +38,10 @@ void ModLoader::Initialize() { return; #endif } + Hashes::GetInstance().Load("./hashes.bin"); Mods::GetInstance().Find(); Assets::GetInstance().Install(); - LuaHook::GetInstance().Initialize(); + LuaHook::GetInstance().Install(); Hooks::GetInstance().Enable(); } diff --git a/src/modloader/ModLoader.h b/src/modloader/ModLoader.h index d0d86fd..8ff4878 100644 --- a/src/modloader/ModLoader.h +++ b/src/modloader/ModLoader.h @@ -23,6 +23,4 @@ class ModLoader { Console console; }; - - #endif //MODLOADER_H diff --git a/src/mods/Mod.cpp b/src/mods/Mod.cpp index ce4cfe2..e7860e1 100644 --- a/src/mods/Mod.cpp +++ b/src/mods/Mod.cpp @@ -13,9 +13,28 @@ #include "../assets/Assets.h" #include "../hooks/LuaHook.h" #include "../signatures/Signatures.h" +#include "../tweakers/SwarmTweaker/SwarmTweaker.h" #include "../util/Logger.h" -Mod * Mod::fromXML(const std::string path) { +void Mod::TweakersFromXML(const pugi::xml_node modNode, Mod* mod) { + pugi::xml_node tweakersNode = modNode.child("Tweakers"); + if (!tweakersNode) return; + + for (pugi::xml_node tweakerNode: tweakersNode.children()) { + const auto name = tweakerNode.name(); + + if (strcmp(name, "SwarmTweaker") == 0) { + const auto swarmTweaker = new SwarmTweaker; + swarmTweaker->path = tweakerNode.attribute("path").as_string(); + + mod->tweakers.emplace_back(swarmTweaker); + + MSML_LOG_INFO("%s registered a SwarmTweaker", mod->name.c_str()); + } + } +} + +Mod * Mod::fromXML(const std::string &path) { const auto mod = new Mod; pugi::xml_document doc; @@ -115,6 +134,8 @@ Mod * Mod::fromXML(const std::string path) { MSML_LOG_INFO("%s registered %d hook(s)", mod->name.c_str(), hookCount); + TweakersFromXML(modNode, mod); + return mod; } @@ -129,3 +150,9 @@ void Mod::RunPreHooks() const { LuaHook::GetInstance().Require(hook); } } + +void Mod::ApplyTweaks(const EA::ResourceMan::Key& key) const { + for (const auto & tweaker : tweakers) { + tweaker->Apply(key); + } +} diff --git a/src/mods/Mod.h b/src/mods/Mod.h index ab10872..296c27e 100644 --- a/src/mods/Mod.h +++ b/src/mods/Mod.h @@ -5,9 +5,12 @@ #ifndef MOD_H #define MOD_H +#include #include #include +#include "../tweakers/Tweaker.h" + class Mod { public: std::string name; @@ -17,12 +20,18 @@ class Mod { std::string assetsPath; int priority = 0; - static Mod* fromXML(std::string path); + std::vector tweakers; + + static Mod* fromXML(const std::string &path); void RunPostHooks() const; void RunPreHooks() const; + void ApplyTweaks(const EA::ResourceMan::Key &key) const; + std::vector postHooks; std::vector preHooks; +private: + static void TweakersFromXML(pugi::xml_node modNode, Mod *mod); }; diff --git a/src/mods/Mods.h b/src/mods/Mods.h index f7a9875..e8d7371 100644 --- a/src/mods/Mods.h +++ b/src/mods/Mods.h @@ -8,12 +8,13 @@ #include #include "Mod.h" +#include "../tweakers/Tweaker.h" class Mods { public: static Mods& GetInstance(); void Find(); - std::vector GetModsSorted() const; + [[nodiscard]] std::vector GetModsSorted() const; std::vector mods; void RunPostHooks() const; void RunPreHooks() const; diff --git a/src/dsound.h b/src/platform/w32/dsound.h similarity index 98% rename from src/dsound.h rename to src/platform/w32/dsound.h index e5d0a1f..351b5d1 100644 --- a/src/dsound.h +++ b/src/platform/w32/dsound.h @@ -7,7 +7,7 @@ FARPROC p[12] = {nullptr}; -void dsound(HMODULE hL){ +void exports(HMODULE hL){ p[0] = GetProcAddress(hL, "DirectSoundCreate"); p[1] = GetProcAddress(hL, "DirectSoundEnumerateA"); p[2] = GetProcAddress(hL, "DirectSoundEnumerateW"); diff --git a/src/platform/w64/wsock.def b/src/platform/w64/wsock.def new file mode 100644 index 0000000..367f0d8 --- /dev/null +++ b/src/platform/w64/wsock.def @@ -0,0 +1,76 @@ +EXPORTS +__WSAFDIsSet=_WSOCK_EXPORT___WSAFDIsSet @151 +accept=_WSOCK_EXPORT_accept @1 +AcceptEx=_WSOCK_EXPORT_AcceptEx @1141 +bind=_WSOCK_EXPORT_bind @2 +closesocket=_WSOCK_EXPORT_closesocket @3 +connect=_WSOCK_EXPORT_connect @4 +dn_expand=_WSOCK_EXPORT_dn_expand @1106 +EnumProtocolsA=_WSOCK_EXPORT_EnumProtocolsA @1111 +EnumProtocolsW=_WSOCK_EXPORT_EnumProtocolsW @1112 +GetAcceptExSockaddrs=_WSOCK_EXPORT_GetAcceptExSockaddrs @1142 +GetAddressByNameA=_WSOCK_EXPORT_GetAddressByNameA @1109 +GetAddressByNameW=_WSOCK_EXPORT_GetAddressByNameW @1110 +gethostbyaddr=_WSOCK_EXPORT_gethostbyaddr @51 +gethostbyname=_WSOCK_EXPORT_gethostbyname @52 +gethostname=_WSOCK_EXPORT_gethostname @57 +GetNameByTypeA=_WSOCK_EXPORT_GetNameByTypeA @1115 +GetNameByTypeW=_WSOCK_EXPORT_GetNameByTypeW @1116 +getnetbyname=_WSOCK_EXPORT_getnetbyname @1101 +getpeername=_WSOCK_EXPORT_getpeername @5 +getprotobyname=_WSOCK_EXPORT_getprotobyname @53 +getprotobynumber=_WSOCK_EXPORT_getprotobynumber @54 +getservbyname=_WSOCK_EXPORT_getservbyname @55 +getservbyport=_WSOCK_EXPORT_getservbyport @56 +GetServiceA=_WSOCK_EXPORT_GetServiceA @1119 +GetServiceW=_WSOCK_EXPORT_GetServiceW @1120 +getsockname=_WSOCK_EXPORT_getsockname @6 +getsockopt=_WSOCK_EXPORT_getsockopt @7 +GetTypeByNameA=_WSOCK_EXPORT_GetTypeByNameA @1113 +GetTypeByNameW=_WSOCK_EXPORT_GetTypeByNameW @1114 +htonl=_WSOCK_EXPORT_htonl @8 +htons=_WSOCK_EXPORT_htons @9 +inet_addr=_WSOCK_EXPORT_inet_addr @10 +inet_network=_WSOCK_EXPORT_inet_network @1100 +inet_ntoa=_WSOCK_EXPORT_inet_ntoa @11 +ioctlsocket=_WSOCK_EXPORT_ioctlsocket @12 +listen=_WSOCK_EXPORT_listen @13 +MigrateWinsockConfiguration=_WSOCK_EXPORT_MigrateWinsockConfiguration @24 +NPLoadNameSpaces=_WSOCK_EXPORT_NPLoadNameSpaces @1130 +ntohl=_WSOCK_EXPORT_ntohl @14 +ntohs=_WSOCK_EXPORT_ntohs @15 +rcmd=_WSOCK_EXPORT_rcmd @1102 +recv=_WSOCK_EXPORT_recv @16 +recvfrom=_WSOCK_EXPORT_recvfrom @17 +rexec=_WSOCK_EXPORT_rexec @1103 +rresvport=_WSOCK_EXPORT_rresvport @1104 +s_perror=_WSOCK_EXPORT_s_perror @1108 +select=_WSOCK_EXPORT_select @18 +send=_WSOCK_EXPORT_send @19 +sendto=_WSOCK_EXPORT_sendto @20 +sethostname=_WSOCK_EXPORT_sethostname @1105 +SetServiceA=_WSOCK_EXPORT_SetServiceA @1117 +SetServiceW=_WSOCK_EXPORT_SetServiceW @1118 +setsockopt=_WSOCK_EXPORT_setsockopt @21 +shutdown=_WSOCK_EXPORT_shutdown @22 +socket=_WSOCK_EXPORT_socket @23 +TransmitFile=_WSOCK_EXPORT_TransmitFile @1140 +WEP=_WSOCK_EXPORT_WEP @500 +WSAAsyncGetHostByAddr=_WSOCK_EXPORT_WSAAsyncGetHostByAddr @102 +WSAAsyncGetHostByName=_WSOCK_EXPORT_WSAAsyncGetHostByName @103 +WSAAsyncGetProtoByName=_WSOCK_EXPORT_WSAAsyncGetProtoByName @105 +WSAAsyncGetProtoByNumber=_WSOCK_EXPORT_WSAAsyncGetProtoByNumber @104 +WSAAsyncGetServByName=_WSOCK_EXPORT_WSAAsyncGetServByName @107 +WSAAsyncGetServByPort=_WSOCK_EXPORT_WSAAsyncGetServByPort @106 +WSAAsyncSelect=_WSOCK_EXPORT_WSAAsyncSelect @101 +WSACancelAsyncRequest=_WSOCK_EXPORT_WSACancelAsyncRequest @108 +WSACancelBlockingCall=_WSOCK_EXPORT_WSACancelBlockingCall @113 +WSACleanup=_WSOCK_EXPORT_WSACleanup @116 +WSAGetLastError=_WSOCK_EXPORT_WSAGetLastError @111 +WSAIsBlocking=_WSOCK_EXPORT_WSAIsBlocking @114 +WSApSetPostRoutine=_WSOCK_EXPORT_WSApSetPostRoutine @1000 +WSARecvEx=_WSOCK_EXPORT_WSARecvEx @1107 +WSASetBlockingHook=_WSOCK_EXPORT_WSASetBlockingHook @109 +WSASetLastError=_WSOCK_EXPORT_WSASetLastError @112 +WSAStartup=_WSOCK_EXPORT_WSAStartup @115 +WSAUnhookBlockingHook=_WSOCK_EXPORT_WSAUnhookBlockingHook @110 diff --git a/src/platform/w64/wsock.h b/src/platform/w64/wsock.h new file mode 100644 index 0000000..36f03f7 --- /dev/null +++ b/src/platform/w64/wsock.h @@ -0,0 +1,107 @@ +// +// Created by exozg on 19/03/2025. +// +#pragma once + +#pragma pack(1) + +// taken from https://gitlab.com/znixian/payday2-superblt/-/blob/master/platforms/w32/loader/wsock.cpp?ref_type=heads + +#pragma region ALLFUNC(FUNC) + +#define ALLFUNC(FUNC) \ + FUNC(0,__WSAFDIsSet,151) \ + FUNC(1,accept,1) \ + FUNC(2,AcceptEx,1141) \ + FUNC(3,bind,2) \ + FUNC(4,closesocket,3) \ + FUNC(5,connect,4) \ + FUNC(6,dn_expand,1106) \ + FUNC(7,EnumProtocolsA,1111) \ + FUNC(8,EnumProtocolsW,1112) \ + FUNC(9,GetAcceptExSockaddrs,1142) \ + FUNC(10,GetAddressByNameA,1109) \ + FUNC(11,GetAddressByNameW,1110) \ + FUNC(12,gethostbyaddr,51) \ + FUNC(13,gethostbyname,52) \ + FUNC(14,gethostname,57) \ + FUNC(15,GetNameByTypeA,1115) \ + FUNC(16,GetNameByTypeW,1116) \ + FUNC(17,getnetbyname,1101) \ + FUNC(18,getpeername,5) \ + FUNC(19,getprotobyname,53) \ + FUNC(20,getprotobynumber,54) \ + FUNC(21,getservbyname,55) \ + FUNC(22,getservbyport,56) \ + FUNC(23,GetServiceA,1119) \ + FUNC(24,GetServiceW,1120) \ + FUNC(25,getsockname,6) \ + FUNC(26,getsockopt,7) \ + FUNC(27,GetTypeByNameA,1113) \ + FUNC(28,GetTypeByNameW,1114) \ + FUNC(29,htonl,8) \ + FUNC(30,htons,9) \ + FUNC(31,inet_addr,10) \ + FUNC(32,inet_network,1100) \ + FUNC(33,inet_ntoa,11) \ + FUNC(34,ioctlsocket,12) \ + FUNC(35,listen,13) \ + FUNC(36,MigrateWinsockConfiguration,24) \ + FUNC(37,NPLoadNameSpaces,1130) \ + FUNC(38,ntohl,14) \ + FUNC(39,ntohs,15) \ + FUNC(40,rcmd,1102) \ + FUNC(41,recv,16) \ + FUNC(42,recvfrom,17) \ + FUNC(43,rexec,1103) \ + FUNC(44,rresvport,1104) \ + FUNC(45,s_perror,1108) \ + FUNC(46,select,18) \ + FUNC(47,send,19) \ + FUNC(48,sendto,20) \ + FUNC(49,sethostname,1105) \ + FUNC(50,SetServiceA,1117) \ + FUNC(51,SetServiceW,1118) \ + FUNC(52,setsockopt,21) \ + FUNC(53,shutdown,22) \ + FUNC(54,socket,23) \ + FUNC(55,TransmitFile,1140) \ + FUNC(56,WEP,500) \ + FUNC(57,WSAAsyncGetHostByAddr,102) \ + FUNC(58,WSAAsyncGetHostByName,103) \ + FUNC(59,WSAAsyncGetProtoByName,105) \ + FUNC(60,WSAAsyncGetProtoByNumber,104) \ + FUNC(61,WSAAsyncGetServByName,107) \ + FUNC(62,WSAAsyncGetServByPort,106) \ + FUNC(63,WSAAsyncSelect,101) \ + FUNC(64,WSACancelAsyncRequest,108) \ + FUNC(65,WSACancelBlockingCall,113) \ + FUNC(66,WSACleanup,116) \ + FUNC(67,WSAGetLastError,111) \ + FUNC(68,WSAIsBlocking,114) \ + FUNC(69,WSApSetPostRoutine,1000) \ + FUNC(70,WSARecvEx,1107) \ + FUNC(71,WSASetBlockingHook,109) \ + FUNC(72,WSASetLastError,112) \ + FUNC(73,WSAStartup,115) \ + FUNC(74,WSAUnhookBlockingHook,110) \ + +#define ALLFUNC_COUNT 75 + +#pragma endregion + +FARPROC p[ALLFUNC_COUNT] = {nullptr}; + +void exports(HMODULE hL){ +#define REGISTER(num, name, ordinal) p[num] = GetProcAddress(hL, #name); + ALLFUNC(REGISTER); +#undef REGISTER +} + +#define DEF_STUB(num, name, ordinal) \ +extern "C" void _WSOCK_EXPORT_##name() { \ +static void (*func)() = (void(*)())p[num]; \ +func(); \ +} +ALLFUNC(DEF_STUB) +#undef DEF_STUB diff --git a/src/signatures/Signatures.cpp b/src/signatures/Signatures.cpp index a28b8e1..3387c00 100644 --- a/src/signatures/Signatures.cpp +++ b/src/signatures/Signatures.cpp @@ -128,7 +128,7 @@ bool Signatures::LoadDatabase() { auto name_str = std::string(name, length); - uint32_t addr; + uintptr_t addr; READ_BIN(addr); if (signatures.contains(name_str)) { @@ -149,7 +149,7 @@ void Signatures::SaveDatabase() { std::ofstream outfile(SIGCACHE_DB_NAME, std::ios::out | std::ios::binary); std::array checksum = GetCheckSum(); - uint32_t count = signatures.size(); + size_t count = signatures.size(); for (auto i = 0; i < 32U; i++) { WRITE_BIN(checksum[i]); @@ -158,8 +158,8 @@ void Signatures::SaveDatabase() { for (const auto &sig: signatures) { std::string name = sig.first; - uint32_t length = name.length(); - auto addr = reinterpret_cast(sig.second->GetAddress()); + size_t length = name.length(); + auto addr = reinterpret_cast(sig.second->GetAddress()); WRITE_BIN(length); outfile.write(name.c_str(), length); diff --git a/src/signatures/sigdef.h b/src/signatures/sigdef.h index 8a93ba0..a8564c0 100644 --- a/src/signatures/sigdef.h +++ b/src/signatures/sigdef.h @@ -12,6 +12,8 @@ #include +#pragma pack(push, 1) + namespace EA::ResourceMan { struct Key; } @@ -19,44 +21,70 @@ namespace EA::ResourceMan { using namespace sigmatch_literals; #ifdef SIG_DEFINE -#define CREATE_NORMAL_CALLABLE_SIGNATURE(name, ns, retn, signature, offset, ...) \ +#ifdef _WIN64 + +#define CREATE_NORMAL_CALLABLE_SIGNATURE(name, ns, retn, signature, signature64, offset, ...) \ typedef retn(*name ## ptr)(__VA_ARGS__); \ name ## ptr name = nullptr; \ - SigSearch name ## Hook(#ns "::" #name, signature ## _sig, (void*&)name, offset, false); + SigSearch name ## Hook(#ns "::" #name, signature64 ## _sig, (void*&)name, offset, false); \ -#define CREATE_NORMAL_CALLABLE_SIGNATURE_FIRST(name, ns, retn, signature, offset, ...) \ +#define CREATE_NORMAL_CALLABLE_SIGNATURE_FIRST(name, ns, retn, signature, signature64, offset, ...) \ typedef retn(*name ## ptr)(__VA_ARGS__); \ name ## ptr name = nullptr; \ - SigSearch name ## Hook(#ns "::" #name, signature ## _sig, (void*&)name, offset, true); + SigSearch name ## Hook(#ns "::" #name, signature64 ## _sig, (void*&)name, offset, true); \ -#define CREATE_MEMBER_CALLABLE_SIGNATURE(name, ns, retn, signature, offset, ...) \ +#define CREATE_MEMBER_CALLABLE_SIGNATURE(name, ns, retn, signature, signature64, offset, ...) \ typedef retn(__thiscall *name ## ptr)(ns* this_ptr, __VA_ARGS__); \ name ## ptr name = nullptr; \ - SigSearch name ## Hook(#ns "::" #name, signature ## _sig, (void*&)name, offset, false); + SigSearch name ## Hook(#ns "::" #name, signature64 ## _sig, (void*&)name, offset, false); \ -#define CREATE_MEMBER_CALLABLE_SIGNATURE_FIRST(name, ns, retn, signature, offset, ...) \ +#define CREATE_MEMBER_CALLABLE_SIGNATURE_FIRST(name, ns, retn, signature, signature64, offset, ...) \ typedef retn(__thiscall *name ## ptr)(ns* this_ptr, __VA_ARGS__); \ name ## ptr name = nullptr; \ - SigSearch name ## Hook(#ns "::" #name, signature ## _sig, (void*&)name, offset, true); + SigSearch name ## Hook(#ns "::" #name, signature64 ## _sig, (void*&)name, offset, true); \ #else -#define CREATE_NORMAL_CALLABLE_SIGNATURE(name, ns, retn, signature, offset, ...) \ +#define CREATE_NORMAL_CALLABLE_SIGNATURE(name, ns, retn, signature, signature64, offset, ...) \ + typedef retn(*name ## ptr)(__VA_ARGS__); \ + name ## ptr name = nullptr; \ + SigSearch name ## Hook(#ns "::" #name, signature ## _sig, (void*&)name, offset, false); \ + +#define CREATE_NORMAL_CALLABLE_SIGNATURE_FIRST(name, ns, retn, signature, signature64, offset, ...) \ + typedef retn(*name ## ptr)(__VA_ARGS__); \ + name ## ptr name = nullptr; \ + SigSearch name ## Hook(#ns "::" #name, signature ## _sig, (void*&)name, offset, true); \ + +#define CREATE_MEMBER_CALLABLE_SIGNATURE(name, ns, retn, signature, signature64, offset, ...) \ + typedef retn(__thiscall *name ## ptr)(ns* this_ptr, __VA_ARGS__); \ + name ## ptr name = nullptr; \ + SigSearch name ## Hook(#ns "::" #name, signature ## _sig, (void*&)name, offset, false); \ + +#define CREATE_MEMBER_CALLABLE_SIGNATURE_FIRST(name, ns, retn, signature, signature64, offset, ...) \ + typedef retn(__thiscall *name ## ptr)(ns* this_ptr, __VA_ARGS__); \ + name ## ptr name = nullptr; \ + SigSearch name ## Hook(#ns "::" #name, signature ## _sig, (void*&)name, offset, true); \ + +#endif + +#else + +#define CREATE_NORMAL_CALLABLE_SIGNATURE(name, ns, retn, signature, signature64, offset, ...) \ typedef retn(*name ## ptr)(__VA_ARGS__); \ extern name ## ptr name; \ extern SigSearch name ## Hook; -#define CREATE_NORMAL_CALLABLE_SIGNATURE_FIRST(name, ns, retn, signature, offset, ...) \ +#define CREATE_NORMAL_CALLABLE_SIGNATURE_FIRST(name, ns, retn, signature, signature64, offset, ...) \ typedef retn(*name ## ptr)(__VA_ARGS__); \ extern name ## ptr name; \ extern SigSearch name ## Hook; -#define CREATE_MEMBER_CALLABLE_SIGNATURE(name, ns, retn, signature, offset, ...) \ +#define CREATE_MEMBER_CALLABLE_SIGNATURE(name, ns, retn, signature, signature64, offset, ...) \ typedef retn(__thiscall *name ## ptr)(ns* this_ptr, __VA_ARGS__); \ extern name ## ptr name; \ extern SigSearch name ## Hook; -#define CREATE_MEMBER_CALLABLE_SIGNATURE_FIRST(name, ns, retn, signature, offset, ...) \ +#define CREATE_MEMBER_CALLABLE_SIGNATURE_FIRST(name, ns, retn, signature, signature64, offset, ...) \ typedef retn(__thiscall *name ## ptr)(ns* this_ptr, __VA_ARGS__); \ extern name ## ptr name; \ extern SigSearch name ## Hook; @@ -66,23 +94,30 @@ using namespace sigmatch_literals; class SigSearchBase { public: virtual ~SigSearchBase() = default; + [[nodiscard]] virtual bool Search() const = 0; + [[nodiscard]] virtual std::string GetName() const = 0; - [[nodiscard]] virtual void* GetAddress() const = 0; - virtual void ApplyAddress(void* addr) const = 0; + + [[nodiscard]] virtual void *GetAddress() const = 0; + + virtual void ApplyAddress(void *addr) const = 0; }; -template -class SigSearch: public SigSearchBase { + + +template +class SigSearch : public SigSearchBase { public: std::string name; sigmatch::signature signature; - void*& address; + void *&address; OriginalFuncPtr Original = nullptr; uint32_t offset; bool first = false; - SigSearch(const std::string &name, const sigmatch::signature &sig, void*& address, const int offset, bool first): name(name), signature(sig), address(address), offset(offset), first(first) { + SigSearch(const std::string &name, const sigmatch::signature &sig, void *&address, const int offset, + bool first): name(name), signature(sig), address(address), offset(offset), first(first) { Signatures::GetInstance().Append(name, this); } @@ -91,7 +126,7 @@ class SigSearch: public SigSearchBase { MSML_LOG_ERROR("Failed to find an address for %s", name.c_str()); return false; } - MSML_LOG_DEBUG("Found %s 0x%x", name.c_str(), address); + MSML_LOG_DEBUG("Found %s %p", name.c_str(), address); return true; } @@ -99,7 +134,7 @@ class SigSearch: public SigSearchBase { return name; } - [[nodiscard]] void* GetAddress() const override { + [[nodiscard]] void *GetAddress() const override { return address; } @@ -108,51 +143,79 @@ class SigSearch: public SigSearchBase { } void Install(void *detour) { - Hooks::GetInstance().Install(address, detour, reinterpret_cast(&Original)); + Hooks::GetInstance().Install(address, detour, reinterpret_cast(&Original)); } }; +namespace Revo { + namespace ResourceSystem { + struct ResourceSystem { + }; -namespace IO { - enum class AccessFlags : int - { - /// No specified flags. Also used to indicate that a given IO stream is closed. - None = 0x00, - /// Used for identifying read access to an entity. - Read = 0x01, - /// Used for identifying write access to an entity. - Write = 0x02, - /// Used for identifying both read and write access to an entity. - ReadWrite = 0x03 - }; - - /// Creation disposition. Specifies aspects of how to create or not create a file during opening of it. - enum class CD : int - { - /// Fails if file already exists. - CreateNew = 1, - /// Never fails, always opens or creates and truncates to 0. - CreateAlways = 2, - /// Fails if file doesn't exist, keeps contents. - OpenExisting = 3, - /// Never fails, creates if doesn't exist, keeps contents. - OpenAlways = 4, - /// Fails if file doesn't exist, but truncates to 0 if it does. - TruncateExisting = 5, - /// Default (implementation-specific) disposition - Default = 6, - // Specific to MySims - LoadAllFiles = 7, - }; -} + // CREATE_MEMBER_CALLABLE_SIGNATURE(LoadPackage, ResourceSystem, void, "83 EC 24 53 55 56 57 8B 7C 24 38 6A 01 8B E9 68 C5 9D 1C 81", "", 0, const wchar_t* name, const wchar_t* path); + + CREATE_MEMBER_CALLABLE_SIGNATURE(GetResource, ResourceSystem, void*, + "53 8B 5C 24 1C 85 DB 56 57 8B F1 8B C3 ?? ?? 8B 44 24 10 8B 16", + "48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 48 89 7C 24 20 41 54 41 56 41 57 48 83 EC 60 4D 8B E1 49 8B F0 48 8B EA 4C 8B F1 48 8D 0D 4C 4B 84 00 ?? ?? ?? ?? ?? 49", + 0, const EA::ResourceMan::Key& key, void**, void*, void* database, + void* factory, const EA::ResourceMan::Key*, uint32_t, uint32_t, uint32_t, + uint32_t); + CREATE_MEMBER_CALLABLE_SIGNATURE(Init, ResourceSystem, void, + "81 EC 20 02 00 00 A1 C0 44 02 01 33 C4 89 84 24 1C 02 00 00 56 8B F1 ?? ?? ?? ?? ?? 84 C0 ?? ?? 32", + "40 55 57 48 8D AC 24 D8 FD FF FF 48 81 EC 28 03 00 00 48 8B 05 77 FE", 0); + } + + namespace SwarmResourceFactory { + struct SwarmResourceFactory { + }; -namespace Revo::ResourceSystem { - struct ResourceSystem{}; - CREATE_MEMBER_CALLABLE_SIGNATURE(GetResource, ResourceSystem, void*,"53 8B 5C 24 1C 85 DB 56 57 8B F1 8B C3 ?? ?? 8B 44 24 10 8B 16", 0, const EA::ResourceMan::Key& key, void** ,void*,void* database,void* factory,const EA::ResourceMan::Key*,uint32_t,uint32_t,uint32_t,uint32_t); - CREATE_MEMBER_CALLABLE_SIGNATURE(LoadPackage, ResourceSystem, void, "83 EC 24 53 55 56 57 8B 7C 24 38 6A 01 8B E9 68 C5 9D 1C 81", 0, const wchar_t* name, const wchar_t* path); - CREATE_MEMBER_CALLABLE_SIGNATURE(Init, ResourceSystem,void,"81 EC 20 02 00 00 A1 C0 44 02 01 33 C4 89 84 24 1C 02 00 00 56 8B F1 ?? ?? ?? ?? ?? 84 C0 ?? ?? 32", 0); + // CREATE_MEMBER_CALLABLE_SIGNATURE(CreateResource, SwarmResourceFactory, void*, + // "53 55 8B 6C 24 0C 8B 45 00 8B 50 04 56 8B D9 57 8B CD ?? ?? 8B 78 08 81 FF 96 E3 52 97", + // "", 0, void*, void**, void*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); + } } + namespace EA { + namespace IO { + namespace MemoryStream { + struct MemoryStream { + void *vtable; + void *data; + uint8_t padding2[0x4]; + uint32_t size; + }; + } + + enum class AccessFlags : int { + /// No specified flags. Also used to indicate that a given IO stream is closed. + None = 0x00, + /// Used for identifying read access to an entity. + Read = 0x01, + /// Used for identifying write access to an entity. + Write = 0x02, + /// Used for identifying both read and write access to an entity. + ReadWrite = 0x03 + }; + + /// Creation disposition. Specifies aspects of how to create or not create a file during opening of it. + enum class CD : int { + /// Fails if file already exists. + CreateNew = 1, + /// Never fails, always opens or creates and truncates to 0. + CreateAlways = 2, + /// Fails if file doesn't exist, keeps contents. + OpenExisting = 3, + /// Never fails, creates if doesn't exist, keeps contents. + OpenAlways = 4, + /// Fails if file doesn't exist, but truncates to 0 if it does. + TruncateExisting = 5, + /// Default (implementation-specific) disposition + Default = 6, + /// Specific to MySims + LoadAllFiles = 7, + }; + } + namespace ResourceMan { struct Key { uint64_t instance; @@ -161,80 +224,181 @@ namespace EA { }; namespace Database { - struct Database{}; + struct Database { + }; } namespace DatabasePackedFile { - struct DatabasePackedFile {}; + struct DatabasePackedFile { + }; }; namespace Manager { - struct Manager {}; - CREATE_NORMAL_CALLABLE_SIGNATURE(GetManager, Manager, Manager*, "a1 ?? ?? ?? ?? c3 cc cc cc cc cc cc cc cc cc cc 8b 4c 24 04 a1 c4 5b 09 01 89 0d c4 5b 09 01", 0); - CREATE_MEMBER_CALLABLE_SIGNATURE(GetResource, Manager, void*,"83 EC 10 53 56 32 DB 38 5C 24 1C 57 8B F1 ?? ?? 8B 7C 24 38 85 FF", 0, bool,const Key& key, void**, void*, void* database, void* factory, const Key*, uint32_t, uint32_t, uint32_t, uint32_t); - CREATE_MEMBER_CALLABLE_SIGNATURE(RegisterDatabase, Manager, void, "83 EC 10 53 55 56 57 8B F9 8D 4F 48 68 ?? 95 E7 00 89 4C 24 18 ?? ?? ?? ?? ?? 80 7C 24 24", 0, bool add, void* pDatabase, uint32_t priority); + struct Manager { + }; + + // CREATE_NORMAL_CALLABLE_SIGNATURE(GetManager, Manager, Manager*, "a1 ?? ?? ?? ?? c3 cc cc cc cc cc cc cc cc cc cc 8b 4c 24 04 a1 c4 5b 09 01 89 0d c4 5b 09 01", "", 0); + // CREATE_MEMBER_CALLABLE_SIGNATURE(GetResource, Manager, void*, + // "83 EC 10 53 56 32 DB 38 5C 24 1C 57 8B F1 ?? ?? 8B 7C 24 38 85 FF", "", 0, + // bool, const Key& key, void**, void*, void* database, void* factory, + // const Key*, uint32_t, uint32_t, uint32_t, uint32_t); + CREATE_MEMBER_CALLABLE_SIGNATURE(RegisterDatabase, Manager, void, + "83 EC 10 53 55 56 57 8B F9 8D 4F 48 68 ?? 95 E7 00 89 4C 24 18 ?? ?? ?? ?? ?? 80 7C 24 24", + "48 89 5C 24 10 48 89 6C 24 18 56 57 41 54 41 56 41 57 48 83 EC 40 41 8B E9 49 8B F0 0F", + 0, bool add, void* pDatabase, uint32_t priority); } namespace DatabaseDirectoryFiles { - struct DatabaseDirectoryFiles{}; - CREATE_MEMBER_CALLABLE_SIGNATURE(ctor, DatabaseDirectoryFiles, DatabaseDirectoryFiles*, "53 56 8B F1 57 C7 06 94 4A E5 00 33 C0 8D 4E 04 87 01 C7 06", 0, const wchar_t* path); - CREATE_MEMBER_CALLABLE_SIGNATURE(AddRef, DatabaseDirectoryFiles, void, "83 c1 04 b8 01 00 00 00 f0 0f c1 01 40 c3 cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc b8 40 e2 b6 04", 0); - CREATE_MEMBER_CALLABLE_SIGNATURE(Init, DatabaseDirectoryFiles, void, "80 79 08 00 b0 01 75 03 88 41 08 c3 cc cc cc cc 80 79 08 00 74 0b 8b 01", 0); - CREATE_MEMBER_CALLABLE_SIGNATURE(Open, DatabaseDirectoryFiles, void, "53 56 8b f1 80 7e 08 00 57 74 55", 0, IO::AccessFlags access_flags, IO::CD creation_disposition, bool, bool); - CREATE_MEMBER_CALLABLE_SIGNATURE(AddFile, DatabaseDirectoryFiles, void*, "83 EC 68 8B 44 24 70 56 6A 02 50 8B F1 ?? ?? ?? ?? ?? 8B 8C 24 80 00 00 00 83 C4 08 52 50 51", 0, const Key*, const wchar_t*, const wchar_t*); - CREATE_MEMBER_CALLABLE_SIGNATURE(Attach, DatabaseDirectoryFiles, void, "53 55 56 33 DB 38 5C 24 10 57 8B F1 ?? ?? ?? ?? ?? ?? 8B 46 5C 3B C3 8B 7C 24 18", 0, bool, void* pResourceMan, bool); - CREATE_MEMBER_CALLABLE_SIGNATURE(AddExtensionMapping, DatabaseDirectoryFiles, void, "83 EC 28 53 55 56 8B E9 57 8D 7D 68 68 ?? 8D E7 00 8B CF 89 7C 24 14 ?? ?? ?? ?? ?? 8B", 0, const wchar_t* extension, uint32_t type); - - CREATE_MEMBER_CALLABLE_SIGNATURE(UpdateRecordData, DatabaseDirectoryFiles, void,"83 ec 20 53 57 8b f9 33 db 38 5f 08 0f 84 a3 00 00 00 8b 47 10 50", 0, void* eastl_vector); - CREATE_MEMBER_CALLABLE_SIGNATURE(UpdateRecordData2, DatabaseDirectoryFiles, void,"81 ec 44 08 00 00 a1 ?? ?? ?? ?? 33 c4 89 84 24 40 08 00 00 8b 84 24 4c 08 00 00 53 55 56 57", 0, const wchar_t* path, void* eastl_vector); + struct DatabaseDirectoryFiles { + }; + + CREATE_MEMBER_CALLABLE_SIGNATURE(ctor, DatabaseDirectoryFiles, DatabaseDirectoryFiles*, + "53 56 8B F1 57 C7 06 94 4A E5 00 33 C0 8D 4E 04 87 01 C7 06", + "48 89 5C 24 10 48 89 74 24 18 48 89 4C 24 08 57 48 83 EC 20 48 8B FA 48 8B D9 48 8D 0D 9F BB AF 00 ?? ?? ?? ?? ?? 48 8D 05 3B", + 0, + const wchar_t* path); + // CREATE_MEMBER_CALLABLE_SIGNATURE(AddRef, DatabaseDirectoryFiles, void, + // "83 c1 04 b8 01 00 00 00 f0 0f c1 01 40 c3 cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc b8 40 e2 b6 04", + // "", 0); + CREATE_MEMBER_CALLABLE_SIGNATURE(Init, DatabaseDirectoryFiles, void, + "80 79 08 00 b0 01 75 03 88 41 08 c3 cc cc cc cc 80 79 08 00 74 0b 8b 01", + "40 53 48 83 EC 20 48 8B D9 48 8D 0D 10 7D AF 00 ?? ?? ?? ?? ?? 80 7B 10 00 B0 01 ?? ?? 88 43 10", + 0); + CREATE_MEMBER_CALLABLE_SIGNATURE(Open, DatabaseDirectoryFiles, void, "53 56 8b f1 80 7e 08 00 57 74 55", + "48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 20 48 8B F9 41 8B F0 48 8D 0D 9F 7B AF 00 8B EA", + 0, IO::AccessFlags access_flags, IO::CD creation_disposition, bool, bool); + CREATE_MEMBER_CALLABLE_SIGNATURE(AddFile, DatabaseDirectoryFiles, void*, + "83 EC 68 8B 44 24 70 56 6A 02 50 8B F1 ?? ?? ?? ?? ?? 8B 8C 24 80 00 00 00 83 C4 08 52 50 51", + "48 89 5C 24 10 48 89 74 24 18 55 57 41 56 48 8D 6C 24 B9 48 81 EC C0 00 00 00 49", + 0, const Key*, const wchar_t*, const wchar_t*); + CREATE_MEMBER_CALLABLE_SIGNATURE(Attach, DatabaseDirectoryFiles, void, + "53 55 56 33 DB 38 5C 24 10 57 8B F1 ?? ?? ?? ?? ?? ?? 8B 46 5C 3B C3 8B 7C 24 18", + "48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 41 56 41 57 48 83 EC 20 4C 8B F1 45 0F B6 F9", + 0, bool, void* pResourceMan, bool); + CREATE_MEMBER_CALLABLE_SIGNATURE(AddExtensionMapping, DatabaseDirectoryFiles, void, + "83 EC 28 53 55 56 8B E9 57 8D 7D 68 68 ?? 8D E7 00 8B CF 89 7C 24 14 ?? ?? ?? ?? ?? 8B", + "44 89 44 24 18 48 89 4C 24 08 55 53 56 57 41 54 41 55 41 56 41 57 48 8B EC 48 83 EC 78", + 0, const wchar_t* extension, uint32_t type); + + // CREATE_MEMBER_CALLABLE_SIGNATURE(UpdateRecordData, DatabaseDirectoryFiles, void,"83 ec 20 53 57 8b f9 33 db 38 5f 08 0f 84 a3 00 00 00 8b 47 10 50", "", 0, void* eastl_vector); + // CREATE_MEMBER_CALLABLE_SIGNATURE(UpdateRecordData2, DatabaseDirectoryFiles, void,"81 ec 44 08 00 00 a1 ?? ?? ?? ?? 33 c4 89 84 24 40 08 00 00 8b 84 24 4c 08 00 00 53 55 56 57", "", 0, const wchar_t* path, void* eastl_vector); + } + namespace PFRecordBase { + struct PFRecordBase { + void *vtable; + uint8_t padding[0x12]; + Key key; + }; } namespace PFRecordRead { - struct PFRecordRead {}; - CREATE_MEMBER_CALLABLE_SIGNATURE(PFRecordRead_1, PFRecordRead, void*, "56 8B F1 C7 06 04 E7 E4 00 33 C0 8D 4E 04 87 01 8B 44 24 10 C7", 0, uint32_t, uint32_t, Key*, DatabasePackedFile::DatabasePackedFile*); - CREATE_MEMBER_CALLABLE_SIGNATURE(PFRecordRead_2, PFRecordRead, void*, "56 8B F1 57 C7 06 04 E7 E4 00 33 C0 8D 4E 04 87 01 8B 44 24 18 8B", 0, void*, uint32_t, bool, Key*, DatabasePackedFile::DatabasePackedFile*); + struct PFRecordRead { + void *vtable; + // uint8_t padding[0x4]; + // IO::MemoryStream::MemoryStream stream; + }; + + // CREATE_MEMBER_CALLABLE_SIGNATURE(PFRecordRead_1, PFRecordRead, void*, + // "56 8B F1 C7 06 04 E7 E4 00 33 C0 8D 4E 04 87 01 8B 44 24 10 C7", "", 0, + // uint32_t, uint32_t, Key*, DatabasePackedFile::DatabasePackedFile*); + // CREATE_MEMBER_CALLABLE_SIGNATURE(PFRecordRead_2, PFRecordRead, void*, + // "56 8B F1 57 C7 06 04 E7 E4 00 33 C0 8D 4E 04 87 01 8B 44 24 18 8B", "", 0, + // void*, uint32_t, bool, Key*, DatabasePackedFile::DatabasePackedFile*); + // CREATE_MEMBER_CALLABLE_SIGNATURE(Read, PFRecordRead, uint32_t, "53 56 8B F1 8B 5E 2C 85 DB ?? ?? 57 83 CF FF 83 7E FC 00 ?? ?? 8B 46 30 8B 7C", "", 0, void*, uint32_t); } namespace DDFRecord { - struct DDFRecord {}; - CREATE_MEMBER_CALLABLE_SIGNATURE(ctor, DDFRecord, void*, "56 8B F1 57 C7 06 04 E7 E4 00 33 C0 8D 4E 04 87 01 8D 7E", 0, void*, const Key*) + struct DDFRecord { + }; + + // CREATE_MEMBER_CALLABLE_SIGNATURE(ctor, DDFRecord, void*, "56 8B F1 57 C7 06 04 E7 E4 00 33 C0 8D 4E 04 87 01 8D 7E", "", 0, void*, const Key*) } - CREATE_NORMAL_CALLABLE_SIGNATURE(SetupDatabaseDirectoryFiles, ResourceMan,void,"81 ec e0 08 00 00 a1 ?? ?? ?? ?? 33 c4 89 84 24 dc 08 00 00 8b 84 24 e4 08 00 00 53 55 8b ac 24 fc 08 00 00 56 8b b4 24 fc 08 00 00 89 44 24 0c 8b 84 24 f4 08 00 00 57 33 db 33 ff 3b c3 89 44 24 2c 89 7c 24 14 75 11", 0, const wchar_t*, void* manager, IO::AccessFlags, bool (*)(const wchar_t*, void*), void*, int) + // CREATE_NORMAL_CALLABLE_SIGNATURE(SetupDatabaseDirectoryFiles, ResourceMan,void,"81 ec e0 08 00 00 a1 ?? ?? ?? ?? 33 c4 89 84 24 dc 08 00 00 8b 84 24 e4 08 00 00 53 55 8b ac 24 fc 08 00 00 56 8b b4 24 fc 08 00 00 89 44 24 0c 8b 84 24 f4 08 00 00 57 33 db 33 ff 3b c3 89 44 24 2c 89 7c 24 14 75 11", "", 0, const wchar_t*, void* manager, IO::AccessFlags, bool (*)(const wchar_t*, void*), void*, int) } namespace ScriptOs::LuaScriptingSystem { struct LuaScriptingSystem { - uint8_t padding[0x10]; - lua_State* state; + void *vtable; + size_t padding[3]; + lua_State *state; }; - CREATE_MEMBER_CALLABLE_SIGNATURE(Startup, LuaScriptingSystem, void, "83 ec 30 53 55 56 57 8b f1 c7 44 24 10 1c 00 00 00 c7 44 24 14 c8 32 00 00 c7 44 24 18 20 00 00 00 c7 44 24 1c 50 46 00 00 c7 44 24 20 28 00 00 00 c7 44 24 24 52 1c 00 00 c7 44 24 28 50 00 00 00 c7 44 24 2c b6 35 00 00 c7 44 24 30 a0 00 00 00 c7 44 24 34 b2 0c 00 00 c7 44 24 38 40 01 00 00 c7 44 24 3c dc 05 00 00 33 db", 0); + + CREATE_MEMBER_CALLABLE_SIGNATURE(Startup, LuaScriptingSystem, void, + "83 ec 30 53 55 56 57 8b f1 c7 44 24 10 1c 00 00 00 c7 44 24 14 c8 32 00 00 c7 44 24 18 20 00 00 00 c7 44 24 1c 50 46 00 00 c7 44 24 20 28 00 00 00 c7 44 24 24 52 1c 00 00 c7 44 24 28 50 00 00 00 c7 44 24 2c b6 35 00 00 c7 44 24 30 a0 00 00 00 c7 44 24 34 b2 0c 00 00 c7 44 24 38 40 01 00 00 c7 44 24 3c dc 05 00 00 33 db", + "48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 48 89 7C 24 20 41 56 48 81 EC C0 00 00 00 48 8B E9 48 8D", + 0); } } #pragma region lua functions // These are correct, but very hard to find... -CREATE_NORMAL_CALLABLE_SIGNATURE(lua_pushvalue, lua, void, "8B 44 24 08 56 8B 74 24 08 50 56 ?? ?? ?? ?? ?? 8B 4E 08 8B 10 89 11 8B 40 04 83", 0, lua_State *L, int index); -CREATE_NORMAL_CALLABLE_SIGNATURE(lua_getfield, lua, int, "8B 44 24 08 83 EC 08 53 56 8B 74 24 14 57 50 56 ?? ?? ?? ?? ?? 8B 54 24 28 8B F8 8B C2 83 C4 08 8D 58 01 8A 08 83 C0 01 84 C9 ?? ?? 2B C3 50 52 56 ?? ?? ?? ?? ?? 8B 4E 08 51 8d 54 24 1c", 0, lua_State *L, int index, const char *k); -CREATE_NORMAL_CALLABLE_SIGNATURE(lua_pushcclosure, lua, void, "56 8B 74 24 08 8B 46 10 8B 48 44 3B 48 40 57 ?? ?? 56 ?? ?? ?? ?? ?? 83 C4 04 8B 46 14 3B 46 28 ?? ?? 8B 46 44", 0, lua_State *L, lua_CFunction fn, int n); -CREATE_NORMAL_CALLABLE_SIGNATURE(lua_setfield, lua, void, "8B 44 24 08 83 EC 08 53 56 8B 74 24 14 57 50 56 ?? ?? ?? ?? ?? 8B 54 24 28 8B F8 8B C2 83 C4 08 8D 58 01 8A 08 83 C0 01 84 C9 ?? ?? 2B C3 50 52 56 ?? ?? ?? ?? ?? 8B 4E 08 83 E9 08 51", 0, lua_State *L, int index, const char *k); -CREATE_NORMAL_CALLABLE_SIGNATURE(lua_settop, lua, void, "8B 4C 24 08 85 C9 8B 44 24 04 ?? ?? 8B 50 0C 03 C9 03 C9 03 C9 03 D1 39 50", 0, lua_State *L, int index); -CREATE_NORMAL_CALLABLE_SIGNATURE(lua_gettop, lua, int, "8b 4c 24 04 8b 41 08 2b 41 0c c1 f8 03 c3", 0, lua_State *L); -CREATE_NORMAL_CALLABLE_SIGNATURE(lua_tolstring, lua, const char*, "56 8B 74 24 08 57 8B 7C 24 10 57 56 ?? ?? ?? ?? ?? 83 C4 08 83 78 04 04 ?? ?? 50 56 ?? ?? ?? ?? ?? 83 C4", 0, lua_State *L, int index, size_t *len); -CREATE_NORMAL_CALLABLE_SIGNATURE(lua_newstate, lua, lua_State*, "53 55 8B 6C 24 0C 57 8B 7C 24 14 33 DB 53 68 4C 01 00 00 53 53 57 ?? ?? 83 C4 14 3B C3 ?? ?? 5F", 0, lua_Alloc f, void* ud); -CREATE_NORMAL_CALLABLE_SIGNATURE(luaL_ref, lua, int, "53 8B 5C 24 0C 8D 83 0F 27 00 00 3D 0F 27 00 00 56 8B 74 24 0C ?? ?? 56 ?? ?? ?? ?? ?? 83 C4 04 8D", 0, lua_State *L, int t); -CREATE_NORMAL_CALLABLE_SIGNATURE(luaL_loadfile, lua, int, "81 EC 0C 02 00 00 A1 C0 44 02 01 33 C4 89 84 24 08 02 00 00 55 8B AC 24 18 02 00 00 56 8B B4 24 18 02 00 00 57 56 ?? ?? ?? ?? ?? 8B", 0, lua_State *L, const char* filename); -CREATE_NORMAL_CALLABLE_SIGNATURE(lua_remove, lua, void, "8b 44 24 08 56 8b 74 24 08 50 56 e8 ?? ?? ?? ?? 83 c0 08 83 c4 08 3b 46 08 73 18 eb 03 8d 49 00", 0, lua_State *L, int index); -CREATE_NORMAL_CALLABLE_SIGNATURE(lua_insert, lua, void, "8B 44 24 08 56 8B 74 24 08 50 56 ?? ?? ?? ?? ?? 8B 4E 08 83 C4 08 3B C8 ?? ?? 8D 9B 00 00 00", 0, lua_State *L, int index); -CREATE_NORMAL_CALLABLE_SIGNATURE(lua_pcall, lua, int, "8B 44 24 10 83 EC 08 85 C0 56 8B 74 24 10 ?? ?? 33 C9 ?? ?? 50 56 ?? ?? ?? ?? ?? 83 C4 08 2B", 0, lua_State *L, int nargs, int nresults, int errfunc); -CREATE_NORMAL_CALLABLE_SIGNATURE(lua_rawgeti, lua, void, "8B 44 24 08 56 8B 74 24 08 50 56 ?? ?? ?? ?? ?? 8B 4C 24 18 8B 10 51 52 ?? ?? ?? ?? ?? 8B 4E 08 8B 10 89", 0, lua_State *L, int index, int n); -CREATE_NORMAL_CALLABLE_SIGNATURE(luaL_checklstring, lua, const char *, "8B 44 24 0C 53 56 8B 74 24 0C 57 8B 7C 24 14 50 57 56 ?? ?? ?? ?? ?? 8B D8 83 C4 0C 85 DB ?? ?? 55", 0, lua_State *L, int narg, size_t *l); -CREATE_NORMAL_CALLABLE_SIGNATURE(lua_pushstring, lua, void, "55 8B 6C 24 0C 85 ED ?? ?? 8B 44 24 08 8B 48 08 89 69 04 83 40 08 08 5D", 0, lua_State *L, const char *s); -CREATE_NORMAL_CALLABLE_SIGNATURE(luaB_loadstring, lua, int, "51 56 8B 74 24 0C 57 8D 44 24 08 50 6A 01 56 ?? ?? ?? ?? ?? 6A 00 8B F8 57 6A 02 56", 0, lua_State *L); -CREATE_NORMAL_CALLABLE_SIGNATURE(luaG_errormsg, void, int, "56 8B 74 24 08 8B 46 60 85 C0 ?? ?? 57 8B 7E 20 03 F8 83 7F 04 06", 0, lua_State *L); -CREATE_NORMAL_CALLABLE_SIGNATURE(luaL_loadbuffer, void, int, "83 EC 08 8B 44 24 10 8B 54 24 18 8B 4C 24 14 52 89 44 24 04 8D 44 24 04 50 89 4C 24 0C 8B 4C 24 14", 0, lua_State * L, const char * buff, size_t sz,const char * name); +CREATE_NORMAL_CALLABLE_SIGNATURE(lua_pushvalue, lua, void, + "8B 44 24 08 56 8B 74 24 08 50 56 ?? ?? ?? ?? ?? 8B 4E 08 8B 10 89 11 8B 40 04 83", + "48 89 5C 24 08 57 48 83 EC 20 48 8B F9 8B DA 48 8D 0D 22 00 9C 00 ?? ?? ?? ?? ?? 8B D3 48 8B CF ?? ?? ?? ?? ?? 4C 8B 47 10 48 8B 5C 24", + 0, lua_State *L, int index); +CREATE_NORMAL_CALLABLE_SIGNATURE(lua_getfield, lua, int, + "8B 44 24 08 83 EC 08 53 56 8B 74 24 14 57 50 56 ?? ?? ?? ?? ?? 8B 54 24 28 8B F8 8B C2 83 C4 08 8D 58 01 8A 08 83 C0 01 84 C9 ?? ?? 2B C3 50 52 56 ?? ?? ?? ?? ?? 8B 4E 08 51 8d 54 24 1c", + "48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 30 48 8B F1 49 8B F8 48 8D 0D 6C 0B 9C 00 8B DA ?? ?? ?? ?? ?? 8B D3 48 8B CE ?? ?? ?? ?? ?? 48 8B", + 0, lua_State *L, int index, const char *k); +CREATE_NORMAL_CALLABLE_SIGNATURE(lua_pushcclosure, lua, void, + "56 8B 74 24 08 8B 46 10 8B 48 44 3B 48 40 57 ?? ?? 56 ?? ?? ?? ?? ?? 83 C4 04 8B 46 14 3B 46 28 ?? ?? 8B 46 44", + "48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 48 8B D9 49 63 F8 48 8D 0D BC 03 9C 00 48 8B F2 ?? ?? ?? ?? ?? 4C 8B 4B 20 49 8B 41 70 49", + 0, lua_State *L, lua_CFunction fn, int n); +CREATE_NORMAL_CALLABLE_SIGNATURE(lua_setfield, lua, void, + "8B 44 24 08 83 EC 08 53 56 8B 74 24 14 57 50 56 ?? ?? ?? ?? ?? 8B 54 24 28 8B F8 8B C2 83 C4 08 8D 58 01 8A 08 83 C0 01 84 C9 ?? ?? 2B C3 50 52 56 ?? ?? ?? ?? ?? 8B 4E 08 83 E9 08 51", + "48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 30 48 8B F1 49 8B F8 48 8D 0D 8C FA 9B 00 8B DA ?? ?? ?? ?? ?? 8B D3 48 8B CE ?? ?? ?? ?? ?? 48 8B", + 0, lua_State *L, int index, const char *k); +CREATE_NORMAL_CALLABLE_SIGNATURE(lua_settop, lua, void, + "8B 4C 24 08 85 C9 8B 44 24 04 ?? ?? 8B 50 0C 03 C9 03 C9 03 C9 03 D1 39 50", + "48 89 5C 24 08 57 48 83 EC 20 48 8B D9 48 63 FA 48 8D 0D F1 F8 9B 00 ?? ?? ?? ?? ?? 85 FF ?? ?? 48 8B 53 18 4C 8B", + 0, + lua_State *L, int index); +CREATE_NORMAL_CALLABLE_SIGNATURE(lua_gettop, lua, int, "8b 4c 24 04 8b 41 08 2b 41 0c c1 f8 03 c3", + "40 53 48 83 EC 20 48 8B D9 48 8D 0D 18 0A 9C 00 ?? ?? ?? ?? ?? 48 8B 43 10 48 2B 43 18 48 C1 F8 04 48", + 0, + lua_State *L); +CREATE_NORMAL_CALLABLE_SIGNATURE(lua_tolstring, lua, const char*, + "56 8B 74 24 08 57 8B 7C 24 10 57 56 ?? ?? ?? ?? ?? 83 C4 08 83 78 04 04 ?? ?? 50 56 ?? ?? ?? ?? ?? 83 C4", + "48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 48 8B F9 49 8B D8 48 8D 0D 7C F6 9B 00 8B F2 ?? ?? ?? ?? ?? 8B D6 48 8B", 0, lua_State *L, int index, size_t *len); +CREATE_NORMAL_CALLABLE_SIGNATURE(lua_newstate, lua, lua_State*, + "53 55 8B 6C 24 0C 57 8B 7C 24 14 33 DB 53 68 4C 01 00 00 53 53 57 ?? ?? 83 C4 14 3B C3 ?? ?? 5F", + "48 89 6C 24 18 48 89 74 24 20 41 56 48 83 EC 30 48 8B E9 48 8B F2 48 8D 0D 17 9B 9A 00 ?? ?? ?? ?? ?? 45 33 F6 41 B9 70 02", 0, lua_Alloc f, void* ud); +CREATE_NORMAL_CALLABLE_SIGNATURE(luaL_ref, lua, int, + "53 8B 5C 24 0C 8D 83 0F 27 00 00 3D 0F 27 00 00 56 8B 74 24 0C ?? ?? 56 ?? ?? ?? ?? ?? 83 C4 04 8D", + "48 89 5C 24 10 57 48 83 EC 20 48 8B D9 8B FA 48 8D 0D F0 D9 9B 00 ?? ?? ?? ?? ?? 8D 87 0F 27 00 00", 0, lua_State *L, int t); +CREATE_NORMAL_CALLABLE_SIGNATURE(luaL_loadfile, lua, int, + "81 EC 0C 02 00 00 A1 C0 44 02 01 33 C4 89 84 24 08 02 00 00 55 8B AC 24 18 02 00 00 56 8B B4 24 18 02 00 00 57 56 ?? ?? ?? ?? ?? 8B", + "40 55 56 57 48 81 EC 40 02 00 00 48 8B 05 2E 88 8B 00 48 33 C4 48 89 84 24 30 02 00 00 48 8B F9 48 8B", 0, lua_State *L, const char* filename); +CREATE_NORMAL_CALLABLE_SIGNATURE(lua_remove, lua, void, + "8b 44 24 08 56 8b 74 24 08 50 56 e8 ?? ?? ?? ?? 83 c0 08 83 c4 08 3b 46 08 73 18 eb 03 8d 49 00", + "48 89 5C 24 08 57 48 83 EC 20 48 8B F9 8B DA 48 8D 0D 02 FD 9B 00 ?? ?? ?? ?? ?? 8B D3 48 8B CF ?? ?? ?? ?? ?? 48 8B 4F", 0, lua_State *L, int index); +CREATE_NORMAL_CALLABLE_SIGNATURE(lua_insert, lua, void, + "8B 44 24 08 56 8B 74 24 08 50 56 ?? ?? ?? ?? ?? 8B 4E 08 83 C4 08 3B C8 ?? ?? 8D 9B 00 00 00", + "48 89 5C 24 08 57 48 83 EC 20 48 8B F9 8B DA 48 8D 0D 72 09 9C 00 ?? ?? ?? ?? ?? 8B D3 48 8B CF ?? ?? ?? ?? ?? 48 8B", 0, lua_State *L, int index); +CREATE_NORMAL_CALLABLE_SIGNATURE(lua_pcall, lua, int, + "8B 44 24 10 83 EC 08 85 C0 56 8B 74 24 10 ?? ?? 33 C9 ?? ?? 50 56 ?? ?? ?? ?? ?? 83 C4 08 2B", + "48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 40 48 8B D9 41 8B F9 48 8D 0D B7 04 9C 00 41 8B F0 8B EA ?? ?? ?? ?? ?? 85", 0, lua_State *L, int nargs, int nresults, int errfunc); +CREATE_NORMAL_CALLABLE_SIGNATURE(lua_rawgeti, lua, void, + "8B 44 24 08 56 8B 74 24 08 50 56 ?? ?? ?? ?? ?? 8B 4C 24 18 8B 10 51 52 ?? ?? ?? ?? ?? 8B 4E 08 8B 10 89", + "48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 48 8B F1 41 8B F8 48 8D 0D 8C FE 9B 00 8B DA ?? ?? ?? ?? ?? 8B D3 48 8B CE ?? ?? ?? ?? ?? 8B", 0, lua_State *L, int index, int n); +CREATE_NORMAL_CALLABLE_SIGNATURE(luaL_checklstring, lua, const char *, + "8B 44 24 0C 53 56 8B 74 24 0C 57 8B 7C 24 14 50 57 56 ?? ?? ?? ?? ?? 8B D8 83 C4 0C 85 DB ?? ?? 55", + "48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 48 8B F1 49 8B D8 48 8D 0D AA D7 9B 00 8B FA ?? ?? ?? ?? ?? 8B D7 48 8B CE", 0, lua_State *L, int narg, size_t *l); +CREATE_NORMAL_CALLABLE_SIGNATURE(lua_pushstring, lua, void, + "55 8B 6C 24 0C 85 ED ?? ?? 8B 44 24 08 8B 48 08 89 69 04 83 40 08 08 5D", "48 89 6C 24 18 56 48 83 EC 20 48 8B F1 48 8B EA 48 8D 0D 11 01 9C 00 ?? ?? ?? ?? ?? 48 85 ED ?? ?? 48 8B 46 10 89", 0, + lua_State *L, const char *s); +CREATE_NORMAL_CALLABLE_SIGNATURE(luaB_loadstring, lua, int, + "51 56 8B 74 24 0C 57 8D 44 24 08 50 6A 01 56 ?? ?? ?? ?? ?? 6A 00 8B F8 57 6A 02 56", + "48 89 5C 24 08 57 48 83 EC 20 48 8B F9 48 8D 0D 81 CD 9B 00 ?? ?? ?? ?? ?? 4C 8D 44 24 38 BA", 0, lua_State *L); +// CREATE_NORMAL_CALLABLE_SIGNATURE(luaG_errormsg, void, int, +// "56 8B 74 24 08 8B 46 60 85 C0 ?? ?? 57 8B 7E 20 03 F8 83 7F 04 06", "", 0, +// lua_State *L); +CREATE_NORMAL_CALLABLE_SIGNATURE(luaL_loadbuffer, void, int, + "83 EC 08 8B 44 24 10 8B 54 24 18 8B 4C 24 14 52 89 44 24 04 8D 44 24 04 50 89 4C 24 0C 8B 4C 24 14", + "48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 30 48 8B E9 49 8B F1 48 8D 0D B5 E1 9B 00 49 8B F8 48 8B DA ?? ?? ?? ?? ?? 4C 8B CE 48 89 5C 24", 0, lua_State * L, const char * buff, size_t sz, const char * name); #pragma endregion diff --git a/src/tweakers/SwarmTweaker/SwarmTweaker.cpp b/src/tweakers/SwarmTweaker/SwarmTweaker.cpp new file mode 100644 index 0000000..c0aad51 --- /dev/null +++ b/src/tweakers/SwarmTweaker/SwarmTweaker.cpp @@ -0,0 +1,17 @@ +// +// Created by exozg on 13/03/2025. +// + +#include "SwarmTweaker.h" + +#include "../../assets/Asset.h" +#include "../../util/FNV.h" + +EA::ResourceMan::Key SwarmTweaker::RootSwarmKey = { + .instance = FNV::FromString64("MySims"), + .type = static_cast(SWM), + .group = 0, +}; + +void SwarmTweaker::Apply(const EA::ResourceMan::Key &key) { +} diff --git a/src/tweakers/SwarmTweaker/SwarmTweaker.h b/src/tweakers/SwarmTweaker/SwarmTweaker.h new file mode 100644 index 0000000..1da6518 --- /dev/null +++ b/src/tweakers/SwarmTweaker/SwarmTweaker.h @@ -0,0 +1,21 @@ +// +// Created by exozg on 13/03/2025. +// + +#ifndef SWARMTWEAKER_H +#define SWARMTWEAKER_H + +#include "../Tweaker.h" +#include "../../signatures/sigdef.h" + + +class SwarmTweaker : public Tweaker { +public: + static EA::ResourceMan::Key RootSwarmKey; + std::string path; + void Apply(const EA::ResourceMan::Key& key) override; +}; + + + +#endif //SWARMTWEAKER_H diff --git a/src/tweakers/Tweaker.cpp b/src/tweakers/Tweaker.cpp new file mode 100644 index 0000000..de5baed --- /dev/null +++ b/src/tweakers/Tweaker.cpp @@ -0,0 +1,6 @@ +// +// Created by exozg on 13/03/2025. +// + +#include "Tweaker.h" + diff --git a/src/tweakers/Tweaker.h b/src/tweakers/Tweaker.h new file mode 100644 index 0000000..fa2d316 --- /dev/null +++ b/src/tweakers/Tweaker.h @@ -0,0 +1,18 @@ +// +// Created by exozg on 13/03/2025. +// + +#ifndef TWEAKER_H +#define TWEAKER_H +#include "../signatures/sigdef.h" + + +class Tweaker { +public: + virtual void Apply(const EA::ResourceMan::Key& key) = 0; + virtual ~Tweaker() = default; +}; + + + +#endif //TWEAKER_H diff --git a/src/util/FNV.cpp b/src/util/FNV.cpp index e0466f0..ce67128 100644 --- a/src/util/FNV.cpp +++ b/src/util/FNV.cpp @@ -15,7 +15,7 @@ uint64_t FNV::FromString64(const char *str) { for (int i = 0; str[i] != '\0'; i++) { hash *= FNV_PRIME_64; - hash ^= str[i]; + hash ^= std::tolower(str[i]); } return hash; } @@ -25,7 +25,7 @@ uint32_t FNV::FromString32(const char *str) { for (int i = 0; str[i] != '\0'; i++) { hash *= FNV_PRIME_32; - hash ^= str[i]; + hash ^= std::tolower(str[i]); } return hash; diff --git a/src/util/FNV.h b/src/util/FNV.h index f240237..0920591 100644 --- a/src/util/FNV.h +++ b/src/util/FNV.h @@ -5,6 +5,7 @@ #ifndef FNV_H #define FNV_H #include +#include class FNV { diff --git a/src/util/Logger.h b/src/util/Logger.h index 8b285ed..efd36c9 100644 --- a/src/util/Logger.h +++ b/src/util/Logger.h @@ -43,6 +43,9 @@ class Logger { Logger::Log(Logger::LogLevel::DEBUG, false, __FILE__, __LINE__, format, ##__VA_ARGS__) #endif +#define MSML_LOG_DEBUG_HIDDEN(format, ...) \ + Logger::Log(Logger::LogLevel::DEBUG, false, __FILE__, __LINE__, format, ##__VA_ARGS__) + #define MSML_LOG_LUA(format, ...) \ MSML_LOGLEVEL(LUA, format, ##__VA_ARGS__) From 1f382abde2dc4b004b9d67ad5577ecbd6e1e1b5f Mon Sep 17 00:00:00 2001 From: ThuverX Date: Thu, 20 Mar 2025 22:42:34 +0100 Subject: [PATCH 16/30] fix build pipeline --- .github/workflows/cmake-single-platform.yml | 50 +++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index 5ba9abb..86a4df2 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -11,7 +11,7 @@ env: BUILD_TYPE: Release jobs: - build: + build-x86: runs-on: windows-latest steps: @@ -22,7 +22,12 @@ jobs: - name: Get Tag Name shell: bash - run: echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + run: | + if [[ "${{ github.ref }}" == refs/tags/* ]]; then + echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + else + echo "TAG_NAME=${{ github.head_ref }}" >> $GITHUB_ENV + fi - name: Configure CMake run: cmake -B ${{github.workspace}}/build -G "Visual Studio 17 2022" -A Win32 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} @@ -43,5 +48,44 @@ jobs: - name: Upload Artifacts uses: actions/upload-artifact@v4 with: - name: windows-x86-${{ env.TAG_NAME }} + name: mysims-windows-x86-${{ env.TAG_NAME }} path: ${{ github.workspace }}/artifact/ + build-x64: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: true + + - name: Get Tag Name + shell: bash + run: | + if [[ "${{ github.ref }}" == refs/tags/* ]]; then + echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + else + echo "TAG_NAME=${{ github.head_ref }}" >> $GITHUB_ENV + fi + + - name: Configure CMake + run: cmake -B ${{github.workspace}}/build -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + + - name: Build + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Test + working-directory: ${{github.workspace}}/build + run: ctest -C ${{env.BUILD_TYPE}} + + - name: Prepare Artifact + run: | + mkdir -p ${{ github.workspace }}/artifact/mods/basemod + cp -r ${{ github.workspace }}/basemod/* ${{ github.workspace }}/artifact/mods/basemod/ + cp ${{ github.workspace }}/build/Release/WSOCK32.dll ${{ github.workspace }}/artifact/ + + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + with: + name: mysims-cozybundle-windows-x64-${{ env.TAG_NAME }} + path: ${{ github.workspace }}/artifact/ From 25b9eb4887dc7386de51ab71a5748475a143df35 Mon Sep 17 00:00:00 2001 From: ThuverX Date: Thu, 20 Mar 2025 22:47:04 +0100 Subject: [PATCH 17/30] change pipeline name --- .github/workflows/cmake-single-platform.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index 86a4df2..a0a9ffa 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -1,4 +1,4 @@ -name: CMake on a single platform +name: CMake build all on: push: From c53989384887cb56994f40073f13c67e22b334ed Mon Sep 17 00:00:00 2001 From: ThuverX Date: Thu, 20 Mar 2025 23:17:58 +0100 Subject: [PATCH 18/30] Changed dsound to be included the same way as wsock --- CMakeLists.txt | 1 + src/platform/w32/dsound.def | 11 ++++ src/platform/w32/dsound.h | 127 +++++++----------------------------- 3 files changed, 36 insertions(+), 103 deletions(-) create mode 100644 src/platform/w32/dsound.def diff --git a/CMakeLists.txt b/CMakeLists.txt index eb47966..1c0fc6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,7 @@ if(CMAKE_GENERATOR_PLATFORM STREQUAL "x64") else () list(APPEND SOURCES + src/platform/w32/dsound.def src/platform/w32/dsound.h) endif () diff --git a/src/platform/w32/dsound.def b/src/platform/w32/dsound.def new file mode 100644 index 0000000..1593e90 --- /dev/null +++ b/src/platform/w32/dsound.def @@ -0,0 +1,11 @@ +EXPORTS +DirectSoundCaptureCreate8=_DSOUND_EXPORT_DirectSoundCaptureCreate8 @12 +DirectSoundCreate8=_DSOUND_EXPORT_DirectSoundCreate8 @11 +DirectSoundFullDuplexCreate=_DSOUND_EXPORT_DirectSoundFullDuplexCreate @10 +GetDeviceID=_DSOUND_EXPORT_GetDeviceID @9 +DirectSoundCaptureEnumerateW=_DSOUND_EXPORT_DirectSoundCaptureEnumerateW @8 +DirectSoundCaptureEnumerateA=_DSOUND_EXPORT_DirectSoundCaptureEnumerateA @7 +DirectSoundCaptureCreate=_DSOUND_EXPORT_DirectSoundCaptureCreate @6 +DirectSoundEnumerateW=_DSOUND_EXPORT_DirectSoundEnumerateW @3 +DirectSoundEnumerateA=_DSOUND_EXPORT_DirectSoundEnumerateA @2 +DirectSoundCreate=_DSOUND_EXPORT_DirectSoundCreate @1 diff --git a/src/platform/w32/dsound.h b/src/platform/w32/dsound.h index 351b5d1..68b1735 100644 --- a/src/platform/w32/dsound.h +++ b/src/platform/w32/dsound.h @@ -5,115 +5,36 @@ #pragma pack(1) -FARPROC p[12] = {nullptr}; +// taken from https://gitlab.com/znixian/payday2-superblt/-/blob/master/platforms/w32/loader/wsock.cpp?ref_type=heads -void exports(HMODULE hL){ - p[0] = GetProcAddress(hL, "DirectSoundCreate"); - p[1] = GetProcAddress(hL, "DirectSoundEnumerateA"); - p[2] = GetProcAddress(hL, "DirectSoundEnumerateW"); - p[3] = GetProcAddress(hL, "DllCanUnloadNow"); - p[4] = GetProcAddress(hL, "DllGetClassObject"); - p[5] = GetProcAddress(hL, "DirectSoundCaptureCreate"); - p[6] = GetProcAddress(hL, "DirectSoundCaptureEnumerateA"); - p[7] = GetProcAddress(hL, "DirectSoundCaptureEnumerateW"); - p[8] = GetProcAddress(hL, "GetDeviceID"); - p[9] = GetProcAddress(hL, "DirectSoundFullDuplexCreate"); - p[11] = GetProcAddress(hL, "DirectSoundCaptureCreate8"); - p[10] = GetProcAddress(hL, "DirectSoundCreate8"); -} - -extern "C" __declspec(dllexport) __declspec(naked) void __stdcall __E__0__() -{ - __asm - { - jmp p[0*4]; - } -} - -extern "C" __declspec(dllexport) __declspec(naked) void __stdcall __E__1__() -{ - __asm - { - jmp p[1*4]; - } -} +#pragma region ALLFUNC(FUNC) -extern "C" __declspec(dllexport) __declspec(naked) void __stdcall __E__2__() -{ - __asm - { - jmp p[2*4]; - } -} +#define ALLFUNC(FUNC) \ + FUNC(0,DirectSoundCaptureCreate8,12) \ + FUNC(1,DirectSoundCreate8,11) \ + FUNC(2,DirectSoundFullDuplexCreate,10) \ + FUNC(3,GetDeviceID,9) \ + FUNC(4,DirectSoundCaptureEnumerateW,8) \ + FUNC(5,DirectSoundCaptureEnumerateA,7) \ + FUNC(6,DirectSoundCaptureCreate,6) \ + FUNC(7,DirectSoundEnumerateW,3) \ + FUNC(8,DirectSoundEnumerateA,2) \ + FUNC(9,DirectSoundCreate,1) \ -extern "C" __declspec(dllexport) __declspec(naked) void __stdcall __E__3__() -{ - __asm - { - jmp p[3*4]; - } -} +#define ALLFUNC_COUNT 10 -extern "C" __declspec(dllexport) __declspec(naked) void __stdcall __E__4__() -{ - __asm - { - jmp p[4*4]; - } -} +#pragma endregion -extern "C" __declspec(dllexport) __declspec(naked) void __stdcall __E__5__() -{ - __asm - { - jmp p[5*4]; - } -} +FARPROC p[ALLFUNC_COUNT] = {nullptr}; -extern "C" __declspec(dllexport) __declspec(naked) void __stdcall __E__6__() -{ - __asm - { - jmp p[6*4]; - } -} - -extern "C" __declspec(dllexport) __declspec(naked) void __stdcall __E__7__() -{ - __asm - { - jmp p[7*4]; - } -} - -extern "C" __declspec(dllexport) __declspec(naked) void __stdcall __E__8__() -{ - __asm - { - jmp p[8*4]; - } -} - -extern "C" __declspec(dllexport) __declspec(naked) void __stdcall __E__9__() -{ - __asm - { - jmp p[9*4]; - } +void exports(HMODULE hL){ +#define REGISTER(num, name, ordinal) p[num] = GetProcAddress(hL, #name); + ALLFUNC(REGISTER); +#undef REGISTER } -extern "C" __declspec(dllexport) __declspec(naked) void __stdcall __E__10__() -{ - __asm - { - jmp p[10*4]; - } -} +#define DEF_STUB(num, name, ordinal) \ +extern "C" __declspec(naked) void __stdcall _DSOUND_EXPORT_##name(){__asm {jmp p[num * 4]}}; -extern "C" __declspec(dllexport) __declspec(naked) void __stdcall __E__11__() -{ - __asm - { - jmp p[11*4]; - } -} +ALLFUNC(DEF_STUB) +#undef DEF_STUB \ No newline at end of file From 3affae6f04d39f5d61a83c27a3e55bce7eebfffb Mon Sep 17 00:00:00 2001 From: ThuverX Date: Sat, 17 May 2025 20:46:07 +0200 Subject: [PATCH 19/30] Include EASTL from Spore mod api --- .../assets/0x00000000!0x000000000B25E40B.dds | Bin 0 -> 1398256 bytes .../assets/0x00000000!0x0000000061805F86.dds | Bin 0 -> 1398256 bytes .../assets/0x00000000!0x00000000EE93FAC8.dds | Bin 0 -> 1398256 bytes libs/eastl/.appveyor.yml | 24 + libs/eastl/.clang-format | 32 + libs/eastl/.gitattributes | 3 + libs/eastl/.gitignore | 36 + libs/eastl/.p4ignore | 2 + libs/eastl/.travis.yml | 58 + libs/eastl/3RDPARTYLICENSES.TXT | 103 + libs/eastl/CMakeLists.txt | 85 + libs/eastl/CONTRIBUTING.md | 71 + libs/eastl/LICENSE | 27 + libs/eastl/README.md | 43 + libs/eastl/include/EASTL/algorithm.h | 4167 +++++++++++++++++ libs/eastl/include/EASTL/allocator.h | 407 ++ libs/eastl/include/EASTL/allocator_malloc.h | 124 + libs/eastl/include/EASTL/array.h | 496 ++ libs/eastl/include/EASTL/bitset.h | 2254 +++++++++ libs/eastl/include/EASTL/bitvector.h | 1506 ++++++ libs/eastl/include/EASTL/bonus/adaptors.h | 74 + libs/eastl/include/EASTL/bonus/call_traits.h | 117 + .../include/EASTL/bonus/compressed_pair.h | 460 ++ .../EASTL/bonus/fixed_string_abstract.h | 638 +++ .../include/EASTL/bonus/intrusive_sdlist.h | 694 +++ .../include/EASTL/bonus/intrusive_slist.h | 321 ++ libs/eastl/include/EASTL/bonus/list_map.h | 937 ++++ libs/eastl/include/EASTL/bonus/ring_buffer.h | 1557 ++++++ libs/eastl/include/EASTL/bonus/sort_extra.h | 204 + .../eastl/include/EASTL/bonus/sparse_matrix.h | 1581 +++++++ .../include/EASTL/bonus/string_abstract.h | 3825 +++++++++++++++ libs/eastl/include/EASTL/chrono.h | 712 +++ libs/eastl/include/EASTL/core_allocator.h | 75 + .../include/EASTL/core_allocator_adapter.h | 364 ++ libs/eastl/include/EASTL/deque.h | 2978 ++++++++++++ libs/eastl/include/EASTL/fixed_allocator.h | 449 ++ libs/eastl/include/EASTL/fixed_hash_map.h | 844 ++++ libs/eastl/include/EASTL/fixed_hash_set.h | 845 ++++ libs/eastl/include/EASTL/fixed_list.h | 426 ++ libs/eastl/include/EASTL/fixed_map.h | 641 +++ libs/eastl/include/EASTL/fixed_set.h | 621 +++ libs/eastl/include/EASTL/fixed_slist.h | 414 ++ libs/eastl/include/EASTL/fixed_string.h | 823 ++++ libs/eastl/include/EASTL/fixed_substring.h | 278 ++ libs/eastl/include/EASTL/fixed_vector.h | 644 +++ libs/eastl/include/EASTL/functional.h | 1140 +++++ libs/eastl/include/EASTL/hash_map.h | 536 +++ libs/eastl/include/EASTL/hash_set.h | 440 ++ libs/eastl/include/EASTL/heap.h | 589 +++ libs/eastl/include/EASTL/initializer_list.h | 121 + .../include/EASTL/internal/allocator_traits.h | 392 ++ .../internal/allocator_traits_fwd_decls.h | 40 + libs/eastl/include/EASTL/internal/config.h | 1838 ++++++++ libs/eastl/include/EASTL/internal/copy_help.h | 212 + .../include/EASTL/internal/enable_shared.h | 77 + libs/eastl/include/EASTL/internal/fill_help.h | 484 ++ .../eastl/include/EASTL/internal/fixed_pool.h | 1635 +++++++ libs/eastl/include/EASTL/internal/function.h | 1352 ++++++ .../include/EASTL/internal/functional_base.h | 240 + .../include/EASTL/internal/generic_iterator.h | 229 + libs/eastl/include/EASTL/internal/hashtable.h | 2984 ++++++++++++ .../include/EASTL/internal/integer_sequence.h | 70 + .../EASTL/internal/intrusive_hashtable.h | 1005 ++++ libs/eastl/include/EASTL/internal/mem_fn.h | 470 ++ libs/eastl/include/EASTL/internal/move_help.h | 196 + .../include/EASTL/internal/pair_fwd_decls.h | 16 + .../include/EASTL/internal/red_black_tree.h | 2296 +++++++++ libs/eastl/include/EASTL/internal/smart_ptr.h | 279 ++ .../include/EASTL/internal/thread_support.h | 256 + .../include/EASTL/internal/tuple_fwd_decls.h | 30 + .../include/EASTL/internal/type_compound.h | 626 +++ .../include/EASTL/internal/type_fundamental.h | 259 + libs/eastl/include/EASTL/internal/type_pod.h | 1915 ++++++++ .../include/EASTL/internal/type_properties.h | 453 ++ .../EASTL/internal/type_transformations.h | 567 +++ libs/eastl/include/EASTL/intrusive_hash_map.h | 98 + libs/eastl/include/EASTL/intrusive_hash_set.h | 100 + libs/eastl/include/EASTL/intrusive_list.h | 1315 ++++++ libs/eastl/include/EASTL/intrusive_ptr.h | 409 ++ libs/eastl/include/EASTL/iterator.h | 1303 ++++++ libs/eastl/include/EASTL/linked_array.h | 336 ++ libs/eastl/include/EASTL/linked_ptr.h | 426 ++ libs/eastl/include/EASTL/list.h | 2377 ++++++++++ libs/eastl/include/EASTL/map.h | 610 +++ libs/eastl/include/EASTL/memory.h | 1556 ++++++ libs/eastl/include/EASTL/numeric.h | 246 + libs/eastl/include/EASTL/numeric_limits.h | 1735 +++++++ libs/eastl/include/EASTL/optional.h | 590 +++ libs/eastl/include/EASTL/priority_queue.h | 549 +++ libs/eastl/include/EASTL/queue.h | 392 ++ libs/eastl/include/EASTL/random.h | 254 + libs/eastl/include/EASTL/ratio.h | 320 ++ libs/eastl/include/EASTL/safe_ptr.h | 485 ++ libs/eastl/include/EASTL/scoped_array.h | 237 + libs/eastl/include/EASTL/scoped_ptr.h | 256 + libs/eastl/include/EASTL/set.h | 618 +++ libs/eastl/include/EASTL/shared_array.h | 437 ++ libs/eastl/include/EASTL/shared_ptr.h | 1987 ++++++++ libs/eastl/include/EASTL/slist.h | 2121 +++++++++ libs/eastl/include/EASTL/sort.h | 1910 ++++++++ libs/eastl/include/EASTL/stack.h | 376 ++ libs/eastl/include/EASTL/string.h | 4118 ++++++++++++++++ libs/eastl/include/EASTL/tuple.h | 809 ++++ libs/eastl/include/EASTL/type_traits.h | 934 ++++ libs/eastl/include/EASTL/unique_ptr.h | 795 ++++ libs/eastl/include/EASTL/utility.h | 834 ++++ libs/eastl/include/EASTL/vector.h | 2287 +++++++++ libs/eastl/include/EASTL/vector_map.h | 880 ++++ libs/eastl/include/EASTL/vector_multimap.h | 856 ++++ libs/eastl/include/EASTL/vector_multiset.h | 813 ++++ libs/eastl/include/EASTL/vector_set.h | 797 ++++ libs/eastl/include/EASTL/version.h | 15 + libs/eastl/include/EASTL/weak_ptr.h | 17 + libs/eastl/test/CMakeLists.txt | 66 + .../test/packages/EAAssert/CMakeLists.txt | 28 + .../EAAssert/include/EAAssert/eaassert.h | 17 + .../eastl/test/packages/EABase/CMakeLists.txt | 30 + .../test/packages/EABase/doc/EABase.html | 309 ++ .../include/Common/EABase/config/eacompiler.h | 1585 +++++++ .../Common/EABase/config/eacompilertraits.h | 1916 ++++++++ .../include/Common/EABase/config/eaplatform.h | 579 +++ .../EABase/include/Common/EABase/eabase.h | 968 ++++ .../EABase/include/Common/EABase/eahave.h | 874 ++++ .../EABase/include/Common/EABase/earesult.h | 62 + .../EABase/include/Common/EABase/eastdarg.h | 99 + .../EABase/include/Common/EABase/nullptr.h | 102 + .../EABase/include/Common/EABase/version.h | 36 + .../eastl/test/packages/EAMain/CMakeLists.txt | 23 + .../include/EAMain/EAEntryPointMain.inl | 26 + .../packages/EAMain/include/EAMain/EAMain.h | 72 + .../eastl/test/packages/EAStdC/CMakeLists.txt | 46 + .../EAStdC/include/EAStdC/EAAlignment.h | 99 + .../EAStdC/include/EAStdC/EADateTime.h | 27 + .../packages/EAStdC/include/EAStdC/EAMemory.h | 80 + .../EAStdC/include/EAStdC/EAProcess.h | 16 + .../EAStdC/include/EAStdC/EASprintf.h | 42 + .../EAStdC/include/EAStdC/EAStopwatch.h | 296 ++ .../packages/EAStdC/include/EAStdC/EAString.h | 123 + .../EAStdC/include/EAStdC/EATextUtil.h | 70 + .../test/packages/EAStdC/source/EAMemory.cpp | 88 + .../test/packages/EAStdC/source/EASprintf.cpp | 29 + .../eastl/test/packages/EATest/CMakeLists.txt | 48 + .../EATest/include/EATest/EAMissingImpl.inl | 34 + .../include/EATest/EASTLNewOperatorGuard.inl | 31 + .../EATest/include/EATest/EASTLVsnprintf.inl | 43 + .../packages/EATest/include/EATest/EATest.h | 1497 ++++++ .../EATest/include/EATest/internal/Config.h | 318 ++ .../test/packages/EATest/source/EATest.cpp | 1679 +++++++ .../test/packages/EAThread/CMakeLists.txt | 23 + .../EAThread/include/eathread/eathread.h | 37 + .../include/eathread/eathread_atomic.h | 42 + .../include/eathread/eathread_thread.h | 60 + libs/eastl/test/packages/README.md | 24 + 153 files changed, 96449 insertions(+) create mode 100644 examples/greener-grass/assets/0x00000000!0x000000000B25E40B.dds create mode 100644 examples/greener-grass/assets/0x00000000!0x0000000061805F86.dds create mode 100644 examples/greener-grass/assets/0x00000000!0x00000000EE93FAC8.dds create mode 100644 libs/eastl/.appveyor.yml create mode 100644 libs/eastl/.clang-format create mode 100644 libs/eastl/.gitattributes create mode 100644 libs/eastl/.gitignore create mode 100644 libs/eastl/.p4ignore create mode 100644 libs/eastl/.travis.yml create mode 100644 libs/eastl/3RDPARTYLICENSES.TXT create mode 100644 libs/eastl/CMakeLists.txt create mode 100644 libs/eastl/CONTRIBUTING.md create mode 100644 libs/eastl/LICENSE create mode 100644 libs/eastl/README.md create mode 100644 libs/eastl/include/EASTL/algorithm.h create mode 100644 libs/eastl/include/EASTL/allocator.h create mode 100644 libs/eastl/include/EASTL/allocator_malloc.h create mode 100644 libs/eastl/include/EASTL/array.h create mode 100644 libs/eastl/include/EASTL/bitset.h create mode 100644 libs/eastl/include/EASTL/bitvector.h create mode 100644 libs/eastl/include/EASTL/bonus/adaptors.h create mode 100644 libs/eastl/include/EASTL/bonus/call_traits.h create mode 100644 libs/eastl/include/EASTL/bonus/compressed_pair.h create mode 100644 libs/eastl/include/EASTL/bonus/fixed_string_abstract.h create mode 100644 libs/eastl/include/EASTL/bonus/intrusive_sdlist.h create mode 100644 libs/eastl/include/EASTL/bonus/intrusive_slist.h create mode 100644 libs/eastl/include/EASTL/bonus/list_map.h create mode 100644 libs/eastl/include/EASTL/bonus/ring_buffer.h create mode 100644 libs/eastl/include/EASTL/bonus/sort_extra.h create mode 100644 libs/eastl/include/EASTL/bonus/sparse_matrix.h create mode 100644 libs/eastl/include/EASTL/bonus/string_abstract.h create mode 100644 libs/eastl/include/EASTL/chrono.h create mode 100644 libs/eastl/include/EASTL/core_allocator.h create mode 100644 libs/eastl/include/EASTL/core_allocator_adapter.h create mode 100644 libs/eastl/include/EASTL/deque.h create mode 100644 libs/eastl/include/EASTL/fixed_allocator.h create mode 100644 libs/eastl/include/EASTL/fixed_hash_map.h create mode 100644 libs/eastl/include/EASTL/fixed_hash_set.h create mode 100644 libs/eastl/include/EASTL/fixed_list.h create mode 100644 libs/eastl/include/EASTL/fixed_map.h create mode 100644 libs/eastl/include/EASTL/fixed_set.h create mode 100644 libs/eastl/include/EASTL/fixed_slist.h create mode 100644 libs/eastl/include/EASTL/fixed_string.h create mode 100644 libs/eastl/include/EASTL/fixed_substring.h create mode 100644 libs/eastl/include/EASTL/fixed_vector.h create mode 100644 libs/eastl/include/EASTL/functional.h create mode 100644 libs/eastl/include/EASTL/hash_map.h create mode 100644 libs/eastl/include/EASTL/hash_set.h create mode 100644 libs/eastl/include/EASTL/heap.h create mode 100644 libs/eastl/include/EASTL/initializer_list.h create mode 100644 libs/eastl/include/EASTL/internal/allocator_traits.h create mode 100644 libs/eastl/include/EASTL/internal/allocator_traits_fwd_decls.h create mode 100644 libs/eastl/include/EASTL/internal/config.h create mode 100644 libs/eastl/include/EASTL/internal/copy_help.h create mode 100644 libs/eastl/include/EASTL/internal/enable_shared.h create mode 100644 libs/eastl/include/EASTL/internal/fill_help.h create mode 100644 libs/eastl/include/EASTL/internal/fixed_pool.h create mode 100644 libs/eastl/include/EASTL/internal/function.h create mode 100644 libs/eastl/include/EASTL/internal/functional_base.h create mode 100644 libs/eastl/include/EASTL/internal/generic_iterator.h create mode 100644 libs/eastl/include/EASTL/internal/hashtable.h create mode 100644 libs/eastl/include/EASTL/internal/integer_sequence.h create mode 100644 libs/eastl/include/EASTL/internal/intrusive_hashtable.h create mode 100644 libs/eastl/include/EASTL/internal/mem_fn.h create mode 100644 libs/eastl/include/EASTL/internal/move_help.h create mode 100644 libs/eastl/include/EASTL/internal/pair_fwd_decls.h create mode 100644 libs/eastl/include/EASTL/internal/red_black_tree.h create mode 100644 libs/eastl/include/EASTL/internal/smart_ptr.h create mode 100644 libs/eastl/include/EASTL/internal/thread_support.h create mode 100644 libs/eastl/include/EASTL/internal/tuple_fwd_decls.h create mode 100644 libs/eastl/include/EASTL/internal/type_compound.h create mode 100644 libs/eastl/include/EASTL/internal/type_fundamental.h create mode 100644 libs/eastl/include/EASTL/internal/type_pod.h create mode 100644 libs/eastl/include/EASTL/internal/type_properties.h create mode 100644 libs/eastl/include/EASTL/internal/type_transformations.h create mode 100644 libs/eastl/include/EASTL/intrusive_hash_map.h create mode 100644 libs/eastl/include/EASTL/intrusive_hash_set.h create mode 100644 libs/eastl/include/EASTL/intrusive_list.h create mode 100644 libs/eastl/include/EASTL/intrusive_ptr.h create mode 100644 libs/eastl/include/EASTL/iterator.h create mode 100644 libs/eastl/include/EASTL/linked_array.h create mode 100644 libs/eastl/include/EASTL/linked_ptr.h create mode 100644 libs/eastl/include/EASTL/list.h create mode 100644 libs/eastl/include/EASTL/map.h create mode 100644 libs/eastl/include/EASTL/memory.h create mode 100644 libs/eastl/include/EASTL/numeric.h create mode 100644 libs/eastl/include/EASTL/numeric_limits.h create mode 100644 libs/eastl/include/EASTL/optional.h create mode 100644 libs/eastl/include/EASTL/priority_queue.h create mode 100644 libs/eastl/include/EASTL/queue.h create mode 100644 libs/eastl/include/EASTL/random.h create mode 100644 libs/eastl/include/EASTL/ratio.h create mode 100644 libs/eastl/include/EASTL/safe_ptr.h create mode 100644 libs/eastl/include/EASTL/scoped_array.h create mode 100644 libs/eastl/include/EASTL/scoped_ptr.h create mode 100644 libs/eastl/include/EASTL/set.h create mode 100644 libs/eastl/include/EASTL/shared_array.h create mode 100644 libs/eastl/include/EASTL/shared_ptr.h create mode 100644 libs/eastl/include/EASTL/slist.h create mode 100644 libs/eastl/include/EASTL/sort.h create mode 100644 libs/eastl/include/EASTL/stack.h create mode 100644 libs/eastl/include/EASTL/string.h create mode 100644 libs/eastl/include/EASTL/tuple.h create mode 100644 libs/eastl/include/EASTL/type_traits.h create mode 100644 libs/eastl/include/EASTL/unique_ptr.h create mode 100644 libs/eastl/include/EASTL/utility.h create mode 100644 libs/eastl/include/EASTL/vector.h create mode 100644 libs/eastl/include/EASTL/vector_map.h create mode 100644 libs/eastl/include/EASTL/vector_multimap.h create mode 100644 libs/eastl/include/EASTL/vector_multiset.h create mode 100644 libs/eastl/include/EASTL/vector_set.h create mode 100644 libs/eastl/include/EASTL/version.h create mode 100644 libs/eastl/include/EASTL/weak_ptr.h create mode 100644 libs/eastl/test/CMakeLists.txt create mode 100644 libs/eastl/test/packages/EAAssert/CMakeLists.txt create mode 100644 libs/eastl/test/packages/EAAssert/include/EAAssert/eaassert.h create mode 100644 libs/eastl/test/packages/EABase/CMakeLists.txt create mode 100644 libs/eastl/test/packages/EABase/doc/EABase.html create mode 100644 libs/eastl/test/packages/EABase/include/Common/EABase/config/eacompiler.h create mode 100644 libs/eastl/test/packages/EABase/include/Common/EABase/config/eacompilertraits.h create mode 100644 libs/eastl/test/packages/EABase/include/Common/EABase/config/eaplatform.h create mode 100644 libs/eastl/test/packages/EABase/include/Common/EABase/eabase.h create mode 100644 libs/eastl/test/packages/EABase/include/Common/EABase/eahave.h create mode 100644 libs/eastl/test/packages/EABase/include/Common/EABase/earesult.h create mode 100644 libs/eastl/test/packages/EABase/include/Common/EABase/eastdarg.h create mode 100644 libs/eastl/test/packages/EABase/include/Common/EABase/nullptr.h create mode 100644 libs/eastl/test/packages/EABase/include/Common/EABase/version.h create mode 100644 libs/eastl/test/packages/EAMain/CMakeLists.txt create mode 100644 libs/eastl/test/packages/EAMain/include/EAMain/EAEntryPointMain.inl create mode 100644 libs/eastl/test/packages/EAMain/include/EAMain/EAMain.h create mode 100644 libs/eastl/test/packages/EAStdC/CMakeLists.txt create mode 100644 libs/eastl/test/packages/EAStdC/include/EAStdC/EAAlignment.h create mode 100644 libs/eastl/test/packages/EAStdC/include/EAStdC/EADateTime.h create mode 100644 libs/eastl/test/packages/EAStdC/include/EAStdC/EAMemory.h create mode 100644 libs/eastl/test/packages/EAStdC/include/EAStdC/EAProcess.h create mode 100644 libs/eastl/test/packages/EAStdC/include/EAStdC/EASprintf.h create mode 100644 libs/eastl/test/packages/EAStdC/include/EAStdC/EAStopwatch.h create mode 100644 libs/eastl/test/packages/EAStdC/include/EAStdC/EAString.h create mode 100644 libs/eastl/test/packages/EAStdC/include/EAStdC/EATextUtil.h create mode 100644 libs/eastl/test/packages/EAStdC/source/EAMemory.cpp create mode 100644 libs/eastl/test/packages/EAStdC/source/EASprintf.cpp create mode 100644 libs/eastl/test/packages/EATest/CMakeLists.txt create mode 100644 libs/eastl/test/packages/EATest/include/EATest/EAMissingImpl.inl create mode 100644 libs/eastl/test/packages/EATest/include/EATest/EASTLNewOperatorGuard.inl create mode 100644 libs/eastl/test/packages/EATest/include/EATest/EASTLVsnprintf.inl create mode 100644 libs/eastl/test/packages/EATest/include/EATest/EATest.h create mode 100644 libs/eastl/test/packages/EATest/include/EATest/internal/Config.h create mode 100644 libs/eastl/test/packages/EATest/source/EATest.cpp create mode 100644 libs/eastl/test/packages/EAThread/CMakeLists.txt create mode 100644 libs/eastl/test/packages/EAThread/include/eathread/eathread.h create mode 100644 libs/eastl/test/packages/EAThread/include/eathread/eathread_atomic.h create mode 100644 libs/eastl/test/packages/EAThread/include/eathread/eathread_thread.h create mode 100644 libs/eastl/test/packages/README.md diff --git a/examples/greener-grass/assets/0x00000000!0x000000000B25E40B.dds b/examples/greener-grass/assets/0x00000000!0x000000000B25E40B.dds new file mode 100644 index 0000000000000000000000000000000000000000..5c6c9edfb339b855b8dde6aca088f4f09e9d791f GIT binary patch literal 1398256 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 z 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 literal 0 HcmV?d00001 diff --git a/examples/greener-grass/assets/0x00000000!0x0000000061805F86.dds b/examples/greener-grass/assets/0x00000000!0x0000000061805F86.dds new file mode 100644 index 0000000000000000000000000000000000000000..0738528b3cac29076aea8d24c6df4e022bffdeac GIT binary patch literal 1398256 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

eCw~<`+t#c7`zL<|eE|XLOuAQp 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

O_>PnA`PVy$Z_cGQ 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�f&ukw!QKYsIFY={;81@gNT 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 Zd+a)TWmgE%LQE%0cpkaJ7#n`h{{f5nL23X1 literal 0 HcmV?d00001 diff --git a/examples/greener-grass/assets/0x00000000!0x00000000EE93FAC8.dds b/examples/greener-grass/assets/0x00000000!0x00000000EE93FAC8.dds new file mode 100644 index 0000000000000000000000000000000000000000..0738528b3cac29076aea8d24c6df4e022bffdeac GIT binary patch literal 1398256 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

eCw~<`+t#c7`zL<|eE|XLOuAQp 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

O_>PnA`PVy$Z_cGQ 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�f&ukw!QKYsIFY={;81@gNT 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 Zd+a)TWmgE%LQE%0cpkaJ7#n`h{{f5nL23X1 literal 0 HcmV?d00001 diff --git a/libs/eastl/.appveyor.yml b/libs/eastl/.appveyor.yml new file mode 100644 index 0000000..9751ffc --- /dev/null +++ b/libs/eastl/.appveyor.yml @@ -0,0 +1,24 @@ +version: 1.0.{build} + +os: + - Visual Studio 2015 + - Visual Studio 2013 + +platform: + - x86 + - x64 + +build_script: + - cmd: mkdir build + - cmd: cd build + - cmd: cmake .. -DEASTL_BUILD_BENCHMARK:BOOL=ON -DEASTL_BUILD_TESTS:BOOL=ON + - cmd: cmake --build . --config Debug + - cmd: cmake --build . --config Release + +test_script: + - cmd: cd test + - cmd: ctest -C Release -V + - cmd: cd .. + - cmd: cd benchmark + - cmd: ctest -C Release -V + - cmd: cd .. diff --git a/libs/eastl/.clang-format b/libs/eastl/.clang-format new file mode 100644 index 0000000..ccd1128 --- /dev/null +++ b/libs/eastl/.clang-format @@ -0,0 +1,32 @@ +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#- +Language : Cpp +BasedOnStyle : Google +Standard : Auto +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#- +AccessModifierOffset : -4 +AlignTrailingComments : true +AllowAllParametersOfDeclarationOnNextLine : false +AllowShortBlocksOnASingleLine : true +AllowShortFunctionsOnASingleLine : true +AllowShortIfStatementsOnASingleLine : false +AllowShortLoopsOnASingleLine : false +BinPackParameters : false +BreakBeforeBraces : Allman +BreakBeforeTernaryOperators : false +BreakConstructorInitializersBeforeComma : true +ColumnLimit : 120 +Cpp11BracedListStyle : true +DerivePointerAlignment : true +DerivePointerBinding : false +IndentWidth : 4 +KeepEmptyLinesAtTheStartOfBlocks : true +MaxEmptyLinesToKeep : 2 +NamespaceIndentation : Inner +PointerBindsToType : true +SpacesBeforeTrailingComments : 1 +SpacesInAngles : false +SpacesInSquareBrackets : false +TabWidth : 4 +UseTab : ForIndentation +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#- +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#- diff --git a/libs/eastl/.gitattributes b/libs/eastl/.gitattributes new file mode 100644 index 0000000..e0800fd --- /dev/null +++ b/libs/eastl/.gitattributes @@ -0,0 +1,3 @@ +# Auto detect text files and perform LF normalization +# http://git-scm.com/docs/gitattributes +* text=auto diff --git a/libs/eastl/.gitignore b/libs/eastl/.gitignore new file mode 100644 index 0000000..5dd7ab0 --- /dev/null +++ b/libs/eastl/.gitignore @@ -0,0 +1,36 @@ +tags +**/*.swp +**/*.swo +.swp +*.swp +.swo +-.d +eastl_build_out +build_bench +bench.bat +build.bat + +## CMake generated files +CMakeCache.txt +cmake_install.cmake + +## Patch files +*.patch + +## For Visual Studio Generated projects +*.sln +**/*.vcxproj +**/*.vcxproj.filters +*.VC.opendb +*.sdf +.vs/* +**/Debug/* +CMakeFiles/* +EASTL.dir/** +RelWithDebInfo/* +Release/* +Win32/* +x64/* +MinSizeRel/* +build/* +Testing/* diff --git a/libs/eastl/.p4ignore b/libs/eastl/.p4ignore new file mode 100644 index 0000000..f4eb09f --- /dev/null +++ b/libs/eastl/.p4ignore @@ -0,0 +1,2 @@ +/.git/ +tags diff --git a/libs/eastl/.travis.yml b/libs/eastl/.travis.yml new file mode 100644 index 0000000..6570e47 --- /dev/null +++ b/libs/eastl/.travis.yml @@ -0,0 +1,58 @@ +language: cpp + +os: + - linux + - osx + +compiler: + - gcc + - clang + +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-4.8 + - g++-4.8 + - clang + +matrix: + exclude: + - os: osx + compiler: gcc + +install: +# Linux Setup + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wget --no-check-certificate http://cmake.org/files/v3.4/cmake-3.4.3-Linux-x86_64.tar.gz ;fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then tar -xzf cmake-3.4.3-Linux-x86_64.tar.gz ;fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8" ;fi ;fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export PATH=$PWD/cmake-3.4.3-Linux-x86_64/bin:$PATH ;fi +# OSX Setup + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then wget --no-check-certificate http://cmake.org/files/v3.4/cmake-3.4.3-Darwin-x86_64.tar.gz ;fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then tar -xzf cmake-3.4.3-Darwin-x86_64.tar.gz ;fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PATH=$PWD/cmake-3.4.3-Darwin-x86_64/CMake.app/Contents/bin:$PATH ;fi + +script: +# Debug Build + - mkdir build_debug + - cd build_debug + - cmake .. -DEASTL_BUILD_BENCHMARK:BOOL=ON -DEASTL_BUILD_TESTS:BOOL=ON + - cmake --build . --config Debug + - cd .. +# Release Build + - mkdir build_release + - cd build_release + - cmake .. -DEASTL_BUILD_BENCHMARK:BOOL=ON -DEASTL_BUILD_TESTS:BOOL=ON + - cmake --build . --config Release + # - cd .. + +after_success: +# Run Release Tests + - cd test + - ctest -C Release -V + - cd .. +# Run Release Benchmarks + - cd benchmark + - ctest -C Release -V + diff --git a/libs/eastl/3RDPARTYLICENSES.TXT b/libs/eastl/3RDPARTYLICENSES.TXT new file mode 100644 index 0000000..9c286fb --- /dev/null +++ b/libs/eastl/3RDPARTYLICENSES.TXT @@ -0,0 +1,103 @@ +Additional licenses also apply to this software package as detailed below. + + + +HP STL comes with the following license: + +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 1994 +// Hewlett-Packard Company +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. Hewlett-Packard Company makes no +// representations about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. +/////////////////////////////////////////////////////////////////////////////// + + + +libc++ comes with the following license: + +============================================================================== +libc++ License +============================================================================== + +The libc++ library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2015 by the contributors listed at +http://llvm.org/svn/llvm-project/libcxx/trunk/CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2014 by the contributors listed at +http://llvm.org/svn/llvm-project/libcxx/trunk/CREDITS.TXT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + diff --git a/libs/eastl/CMakeLists.txt b/libs/eastl/CMakeLists.txt new file mode 100644 index 0000000..045ebb9 --- /dev/null +++ b/libs/eastl/CMakeLists.txt @@ -0,0 +1,85 @@ +#------------------------------------------------------------------------------------------- +# Copyright (C) Electronic Arts Inc. All rights reserved. +#------------------------------------------------------------------------------------------- +cmake_minimum_required(VERSION 3.1) +project(EASTL) + +#------------------------------------------------------------------------------------------- +# Options +#------------------------------------------------------------------------------------------- +option(EASTL_BUILD_BENCHMARK "Enable generation of build files for benchmark" OFF) +option(EASTL_BUILD_TESTS "Enable generation of build files for tests" OFF) + +#------------------------------------------------------------------------------------------- +# Sub-projects +#------------------------------------------------------------------------------------------- +add_subdirectory(test/packages/EABase) + +if(EASTL_BUILD_TESTS OR EASTL_BUILD_BENCHMARK) + add_subdirectory(test/packages/EAAssert) + add_subdirectory(test/packages/EAStdC) + add_subdirectory(test/packages/EAMain) + add_subdirectory(test/packages/EATest) + add_subdirectory(test/packages/EAThread) +endif() + +if(EASTL_BUILD_BENCHMARK) + add_subdirectory(benchmark) +endif() + +if(EASTL_BUILD_TESTS) + add_subdirectory(test) +endif() + +#------------------------------------------------------------------------------------------- +# Defines +#------------------------------------------------------------------------------------------- +add_definitions(-D_CHAR16T) +add_definitions(-D_CRT_SECURE_NO_WARNINGS) +add_definitions(-D_SCL_SECURE_NO_WARNINGS) +add_definitions(-DEASTL_OPENSOURCE=1) + +#------------------------------------------------------------------------------------------- +# Library definition +#------------------------------------------------------------------------------------------- +file(GLOB EASTL_SOURCES "source/*.cpp" "include/EASTL/*.h") +add_library(EASTL ${EASTL_SOURCES}) + +#------------------------------------------------------------------------------------------- +# Compiler Flags +#------------------------------------------------------------------------------------------- +set_property(TARGET EASTL PROPERTY CXX_STANDARD 11) + +if(EASTL_BUILD_TESTS OR EASTL_BUILD_BENCHMARK) + set_property(TARGET EAStdC EATest PROPERTY CXX_STANDARD 11) +endif() + +if( UNIX AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fasm-blocks" ) +endif() + +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +endif() + +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG") +endif() + +#------------------------------------------------------------------------------------------- +# Include dirs +#------------------------------------------------------------------------------------------- +target_include_directories(EASTL PUBLIC include) + +#------------------------------------------------------------------------------------------- +# Libraries +#------------------------------------------------------------------------------------------- +target_link_libraries(EASTL EABase) + +#------------------------------------------------------------------------------------------- +# Installation +#------------------------------------------------------------------------------------------- +install(TARGETS EASTL DESTINATION lib) +install(DIRECTORY include/EASTL DESTINATION include) +install(DIRECTORY test/packages/EABase/include/Common/EABase DESTINATION include) diff --git a/libs/eastl/CONTRIBUTING.md b/libs/eastl/CONTRIBUTING.md new file mode 100644 index 0000000..74bd209 --- /dev/null +++ b/libs/eastl/CONTRIBUTING.md @@ -0,0 +1,71 @@ +## Contributing + +Before you can contribute, EA must have a Contributor License Agreement (CLA) on file that has been signed by each contributor. +You can sign here: [Go to CLA](https://goo.gl/KPylZ3) + +### Pull Request Policy + +All code contributions to EASTL are submitted as [Github pull requests](https://help.github.com/articles/using-pull-requests/). All pull requests will be reviewed by an EASTL maintainer according to the guidelines found in the next section. + +Your pull request should: + +* merge cleanly +* come with tests + * tests should be minimal and stable + * fail before your fix is applied +* pass the test suite +* code formatting is encoded in clang format + * limit using clang format on new code + * do not deviate from style already established in the files + + +### Running the Unit Tests + +EASTL uses CMake as its build system. + +* Create and navigate to "your_build_folder": + * mkdir your_build_folder && cd your_build_folder +* Generate build scripts: + * cmake eastl_source_folder -DEASTL_BUILD_TESTS:BOOL=ON +* Build unit tests for "your_config": + * cmake --build . --config your_config +* Run the unit tests for "your_config" from the test folder: + * cd test && ctest -C your_config + +Here is an example batch file. +```batch +set build_folder=out +mkdir %build_folder% +pushd %build_folder% +call cmake .. -DEASTL_BUILD_TESTS:BOOL=ON +call cmake --build . --config Release +call cmake --build . --config Debug +call cmake --build . --config RelWithDebInfo +call cmake --build . --config MinSizeRel +pushd test +call ctest -C Release +call ctest -C Debug +call ctest -C RelWithDebInfo +call ctest -C MinSizeRel +popd +popd +``` + +Here is an example bash file +```bash +build_folder=out +mkdir $build_folder +pushd $build_folder +cmake .. -DEASTL_BUILD_TESTS:BOOL=ON +cmake --build . --config Release +cmake --build . --config Debug +cmake --build . --config RelWithDebInfo +cmake --build . --config MinSizeRel +pushd test +ctest -C Release +ctest -C Debug +ctest -C RelWithDebInfo +ctest -C MinSizeRel +popd +popd +``` diff --git a/libs/eastl/LICENSE b/libs/eastl/LICENSE new file mode 100644 index 0000000..8a049d0 --- /dev/null +++ b/libs/eastl/LICENSE @@ -0,0 +1,27 @@ +/* +Copyright (C) 2015 Electronic Arts Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ diff --git a/libs/eastl/README.md b/libs/eastl/README.md new file mode 100644 index 0000000..f928e4f --- /dev/null +++ b/libs/eastl/README.md @@ -0,0 +1,43 @@ +# EA Standard Template Library + +[![Build Status](https://travis-ci.org/electronicarts/EASTL.svg?branch=master)](https://travis-ci.org/electronicarts/EASTL) [![Build status](https://ci.appveyor.com/api/projects/status/dtn82qr8tw8o3vmi?svg=true)](https://ci.appveyor.com/project/rparolin/eastl) [![Join the chat at https://gitter.im/electronicarts/EASTL](https://badges.gitter.im/electronicarts/EASTL.svg)](https://gitter.im/electronicarts/EASTL?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +EASTL stands for Electronic Arts Standard Template Library. It is a C++ template library of containers, algorithms, and iterators useful for runtime and tool development across multiple platforms. It is a fairly extensive and robust implementation of such a library and has an emphasis on high performance above all other considerations. + + +## Usage + +If you are familiar with the C++ STL or have worked with other templated container/algorithm libraries, you probably don't need to read this. If you have no familiarity with C++ templates at all, then you probably will need more than this document to get you up to speed. In this case, you need to understand that templates, when used properly, are powerful vehicles for the ease of creation of optimized C++ code. A description of C++ templates is outside the scope of this documentation, but there is plenty of such documentation on the Internet. + +EASTL is suitable for any tools and shipping applications where the functionality of EASTL is useful. Modern compilers are capable of producing good code with templates and many people are using them in both current generation and future generation applications on multiple platforms from embedded systems to servers and mainframes. + + +## Documentation + +Please see [EASTL Introduction](https://rawgit.com/electronicarts/EASTL/master/doc/EASTL%20Introduction.html). + + +## Compiling sources + +Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on compiling and testing the source. + +## Credits + +EASTL was created by Paul Pedriana and he maintained the project for roughly 10 years. + +Roberto Parolin is the current EASTL owner within EA and is responsible for the open source repository. + +Significant EASTL contributions were made by (in alphabetical order): + +* Avery Lee +* Colin Andrews +* JP Flouret +* Matt Newport +* Paul Pedriana +* Roberto Parolin +* Simon Everett + + +## License + +Modified BSD License (3-Clause BSD license) see the file LICENSE in the project root. diff --git a/libs/eastl/include/EASTL/algorithm.h b/libs/eastl/include/EASTL/algorithm.h new file mode 100644 index 0000000..19c6401 --- /dev/null +++ b/libs/eastl/include/EASTL/algorithm.h @@ -0,0 +1,4167 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements some of the primary algorithms from the C++ STL +// algorithm library. These versions are just like that STL versions and so +// are redundant. They are provided solely for the purpose of projects that +// either cannot use standard C++ STL or want algorithms that have guaranteed +// identical behaviour across platforms. +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Definitions +// +// You will notice that we are very particular about the templated typenames +// we use here. You will notice that we follow the C++ standard closely in +// these respects. Each of these typenames have a specific meaning; +// this is why we don't just label templated arguments with just letters +// such as T, U, V, A, B. Here we provide a quick reference for the typenames +// we use. See the C++ standard, section 25-8 for more details. +// -------------------------------------------------------------- +// typename Meaning +// -------------------------------------------------------------- +// T The value type. +// Compare A function which takes two arguments and returns the lesser of the two. +// Predicate A function which takes one argument returns true if the argument meets some criteria. +// BinaryPredicate A function which takes two arguments and returns true if some criteria is met (e.g. they are equal). +// StrickWeakOrdering A BinaryPredicate that compares two objects, returning true if the first precedes the second. Like Compare but has additional requirements. Used for sorting routines. +// Function A function which takes one argument and applies some operation to the target. +// Size A count or size. +// Generator A function which takes no arguments and returns a value (which will usually be assigned to an object). +// UnaryOperation A function which takes one argument and returns a value (which will usually be assigned to second object). +// BinaryOperation A function which takes two arguments and returns a value (which will usually be assigned to a third object). +// InputIterator An input iterator (iterator you read from) which allows reading each element only once and only in a forward direction. +// ForwardIterator An input iterator which is like InputIterator except it can be reset back to the beginning. +// BidirectionalIterator An input iterator which is like ForwardIterator except it can be read in a backward direction as well. +// RandomAccessIterator An input iterator which can be addressed like an array. It is a superset of all other input iterators. +// OutputIterator An output iterator (iterator you write to) which allows writing each element only once in only in a forward direction. +// +// Note that with iterators that a function which takes an InputIterator will +// also work with a ForwardIterator, BidirectionalIterator, or RandomAccessIterator. +// The given iterator type is merely the -minimum- supported functionality the +// iterator must support. +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Optimizations +// +// There are a number of opportunities for opptimizations that we take here +// in this library. The most obvious kinds are those that subsitute memcpy +// in the place of a conventional loop for data types with which this is +// possible. The algorithms here are optimized to a higher level than currently +// available C++ STL algorithms from vendors such as Microsoft. This is especially +// so for game programming on console devices, as we do things such as reduce +// branching relative to other STL algorithm implementations. However, the +// proper implementation of these algorithm optimizations is a fairly tricky +// thing. +// +// The various things we look to take advantage of in order to implement +// optimizations include: +// - Taking advantage of random access iterators. +// - Taking advantage of POD (plain old data) data types. +// - Taking advantage of type_traits in general. +// - Reducing branching and taking advantage of likely branch predictions. +// - Taking advantage of issues related to pointer and reference aliasing. +// - Improving cache coherency during memory accesses. +// - Making code more likely to be inlinable by the compiler. +// +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Supported Algorithms +// +// Algorithms that we implement are listed here. Note that these items are not +// all within this header file, as we split up the header files in order to +// improve compilation performance. Items marked with '+' are items that are +// extensions which don't exist in the C++ standard. +// +// ------------------------------------------------------------------------------- +// Algorithm Notes +// ------------------------------------------------------------------------------- +// adjacent_find +// adjacent_find +// all_of C++11 +// any_of C++11 +// none_of C++11 +// binary_search +// binary_search +// +binary_search_i +// +binary_search_i +// +change_heap Found in heap.h +// +change_heap Found in heap.h +// copy +// copy_if C++11 +// copy_n C++11 +// copy_backward +// count +// count_if +// equal +// equal +// equal_range +// equal_range +// fill +// fill_n +// find +// find_end +// find_end +// find_first_of +// find_first_of +// +find_first_not_of +// +find_first_not_of +// +find_last_of +// +find_last_of +// +find_last_not_of +// +find_last_not_of +// find_if +// find_if_not +// for_each +// generate +// generate_n +// +identical +// +identical +// iter_swap +// lexicographical_compare +// lexicographical_compare +// lower_bound +// lower_bound +// make_heap Found in heap.h +// make_heap Found in heap.h +// min +// min +// max +// max +// +min_alt Exists to work around the problem of conflicts with min/max #defines on some systems. +// +min_alt +// +max_alt +// +max_alt +// +median +// +median +// merge Found in sort.h +// merge Found in sort.h +// min_element +// min_element +// max_element +// max_element +// mismatch +// mismatch +// move +// move_backward +// nth_element Found in sort.h +// nth_element Found in sort.h +// partial_sort Found in sort.h +// partial_sort Found in sort.h +// push_heap Found in heap.h +// push_heap Found in heap.h +// pop_heap Found in heap.h +// pop_heap Found in heap.h +// random_shuffle +// remove +// remove_if +// remove_copy +// remove_copy_if +// +remove_heap Found in heap.h +// +remove_heap Found in heap.h +// replace +// replace_if +// replace_copy +// replace_copy_if +// reverse_copy +// reverse +// rotate +// rotate_copy +// search +// search +// search_n +// set_difference +// set_difference +// set_intersection +// set_intersection +// set_symmetric_difference +// set_symmetric_difference +// sort Found in sort.h +// sort Found in sort.h +// sort_heap Found in heap.h +// sort_heap Found in heap.h +// stable_sort Found in sort.h +// stable_sort Found in sort.h +// swap +// swap_ranges +// transform +// transform +// unique +// unique +// upper_bound +// upper_bound +// is_permutation +// is_permutation +// next_permutation +// next_permutation +// +// Algorithms from the C++ standard that we don't implement are listed here. +// Most of these items are absent because they aren't used very often. +// They also happen to be the more complicated than other algorithms. +// However, we can implement any of these functions for users that might +// need them. +// includes +// includes +// inplace_merge +// inplace_merge +// partial_sort_copy +// partial_sort_copy +// paritition +// prev_permutation +// prev_permutation +// random_shuffle +// search_n +// set_union +// set_union +// stable_partition +// unique_copy +// unique_copy +// +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_ALGORITHM_H +#define EASTL_ALGORITHM_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + #pragma warning(push, 0) + #if defined(EA_COMPILER_MICROSOFT) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) + #include + #endif +#endif + #include + #include // memcpy, memcmp, memmove +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// min/max workaround +// +// MSVC++ has #defines for min/max which collide with the min/max algorithm +// declarations. The following may still not completely resolve some kinds of +// problems with MSVC++ #defines, though it deals with most cases in production +// game code. +// +#if EASTL_NOMINMAX + #ifdef min + #undef min + #endif + #ifdef max + #undef max + #endif +#endif + + + + +namespace eastl +{ + /// min_element + /// + /// min_element finds the smallest element in the range [first, last). + /// It returns the first iterator i in [first, last) such that no other + /// iterator in [first, last) points to a value smaller than *i. + /// The return value is last if and only if [first, last) is an empty range. + /// + /// Returns: The first iterator i in the range [first, last) such that + /// for any iterator j in the range [first, last) the following corresponding + /// condition holds: !(*j < *i). + /// + /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the + /// corresponding comparisons. + /// + template + ForwardIterator min_element(ForwardIterator first, ForwardIterator last) + { + if(first != last) + { + ForwardIterator currentMin = first; + + while(++first != last) + { + if(*first < *currentMin) + currentMin = first; + } + return currentMin; + } + return first; + } + + + /// min_element + /// + /// min_element finds the smallest element in the range [first, last). + /// It returns the first iterator i in [first, last) such that no other + /// iterator in [first, last) points to a value smaller than *i. + /// The return value is last if and only if [first, last) is an empty range. + /// + /// Returns: The first iterator i in the range [first, last) such that + /// for any iterator j in the range [first, last) the following corresponding + /// conditions hold: compare(*j, *i) == false. + /// + /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the + /// corresponding comparisons. + /// + template + ForwardIterator min_element(ForwardIterator first, ForwardIterator last, Compare compare) + { + if(first != last) + { + ForwardIterator currentMin = first; + + while(++first != last) + { + if(compare(*first, *currentMin)) + currentMin = first; + } + return currentMin; + } + return first; + } + + + /// max_element + /// + /// max_element finds the largest element in the range [first, last). + /// It returns the first iterator i in [first, last) such that no other + /// iterator in [first, last) points to a value greater than *i. + /// The return value is last if and only if [first, last) is an empty range. + /// + /// Returns: The first iterator i in the range [first, last) such that + /// for any iterator j in the range [first, last) the following corresponding + /// condition holds: !(*i < *j). + /// + /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the + /// corresponding comparisons. + /// + template + ForwardIterator max_element(ForwardIterator first, ForwardIterator last) + { + if(first != last) + { + ForwardIterator currentMax = first; + + while(++first != last) + { + if(*currentMax < *first) + currentMax = first; + } + return currentMax; + } + return first; + } + + + /// max_element + /// + /// max_element finds the largest element in the range [first, last). + /// It returns the first iterator i in [first, last) such that no other + /// iterator in [first, last) points to a value greater than *i. + /// The return value is last if and only if [first, last) is an empty range. + /// + /// Returns: The first iterator i in the range [first, last) such that + /// for any iterator j in the range [first, last) the following corresponding + /// condition holds: compare(*i, *j) == false. + /// + /// Complexity: Exactly 'max((last - first) - 1, 0)' applications of the + /// corresponding comparisons. + /// + template + ForwardIterator max_element(ForwardIterator first, ForwardIterator last, Compare compare) + { + if(first != last) + { + ForwardIterator currentMax = first; + + while(++first != last) + { + if(compare(*currentMax, *first)) + currentMax = first; + } + return currentMax; + } + return first; + } + + + #if EASTL_MINMAX_ENABLED + + /// min + /// + /// Min returns the lesser of its two arguments; it returns the first + /// argument if neither is less than the other. The two arguments are + /// compared with operator <. + /// + /// This min and our other min implementations are defined as returning: + /// b < a ? b : a + /// which for example may in practice result in something different than: + /// b <= a ? b : a + /// in the case where b is different from a (though they compare as equal). + /// We choose the specific ordering here because that's the ordering + /// done by other STL implementations. + /// + /// Some compilers (e.g. VS20003 - VS2013) generate poor code for the case of + /// scalars returned by reference, so we provide a specialization for those cases. + /// The specialization returns T by value instead of reference, which is + /// not that the Standard specifies. The Standard allows you to use + /// an expression like &max(x, y), which would be impossible in this case. + /// However, we have found no actual code that uses min or max like this and + /// this specialization causes no problems in practice. Microsoft has acknowledged + /// the problem and may fix it for a future VS version. + /// + template + inline EA_CONSTEXPR typename eastl::enable_if::value, T>::type + min(T a, T b) + { + return b < a ? b : a; + } + + template + inline typename eastl::enable_if::value, const T&>::type + min(const T& a, const T& b) + { + return b < a ? b : a; + } + + #if defined(_MSC_VER) && defined(EA_PROCESSOR_POWERPC) + inline float + min(float a, float b) + { + return (float)__fsel(a - b, b, a); + } + + inline double + min(double a, double b) + { + return (double)__fsel(a - b, b, a); + } + + #elif defined(_MSC_VER) && defined(EA_PROCESSOR_X86) + + // We used to have x86 asm here, but it didn't improve performance. + + #elif defined(__GNUC__) && defined(EA_PROCESSOR_POWERPC) + inline float + min(float a, float b) + { + float result, test(a - b); + __asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (b), "f" (a)); + return result; + } + + inline double + min(double a, double b) + { + double result, test(a - b); + __asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (b), "f" (a)); + return result; + } + #else + inline EA_CONSTEXPR float min(float a, float b) { return b < a ? b : a; } + inline EA_CONSTEXPR double min(double a, double b) { return b < a ? b : a; } + inline EA_CONSTEXPR long double min(long double a, long double b) { return b < a ? b : a; } + #endif + + #endif // EASTL_MINMAX_ENABLED + + + /// min_alt + /// + /// This is an alternative version of min that avoids any possible + /// collisions with Microsoft #defines of min and max. + /// + /// See min(a, b) for detailed specifications. + /// + template + inline EA_CONSTEXPR typename eastl::enable_if::value, T>::type + min_alt(T a, T b) + { + return b < a ? b : a; + } + + template + inline typename eastl::enable_if::value, const T&>::type + min_alt(const T& a, const T& b) + { + return b < a ? b : a; + } + + + #if defined(_MSC_VER) && defined(EA_PROCESSOR_POWERPC) + inline float + min_alt(float a, float b) + { + return (float)__fsel(a - b, b, a); + } + + inline double + min_alt(double a, double b) + { + return (double)__fsel(a - b, b, a); + } + + #elif defined(_MSC_VER) && defined(EA_PROCESSOR_X86) + + // We used to have x86 asm here, but it didn't improve performance. + + #elif defined(__GNUC__) && defined(EA_PROCESSOR_POWERPC) + inline float + min_alt(float a, float b) + { + float result, test(a - b); + __asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (b), "f" (a)); + return result; + } + + inline double + min_alt(double a, double b) + { + double result, test(a - b); + __asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (b), "f" (a)); + return result; + } + #else + inline EA_CONSTEXPR float min_alt(float a, float b) { return b < a ? b : a; } + inline EA_CONSTEXPR double min_alt(double a, double b) { return b < a ? b : a; } + inline EA_CONSTEXPR long double min_alt(long double a, long double b) { return b < a ? b : a; } + #endif + + + #if EASTL_MINMAX_ENABLED + /// min + /// + /// Min returns the lesser of its two arguments; it returns the first + /// argument if neither is less than the other. The two arguments are + /// compared with the Compare function (or function object), which + /// takes two arguments and returns true if the first is less than + /// the second. + /// + /// See min(a, b) for detailed specifications. + /// + /// Example usage: + /// struct A{ int a; }; + /// struct Struct{ bool operator()(const A& a1, const A& a2){ return a1.a < a2.a; } }; + /// + /// A a1, a2, a3; + /// a3 = min(a1, a2, Struct()); + /// + /// Example usage: + /// struct B{ int b; }; + /// inline bool Function(const B& b1, const B& b2){ return b1.b < b2.b; } + /// + /// B b1, b2, b3; + /// b3 = min(b1, b2, Function); + /// + template + inline const T& + min(const T& a, const T& b, Compare compare) + { + return compare(b, a) ? b : a; + } + + #endif // EASTL_MINMAX_ENABLED + + + /// min_alt + /// + /// This is an alternative version of min that avoids any possible + /// collisions with Microsoft #defines of min and max. + /// + /// See min(a, b) for detailed specifications. + /// + template + inline const T& + min_alt(const T& a, const T& b, Compare compare) + { + return compare(b, a) ? b : a; + } + + + #if EASTL_MINMAX_ENABLED + /// max + /// + /// Max returns the greater of its two arguments; it returns the first + /// argument if neither is greater than the other. The two arguments are + /// compared with operator < (and not operator >). + /// + /// This min and our other min implementations are defined as returning: + /// a < b ? b : a + /// which for example may in practice result in something different than: + /// a <= b ? b : a + /// in the case where b is different from a (though they compare as equal). + /// We choose the specific ordering here because that's the ordering + /// done by other STL implementations. + /// + template + inline EA_CONSTEXPR typename eastl::enable_if::value, T>::type + max(T a, T b) + { + return a < b ? b : a; + } + + template + inline typename eastl::enable_if::value, const T&>::type + max(const T& a, const T& b) + { + return a < b ? b : a; + } + + + #if defined(_MSC_VER) && defined(EA_PROCESSOR_POWERPC) + inline float + max(float a, float b) + { + return (float)__fsel(a - b, a, b); + } + + inline double + max(double a, double b) + { + return (double)__fsel(a - b, a, b); + } + + #elif defined(_MSC_VER) && defined(EA_PROCESSOR_X86) + + // We used to have x86 asm here, but it didn't improve performance. + + #elif defined(__GNUC__) && defined(EA_PROCESSOR_POWERPC) + inline float + max(float a, float b) + { + float result, test(a - b); + __asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (a), "f" (b)); + return result; + } + + inline double + max(double a, double b) + { + double result, test(a - b); + __asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (a), "f" (b)); + return result; + } + #else + inline EA_CONSTEXPR float max(float a, float b) { return a < b ? b : a; } + inline EA_CONSTEXPR double max(double a, double b) { return a < b ? b : a; } + inline EA_CONSTEXPR long double max(long double a, long double b) { return a < b ? b : a; } + #endif + + #endif // EASTL_MINMAX_ENABLED + + + /// max_alt + /// + /// This is an alternative version of max that avoids any possible + /// collisions with Microsoft #defines of min and max. + /// + template + inline EA_CONSTEXPR typename eastl::enable_if::value, T>::type + max_alt(T a, T b) + { + return a < b ? b : a; + } + + template + inline typename eastl::enable_if::value, const T&>::type + max_alt(const T& a, const T& b) + { + return a < b ? b : a; + } + + #if defined(_MSC_VER) && defined(EA_PROCESSOR_POWERPC) + inline float + max_alt(float a, float b) + { + return (float)__fsel(a - b, a, b); + } + + inline double + max_alt(double a, double b) + { + return (double)__fsel(a - b, a, b); + } + + #elif defined(_MSC_VER) && defined(EA_PROCESSOR_X86) + + // We used to have x86 asm here, but it didn't improve performance. + + #elif defined(__GNUC__) && defined(EA_PROCESSOR_POWERPC) + inline float + max_alt(float a, float b) + { + float result, test(a - b); + __asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (a), "f" (b)); + return result; + } + + inline double + max_alt(double a, double b) + { + double result, test(a - b); + __asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (a), "f" (b)); + return result; + } + #else + inline EA_CONSTEXPR float max_alt(float a, float b) { return a < b ? b : a; } + inline EA_CONSTEXPR double max_alt(double a, double b) { return a < b ? b : a; } + inline EA_CONSTEXPR long double max_alt(long double a, long double b) { return a < b ? b : a; } + #endif + + + #if EASTL_MINMAX_ENABLED + /// max + /// + /// Min returns the lesser of its two arguments; it returns the first + /// argument if neither is less than the other. The two arguments are + /// compared with the Compare function (or function object), which + /// takes two arguments and returns true if the first is less than + /// the second. + /// + template + inline const T& + max(const T& a, const T& b, Compare compare) + { + return compare(a, b) ? b : a; + } + #endif + + + /// max_alt + /// + /// This is an alternative version of max that avoids any possible + /// collisions with Microsoft #defines of min and max. + /// + template + inline const T& + max_alt(const T& a, const T& b, Compare compare) + { + return compare(a, b) ? b : a; + } + + + /// min(std::initializer_list) + /// + template + T min(std::initializer_list ilist) + { + return *eastl::min_element(ilist.begin(), ilist.end()); + } + + /// min(std::initializer_list, Compare) + /// + template + T min(std::initializer_list ilist, Compare compare) + { + return *eastl::min_element(ilist.begin(), ilist.end(), compare); + } + + + /// max(std::initializer_list) + /// + template + T max(std::initializer_list ilist) + { + return *eastl::max_element(ilist.begin(), ilist.end()); + } + + /// max(std::initializer_list, Compare) + /// + template + T max(std::initializer_list ilist, Compare compare) + { + return *eastl::max_element(ilist.begin(), ilist.end(), compare); + } + + + /// minmax_element + /// + /// Returns: make_pair(first, first) if [first, last) is empty, otherwise make_pair(m, M), + /// where m is the first iterator in [first,last) such that no iterator in the range + /// refers to a smaller element, and where M is the last iterator in [first,last) such + /// that no iterator in the range refers to a larger element. + /// + /// Complexity: At most max([(3/2)*(N - 1)], 0) applications of the corresponding predicate, + /// where N is distance(first, last). + /// + template + eastl::pair + minmax_element(ForwardIterator first, ForwardIterator last, Compare compare) + { + eastl::pair result(first, first); + + if(!(first == last) && !(++first == last)) + { + if(compare(*first, *result.first)) + { + result.second = result.first; + result.first = first; + } + else + result.second = first; + + while(++first != last) + { + ForwardIterator i = first; + + if(++first == last) + { + if(compare(*i, *result.first)) + result.first = i; + else if(!compare(*i, *result.second)) + result.second = i; + break; + } + else + { + if(compare(*first, *i)) + { + if(compare(*first, *result.first)) + result.first = first; + + if(!compare(*i, *result.second)) + result.second = i; + } + else + { + if(compare(*i, *result.first)) + result.first = i; + + if(!compare(*first, *result.second)) + result.second = first; + } + } + } + } + + return result; + } + + + template + eastl::pair + minmax_element(ForwardIterator first, ForwardIterator last) + { + typedef typename eastl::iterator_traits::value_type value_type; + + return eastl::minmax_element(first, last, eastl::less()); + } + + + + /// minmax + /// + /// Requires: Type T shall be LessThanComparable. + /// Returns: pair(b, a) if b is smaller than a, and pair(a, b) otherwise. + /// Remarks: Returns pair(a, b) when the arguments are equivalent. + /// Complexity: Exactly one comparison. + /// + + // The following optimization is a problem because it changes the return value in a way that would break + // users unless they used auto (e.g. auto result = minmax(17, 33); ) + // + // template + // inline EA_CONSTEXPR typename eastl::enable_if::value, eastl::pair >::type + // minmax(T a, T b) + // { + // return (b < a) ? eastl::make_pair(b, a) : eastl::make_pair(a, b); + // } + // + // template + // inline typename eastl::enable_if::value, eastl::pair >::type + // minmax(const T& a, const T& b) + // { + // return (b < a) ? eastl::make_pair(b, a) : eastl::make_pair(a, b); + // } + + // It turns out that the following conforming definition of minmax generates a warning when used with VC++ up + // to at least VS2012. The VS2012 version of minmax is a broken and non-conforming definition, and we don't + // want to do that. We could do it for scalars alone, though we'd have to decide if we are going to do that + // for all compilers, because it changes the return value from a pair of references to a pair of values. + template + inline eastl::pair + minmax(const T& a, const T& b) + { + return (b < a) ? eastl::make_pair(b, a) : eastl::make_pair(a, b); + } + + + template + eastl::pair + minmax(const T& a, const T& b, Compare compare) + { + return compare(b, a) ? eastl::make_pair(b, a) : eastl::make_pair(a, b); + } + + + + template + eastl::pair + minmax(std::initializer_list ilist) + { + typedef typename std::initializer_list::iterator iterator_type; + eastl::pair iteratorPair = eastl::minmax_element(ilist.begin(), ilist.end()); + return eastl::make_pair(*iteratorPair.first, *iteratorPair.second); + } + + template + eastl::pair + minmax(std::initializer_list ilist, Compare compare) + { + typedef typename std::initializer_list::iterator iterator_type; + eastl::pair iteratorPair = eastl::minmax_element(ilist.begin(), ilist.end(), compare); + return eastl::make_pair(*iteratorPair.first, *iteratorPair.second); + } + + + /// median + /// + /// median finds which element of three (a, b, d) is in-between the other two. + /// If two or more elements are equal, the first (e.g. a before b) is chosen. + /// + /// Complexity: Either two or three comparisons will be required, depending + /// on the values. + /// + template + inline const T& median(const T& a, const T& b, const T& c) + { + if(a < b) + { + if(b < c) + return b; + else if(a < c) + return c; + else + return a; + } + else if(a < c) + return a; + else if(b < c) + return c; + return b; + } + + + /// median + /// + /// median finds which element of three (a, b, d) is in-between the other two. + /// If two or more elements are equal, the first (e.g. a before b) is chosen. + /// + /// Complexity: Either two or three comparisons will be required, depending + /// on the values. + /// + template + inline const T& median(const T& a, const T& b, const T& c, Compare compare) + { + if(compare(a, b)) + { + if(compare(b, c)) + return b; + else if(compare(a, c)) + return c; + else + return a; + } + else if(compare(a, c)) + return a; + else if(compare(b, c)) + return c; + return b; + } + + + + + /// all_of + /// + /// Returns: true if the unary predicate p returns true for all elements in the range [first, last) + /// + template + inline bool all_of(InputIterator first, InputIterator last, Predicate p) + { + for(; first != last; ++first) + { + if(!p(*first)) + return false; + } + return true; + } + + + /// any_of + /// + /// Returns: true if the unary predicate p returns true for any of the elements in the range [first, last) + /// + template + inline bool any_of(InputIterator first, InputIterator last, Predicate p) + { + for(; first != last; ++first) + { + if(p(*first)) + return true; + } + return false; + } + + + /// none_of + /// + /// Returns: true if the unary predicate p returns true for none of the elements in the range [first, last) + /// + template + inline bool none_of(InputIterator first, InputIterator last, Predicate p) + { + for(; first != last; ++first) + { + if(p(*first)) + return false; + } + return true; + } + + + /// adjacent_find + /// + /// Returns: The first iterator i such that both i and i + 1 are in the range + /// [first, last) for which the following corresponding conditions hold: *i == *(i + 1). + /// Returns last if no such iterator is found. + /// + /// Complexity: Exactly 'find(first, last, value) - first' applications of the corresponding predicate. + /// + template + inline ForwardIterator + adjacent_find(ForwardIterator first, ForwardIterator last) + { + if(first != last) + { + ForwardIterator i = first; + + for(++i; i != last; ++i) + { + if(*first == *i) + return first; + first = i; + } + } + return last; + } + + + + /// adjacent_find + /// + /// Returns: The first iterator i such that both i and i + 1 are in the range + /// [first, last) for which the following corresponding conditions hold: predicate(*i, *(i + 1)) != false. + /// Returns last if no such iterator is found. + /// + /// Complexity: Exactly 'find(first, last, value) - first' applications of the corresponding predicate. + /// + template + inline ForwardIterator + adjacent_find(ForwardIterator first, ForwardIterator last, BinaryPredicate predicate) + { + if(first != last) + { + ForwardIterator i = first; + + for(++i; i != last; ++i) + { + if(predicate(*first, *i)) + return first; + first = i; + } + } + return last; + } + + + /// shuffle + /// + /// New for C++11 + /// Randomizes a sequence of values via a user-supplied UniformRandomNumberGenerator. + /// The difference between this and the original random_shuffle function is that this uses the more + /// advanced and flexible UniformRandomNumberGenerator interface as opposed to the more + /// limited RandomNumberGenerator interface of random_shuffle. + /// + /// Effects: Shuffles the elements in the range [first, last) with uniform distribution. + /// + /// Complexity: Exactly '(last - first) - 1' swaps. + /// + /// Example usage: + /// struct Rand{ eastl_size_t operator()(eastl_size_t n) { return (eastl_size_t)(rand() % n); } }; // Note: The C rand function is poor and slow. + /// Rand randInstance; + /// shuffle(pArrayBegin, pArrayEnd, randInstance); + /// + #if EASTL_MOVE_SEMANTICS_ENABLED + // See the C++11 Standard, 26.5.1.3, Uniform random number generator requirements. + // Also http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution + + template + void shuffle(RandomAccessIterator first, RandomAccessIterator last, UniformRandomNumberGenerator&& urng) + { + if(first != last) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::make_unsigned::type unsigned_difference_type; + typedef typename eastl::uniform_int_distribution uniform_int_distribution; + typedef typename uniform_int_distribution::param_type uniform_int_distribution_param_type; + + uniform_int_distribution uid; + + for(RandomAccessIterator i = first + 1; i != last; ++i) + iter_swap(i, first + uid(urng, uniform_int_distribution_param_type(0, i - first))); + } + } + #endif + + + /// random_shuffle + /// + /// Randomizes a sequence of values. + /// + /// Effects: Shuffles the elements in the range [first, last) with uniform distribution. + /// + /// Complexity: Exactly '(last - first) - 1' swaps. + /// + /// Example usage: + /// eastl_size_t Rand(eastl_size_t n) { return (eastl_size_t)(rand() % n); } // Note: The C rand function is poor and slow. + /// pointer_to_unary_function randInstance(Rand); + /// random_shuffle(pArrayBegin, pArrayEnd, randInstance); + /// + /// Example usage: + /// struct Rand{ eastl_size_t operator()(eastl_size_t n) { return (eastl_size_t)(rand() % n); } }; // Note: The C rand function is poor and slow. + /// Rand randInstance; + /// random_shuffle(pArrayBegin, pArrayEnd, randInstance); + /// + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline void random_shuffle(RandomAccessIterator first, RandomAccessIterator last, RandomNumberGenerator&& rng) + #else + template + inline void random_shuffle(RandomAccessIterator first, RandomAccessIterator last, RandomNumberGenerator& rng) + #endif + { + typedef typename eastl::iterator_traits::difference_type difference_type; + + // We must do 'rand((i - first) + 1)' here and cannot do 'rand(last - first)', + // as it turns out that the latter results in unequal distribution probabilities. + // http://www.cigital.com/papers/download/developer_gambling.php + + for(RandomAccessIterator i = first + 1; i < last; ++i) + iter_swap(i, first + (difference_type)rng((eastl_size_t)((i - first) + 1))); + } + + + /// random_shuffle + /// + /// Randomizes a sequence of values. + /// + /// Effects: Shuffles the elements in the range [first, last) with uniform distribution. + /// + /// Complexity: Exactly '(last - first) - 1' swaps. + /// + /// Example usage: + /// random_shuffle(pArrayBegin, pArrayEnd); + /// + /// *** Disabled until we decide if we want to get into the business of writing random number generators. *** + /// + /// template + /// inline void random_shuffle(RandomAccessIterator first, RandomAccessIterator last) + /// { + /// for(RandomAccessIterator i = first + 1; i < last; ++i) + /// iter_swap(i, first + SomeRangedRandomNumberGenerator((i - first) + 1)); + /// } + + + + + + + /// move_n + /// + /// Same as move(InputIterator, InputIterator, OutputIterator) except based on count instead of iterator range. + /// + template + inline OutputIterator + move_n_impl(InputIterator first, Size n, OutputIterator result, EASTL_ITC_NS::input_iterator_tag) + { + for(; n > 0; --n) + *result++ = eastl::move(*first++); + return result; + } + + template + inline OutputIterator + move_n_impl(RandomAccessIterator first, Size n, OutputIterator result, EASTL_ITC_NS::random_access_iterator_tag) + { + return eastl::move(first, first + n, result); // Take advantage of the optimizations present in the move algorithm. + } + + + template + inline OutputIterator + move_n(InputIterator first, Size n, OutputIterator result) + { + typedef typename eastl::iterator_traits::iterator_category IC; + return eastl::move_n_impl(first, n, result, IC()); + } + + + + /// copy_n + /// + /// Same as copy(InputIterator, InputIterator, OutputIterator) except based on count instead of iterator range. + /// Effects: Copies exactly count values from the range beginning at first to the range beginning at result, if count > 0. Does nothing otherwise. + /// Returns: Iterator in the destination range, pointing past the last element copied if count>0 or first otherwise. + /// Complexity: Exactly count assignments, if count > 0. + /// + template + inline OutputIterator + copy_n_impl(InputIterator first, Size n, OutputIterator result, EASTL_ITC_NS::input_iterator_tag) + { + for(; n > 0; --n) + *result++ = *first++; + return result; + } + + template + inline OutputIterator + copy_n_impl(RandomAccessIterator first, Size n, OutputIterator result, EASTL_ITC_NS::random_access_iterator_tag) + { + return eastl::copy(first, first + n, result); // Take advantage of the optimizations present in the copy algorithm. + } + + + template + inline OutputIterator + copy_n(InputIterator first, Size n, OutputIterator result) + { + typedef typename eastl::iterator_traits::iterator_category IC; + return eastl::copy_n_impl(first, n, result, IC()); + } + + + /// copy_if + /// + /// Effects: Assigns to the result iterator only if the predicate is true. + /// + template + inline OutputIterator + copy_if(InputIterator first, InputIterator last, OutputIterator result, Predicate predicate) + { + // This implementation's performance could be improved by taking a more complicated approach like with the copy algorithm. + for(; first != last; ++first) + { + if(predicate(*first)) + *result++ = *first; + } + + return result; + } + + + + + // Implementation moving copying both trivial and non-trivial data via a lesser iterator than random-access. + template + struct move_and_copy_backward_helper + { + template + static BidirectionalIterator2 move_or_copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) + { + while(first != last) + *--resultEnd = *--last; + return resultEnd; // resultEnd now points to the beginning of the destination sequence instead of the end. + } + }; + + // Specialization for moving non-trivial data via a lesser iterator than random-access. + template + struct move_and_copy_backward_helper + { + template + static BidirectionalIterator2 move_or_copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) + { + while(first != last) + *--resultEnd = eastl::move(*--last); + return resultEnd; // resultEnd now points to the beginning of the destination sequence instead of the end. + } + }; + + // Specialization for moving non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const. + template<> + struct move_and_copy_backward_helper + { + template + static BidirectionalIterator2 move_or_copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + + for(difference_type n = (last - first); n > 0; --n) + *--resultEnd = eastl::move(*--last); + return resultEnd; // resultEnd now points to the beginning of the destination sequence instead of the end. + } + }; + + // Specialization for copying non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const. + // This specialization converts the random access BidirectionalIterator1 last-first to an integral type. There's simple way for us to take advantage of a random access output iterator, + // as the range is specified by the input instead of the output, and distance(first, last) for a non-random-access iterator is potentially slow. + template <> + struct move_and_copy_backward_helper + { + template + static BidirectionalIterator2 move_or_copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + + for(difference_type n = (last - first); n > 0; --n) + *--resultEnd = *--last; + return resultEnd; // resultEnd now points to the beginning of the destination sequence instead of the end. + } + }; + + // Specialization for when we can use memmove/memcpy. See the notes above for what conditions allow this. + template + struct move_and_copy_backward_helper + { + template + static T* move_or_copy_backward(const T* first, const T* last, T* resultEnd) + { + return (T*)memmove(resultEnd - (last - first), first, (size_t)((uintptr_t)last - (uintptr_t)first)); + // We could use memcpy here if there's no range overlap, but memcpy is rarely much faster than memmove. + } + }; + + template + inline BidirectionalIterator2 move_and_copy_backward_chooser(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) + { + typedef typename eastl::iterator_traits::iterator_category IIC; + typedef typename eastl::iterator_traits::iterator_category OIC; + typedef typename eastl::iterator_traits::value_type value_type_input; + typedef typename eastl::iterator_traits::value_type value_type_output; + + const bool canBeMemmoved = eastl::is_trivially_copyable::value && + eastl::is_same::value && + (eastl::is_pointer::value || eastl::is_same::value) && + (eastl::is_pointer::value || eastl::is_same::value); + + return eastl::move_and_copy_backward_helper::move_or_copy_backward(first, last, resultEnd); // Need to chose based on the input iterator tag and not the output iterator tag, because containers accept input ranges of iterator types different than self. + } + + + // We have a second layer of unwrap_iterator calls because the original iterator might be something like move_iterator > (i.e. doubly-wrapped). + template + inline BidirectionalIterator2 move_and_copy_backward_unwrapper(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) + { + return BidirectionalIterator2(eastl::move_and_copy_backward_chooser(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), eastl::unwrap_iterator(resultEnd))); // Have to convert to BidirectionalIterator2 because result.base() could be a T* + } + + + /// move_backward + /// + /// The elements are moved in reverse order (the last element is moved first), but their relative order is preserved. + /// After this operation the elements in the moved-from range will still contain valid values of the + /// appropriate type, but not necessarily the same values as before the move. + /// Returns the beginning of the result range. + /// Note: When moving between containers, the dest range must be valid; this function doesn't resize containers. + /// Note: If result is within [first, last), move must be used instead of move_backward. + /// + /// Example usage: + /// eastl::move_backward(myArray.begin(), myArray.end(), myDestArray.end()); + /// + /// Reference implementation: + /// template + /// BidirectionalIterator2 move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) + /// { + /// while(last != first) + /// *--resultEnd = eastl::move(*--last); + /// return resultEnd; + /// } + /// + template + inline BidirectionalIterator2 move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) + { + return eastl::move_and_copy_backward_unwrapper(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), resultEnd); + } + + + /// copy_backward + /// + /// copies memory in the range of [first, last) to the range *ending* with result. + /// + /// Effects: Copies elements in the range [first, last) into the range + /// [result - (last - first), result) starting from last 1 and proceeding to first. + /// For each positive integer n <= (last - first), performs *(result n) = *(last - n). + /// + /// Requires: result shall not be in the range [first, last). + /// + /// Returns: result - (last - first). That is, returns the beginning of the result range. + /// + /// Complexity: Exactly 'last - first' assignments. + /// + template + inline BidirectionalIterator2 copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd) + { + const bool isMove = eastl::is_move_iterator::value; EA_UNUSED(isMove); + + return eastl::move_and_copy_backward_unwrapper(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), resultEnd); + } + + + /// count + /// + /// Counts the number of items in the range of [first, last) which equal the input value. + /// + /// Effects: Returns the number of iterators i in the range [first, last) for which the + /// following corresponding conditions hold: *i == value. + /// + /// Complexity: At most 'last - first' applications of the corresponding predicate. + /// + /// Note: The predicate version of count is count_if and not another variation of count. + /// This is because both versions would have three parameters and there could be ambiguity. + /// + template + inline typename eastl::iterator_traits::difference_type + count(InputIterator first, InputIterator last, const T& value) + { + typename eastl::iterator_traits::difference_type result = 0; + + for(; first != last; ++first) + { + if(*first == value) + ++result; + } + return result; + } + + + // C++ doesn't define a count with predicate, as it can effectively be synthesized via count_if + // with an appropriate predicate. However, it's often simpler to just have count with a predicate. + template + inline typename eastl::iterator_traits::difference_type + count(InputIterator first, InputIterator last, const T& value, Predicate predicate) + { + typename eastl::iterator_traits::difference_type result = 0; + + for(; first != last; ++first) + { + if(predicate(*first, value)) + ++result; + } + return result; + } + + + /// count_if + /// + /// Counts the number of items in the range of [first, last) which match + /// the input value as defined by the input predicate function. + /// + /// Effects: Returns the number of iterators i in the range [first, last) for which the + /// following corresponding conditions hold: predicate(*i) != false. + /// + /// Complexity: At most 'last - first' applications of the corresponding predicate. + /// + /// Note: The non-predicate version of count_if is count and not another variation of count_if. + /// This is because both versions would have three parameters and there could be ambiguity. + /// + template + inline typename eastl::iterator_traits::difference_type + count_if(InputIterator first, InputIterator last, Predicate predicate) + { + typename eastl::iterator_traits::difference_type result = 0; + + for(; first != last; ++first) + { + if(predicate(*first)) + ++result; + } + return result; + } + + + /// find + /// + /// finds the value within the unsorted range of [first, last). + /// + /// Returns: The first iterator i in the range [first, last) for which + /// the following corresponding conditions hold: *i == value. + /// Returns last if no such iterator is found. + /// + /// Complexity: At most 'last - first' applications of the corresponding predicate. + /// This is a linear search and not a binary one. + /// + /// Note: The predicate version of find is find_if and not another variation of find. + /// This is because both versions would have three parameters and there could be ambiguity. + /// + template + inline InputIterator + find(InputIterator first, InputIterator last, const T& value) + { + while((first != last) && !(*first == value)) // Note that we always express value comparisons in terms of < or ==. + ++first; + return first; + } + + + // C++ doesn't define a find with predicate, as it can effectively be synthesized via find_if + // with an appropriate predicate. However, it's often simpler to just have find with a predicate. + template + inline InputIterator + find(InputIterator first, InputIterator last, const T& value, Predicate predicate) + { + while((first != last) && !predicate(*first, value)) + ++first; + return first; + } + + + + /// find_if + /// + /// finds the value within the unsorted range of [first, last). + /// + /// Returns: The first iterator i in the range [first, last) for which + /// the following corresponding conditions hold: pred(*i) != false. + /// Returns last if no such iterator is found. + /// If the sequence of elements to search for (i.e. first2 - last2) is empty, + /// the find always fails and last1 will be returned. + /// + /// Complexity: At most 'last - first' applications of the corresponding predicate. + /// + /// Note: The non-predicate version of find_if is find and not another variation of find_if. + /// This is because both versions would have three parameters and there could be ambiguity. + /// + template + inline InputIterator + find_if(InputIterator first, InputIterator last, Predicate predicate) + { + while((first != last) && !predicate(*first)) + ++first; + return first; + } + + + + /// find_if_not + /// + /// find_if_not works the same as find_if except it tests for if the predicate + /// returns false for the elements instead of true. + /// + template + inline InputIterator + find_if_not(InputIterator first, InputIterator last, Predicate predicate) + { + for(; first != last; ++first) + { + if(!predicate(*first)) + return first; + } + return last; + } + + + + + /// find_first_of + /// + /// find_first_of is similar to find in that it performs linear search through + /// a range of ForwardIterators. The difference is that while find searches + /// for one particular value, find_first_of searches for any of several values. + /// Specifically, find_first_of searches for the first occurrance in the + /// range [first1, last1) of any of the elements in [first2, last2). + /// This function is thus similar to the strpbrk standard C string function. + /// If the sequence of elements to search for (i.e. first2-last2) is empty, + /// the find always fails and last1 will be returned. + /// + /// Effects: Finds an element that matches one of a set of values. + /// + /// Returns: The first iterator i in the range [first1, last1) such that for some + /// integer j in the range [first2, last2) the following conditions hold: *i == *j. + /// Returns last1 if no such iterator is found. + /// + /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the + /// corresponding predicate. + /// + template + ForwardIterator1 + find_first_of(ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2) + { + for(; first1 != last1; ++first1) + { + for(ForwardIterator2 i = first2; i != last2; ++i) + { + if(*first1 == *i) + return first1; + } + } + return last1; + } + + + /// find_first_of + /// + /// find_first_of is similar to find in that it performs linear search through + /// a range of ForwardIterators. The difference is that while find searches + /// for one particular value, find_first_of searches for any of several values. + /// Specifically, find_first_of searches for the first occurrance in the + /// range [first1, last1) of any of the elements in [first2, last2). + /// This function is thus similar to the strpbrk standard C string function. + /// + /// Effects: Finds an element that matches one of a set of values. + /// + /// Returns: The first iterator i in the range [first1, last1) such that for some + /// integer j in the range [first2, last2) the following conditions hold: pred(*i, *j) != false. + /// Returns last1 if no such iterator is found. + /// + /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the + /// corresponding predicate. + /// + template + ForwardIterator1 + find_first_of(ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate predicate) + { + for(; first1 != last1; ++first1) + { + for(ForwardIterator2 i = first2; i != last2; ++i) + { + if(predicate(*first1, *i)) + return first1; + } + } + return last1; + } + + + /// find_first_not_of + /// + /// Searches through first range for the first element that does not belong the second input range. + /// This is very much like the C++ string find_first_not_of function. + /// + /// Returns: The first iterator i in the range [first1, last1) such that for some + /// integer j in the range [first2, last2) the following conditions hold: !(*i == *j). + /// Returns last1 if no such iterator is found. + /// + /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the + /// corresponding predicate. + /// + template + ForwardIterator1 + find_first_not_of(ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2) + { + for(; first1 != last1; ++first1) + { + if(eastl::find(first2, last2, *first1) == last2) + break; + } + + return first1; + } + + + + /// find_first_not_of + /// + /// Searches through first range for the first element that does not belong the second input range. + /// This is very much like the C++ string find_first_not_of function. + /// + /// Returns: The first iterator i in the range [first1, last1) such that for some + /// integer j in the range [first2, last2) the following conditions hold: pred(*i, *j) == false. + /// Returns last1 if no such iterator is found. + /// + /// Complexity: At most '(last1 - first1) * (last2 - first2)' applications of the + /// corresponding predicate. + /// + template + inline ForwardIterator1 + find_first_not_of(ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate predicate) + { + typedef typename eastl::iterator_traits::value_type value_type; + + for(; first1 != last1; ++first1) + { + if(eastl::find_if(first2, last2, eastl::bind1st(predicate, *first1)) == last2) + break; + } + + return first1; + } + + + template + inline BidirectionalIterator1 + find_last_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2) + { + if((first1 != last1) && (first2 != last2)) + { + BidirectionalIterator1 it1(last1); + + while((--it1 != first1) && (eastl::find(first2, last2, *it1) == last2)) + ; // Do nothing + + if((it1 != first1) || (eastl::find(first2, last2, *it1) != last2)) + return it1; + } + + return last1; + } + + + template + BidirectionalIterator1 + find_last_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate predicate) + { + typedef typename eastl::iterator_traits::value_type value_type; + + if((first1 != last1) && (first2 != last2)) + { + BidirectionalIterator1 it1(last1); + + while((--it1 != first1) && (eastl::find_if(first2, last2, eastl::bind1st(predicate, *it1)) == last2)) + ; // Do nothing + + if((it1 != first1) || (eastl::find_if(first2, last2, eastl::bind1st(predicate, *it1)) != last2)) + return it1; + } + + return last1; + } + + + template + inline BidirectionalIterator1 + find_last_not_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2) + { + if((first1 != last1) && (first2 != last2)) + { + BidirectionalIterator1 it1(last1); + + while((--it1 != first1) && (eastl::find(first2, last2, *it1) != last2)) + ; // Do nothing + + if((it1 != first1) || (eastl::find( first2, last2, *it1) == last2)) + return it1; + } + + return last1; + } + + + template + inline BidirectionalIterator1 + find_last_not_of(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate predicate) + { + typedef typename eastl::iterator_traits::value_type value_type; + + if((first1 != last1) && (first2 != last2)) + { + BidirectionalIterator1 it1(last1); + + while((--it1 != first1) && (eastl::find_if(first2, last2, eastl::bind1st(predicate, *it1)) != last2)) + ; // Do nothing + + if((it1 != first1) || (eastl::find_if(first2, last2, eastl::bind1st(predicate, *it1))) != last2) + return it1; + } + + return last1; + } + + + + + /// for_each + /// + /// Calls the Function function for each value in the range [first, last). + /// Function takes a single parameter: the current value. + /// + /// Effects: Applies function to the result of dereferencing every iterator in + /// the range [first, last), starting from first and proceeding to last 1. + /// + /// Returns: function. + /// + /// Complexity: Applies function exactly 'last - first' times. + /// + /// Note: If function returns a result, the result is ignored. + /// + template + inline Function + for_each(InputIterator first, InputIterator last, Function function) + { + for(; first != last; ++first) + function(*first); + return function; + } + + + /// generate + /// + /// Iterates the range of [first, last) and assigns to each element the + /// result of the function generator. Generator is a function which takes + /// no arguments. + /// + /// Complexity: Exactly 'last - first' invocations of generator and assignments. + /// + template + inline void + generate(ForwardIterator first, ForwardIterator last, Generator generator) + { + for(; first != last; ++first) // We cannot call generate_n(first, last-first, generator) + *first = generator(); // because the 'last-first' might not be supported by the + } // given iterator. + + + /// generate_n + /// + /// Iterates an interator n times and assigns the result of generator + /// to each succeeding element. Generator is a function which takes + /// no arguments. + /// + /// Complexity: Exactly n invocations of generator and assignments. + /// + template + inline OutputIterator + generate_n(OutputIterator first, Size n, Generator generator) + { + for(; n > 0; --n, ++first) + *first = generator(); + return first; + } + + + /// transform + /// + /// Iterates the input range of [first, last) and the output iterator result + /// and assigns the result of unaryOperation(input) to result. + /// + /// Effects: Assigns through every iterator i in the range [result, result + (last1 - first1)) + /// a new corresponding value equal to unaryOperation(*(first1 + (i - result)). + /// + /// Requires: op shall not have any side effects. + /// + /// Returns: result + (last1 - first1). That is, returns the end of the output range. + /// + /// Complexity: Exactly 'last1 - first1' applications of unaryOperation. + /// + /// Note: result may be equal to first. + /// + template + inline OutputIterator + transform(InputIterator first, InputIterator last, OutputIterator result, UnaryOperation unaryOperation) + { + for(; first != last; ++first, ++result) + *result = unaryOperation(*first); + return result; + } + + + /// transform + /// + /// Iterates the input range of [first, last) and the output iterator result + /// and assigns the result of binaryOperation(input1, input2) to result. + /// + /// Effects: Assigns through every iterator i in the range [result, result + (last1 - first1)) + /// a new corresponding value equal to binaryOperation(*(first1 + (i - result), *(first2 + (i - result))). + /// + /// Requires: binaryOperation shall not have any side effects. + /// + /// Returns: result + (last1 - first1). That is, returns the end of the output range. + /// + /// Complexity: Exactly 'last1 - first1' applications of binaryOperation. + /// + /// Note: result may be equal to first1 or first2. + /// + template + inline OutputIterator + transform(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, BinaryOperation binaryOperation) + { + for(; first1 != last1; ++first1, ++first2, ++result) + *result = binaryOperation(*first1, *first2); + return result; + } + + + /// equal + /// + /// Returns: true if for every iterator i in the range [first1, last1) the + /// following corresponding conditions hold: predicate(*i, *(first2 + (i - first1))) != false. + /// Otherwise, returns false. + /// + /// Complexity: At most last1 first1 applications of the corresponding predicate. + /// + /// To consider: Make specializations of this for scalar types and random access + /// iterators that uses memcmp or some trick memory comparison function. + /// We should verify that such a thing results in an improvement. + /// + template + inline bool + equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2) + { + for(; first1 != last1; ++first1, ++first2) + { + if(!(*first1 == *first2)) // Note that we always express value comparisons in terms of < or ==. + return false; + } + return true; + } + + /* Enable the following if there was shown to be some benefit. A glance and Microsoft VC++ memcmp + shows that it is not optimized in any way, much less one that would benefit us here. + + inline bool equal(const bool* first1, const bool* last1, const bool* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + + inline bool equal(const char* first1, const char* last1, const char* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + + inline bool equal(const unsigned char* first1, const unsigned char* last1, const unsigned char* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + + inline bool equal(const signed char* first1, const signed char* last1, const signed char* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + + #ifndef EA_WCHAR_T_NON_NATIVE // EABase defines this. If you are getting a compiler error here, then somebody has taken away EABase or broken it. + inline bool equal(const wchar_t* first1, const wchar_t* last1, const wchar_t* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + #endif + + inline bool equal(const int16_t* first1, const int16_t* last1, const int16_t* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + + inline bool equal(const uint16_t* first1, const uint16_t* last1, const uint16_t* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + + inline bool equal(const int32_t* first1, const int32_t* last1, const int32_t* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + + inline bool equal(const uint32_t* first1, const uint32_t* last1, const uint32_t* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + + inline bool equal(const int64_t* first1, const int64_t* last1, const int64_t* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + + inline bool equal(const uint64_t* first1, const uint64_t* last1, const uint64_t* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + + inline bool equal(const float* first1, const float* last1, const float* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + + inline bool equal(const double* first1, const double* last1, const double* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + + inline bool equal(const long double* first1, const long double* last1, const long double* first2) + { return (memcmp(first1, first2, (size_t)((uintptr_t)last1 - (uintptr_t)first1)) == 0); } + */ + + + + /// equal + /// + /// Returns: true if for every iterator i in the range [first1, last1) the + /// following corresponding conditions hold: pred(*i, *(first2 + (i first1))) != false. + /// Otherwise, returns false. + /// + /// Complexity: At most last1 first1 applications of the corresponding predicate. + /// + template + inline bool + equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, BinaryPredicate predicate) + { + for(; first1 != last1; ++first1, ++first2) + { + if(!predicate(*first1, *first2)) + return false; + } + return true; + } + + + + /// identical + /// + /// Returns true if the two input ranges are equivalent. + /// There is a subtle difference between this algorithm and + /// the 'equal' algorithm. The equal algorithm assumes the + /// two ranges are of equal length. This algorithm efficiently + /// compares two ranges for both length equality and for + /// element equality. There is no other standard algorithm + /// that can do this. + /// + /// Returns: true if the sequence of elements defined by the range + /// [first1, last1) is of the same length as the sequence of + /// elements defined by the range of [first2, last2) and if + /// the elements in these ranges are equal as per the + /// equal algorithm. + /// + /// Complexity: At most 'min((last1 - first1), (last2 - first2))' applications + /// of the corresponding comparison. + /// + template + bool identical(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2) + { + while((first1 != last1) && (first2 != last2) && (*first1 == *first2)) + { + ++first1; + ++first2; + } + return (first1 == last1) && (first2 == last2); + } + + + /// identical + /// + template + bool identical(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, BinaryPredicate predicate) + { + while((first1 != last1) && (first2 != last2) && predicate(*first1, *first2)) + { + ++first1; + ++first2; + } + return (first1 == last1) && (first2 == last2); + } + + + + /// lexicographical_compare + /// + /// Returns: true if the sequence of elements defined by the range + /// [first1, last1) is lexicographically less than the sequence of + /// elements defined by the range [first2, last2). Returns false otherwise. + /// + /// Complexity: At most 'min((last1 - first1), (last2 - first2))' applications + /// of the corresponding comparison. + /// + /// Note: If two sequences have the same number of elements and their + /// corresponding elements are equivalent, then neither sequence is + /// lexicographically less than the other. If one sequence is a prefix + /// of the other, then the shorter sequence is lexicographically less + /// than the longer sequence. Otherwise, the lexicographical comparison + /// of the sequences yields the same result as the comparison of the first + /// corresponding pair of elements that are not equivalent. + /// + template + inline bool + lexicographical_compare(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) + { + for(; (first1 != last1) && (first2 != last2); ++first1, ++first2) + { + if(*first1 < *first2) + return true; + if(*first2 < *first1) + return false; + } + return (first1 == last1) && (first2 != last2); + } + + inline bool // Specialization for const char*. + lexicographical_compare(const char* first1, const char* last1, const char* first2, const char* last2) + { + const ptrdiff_t n1(last1 - first1), n2(last2 - first2); + const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + return result ? (result < 0) : (n1 < n2); + } + + inline bool // Specialization for char*. + lexicographical_compare(char* first1, char* last1, char* first2, char* last2) + { + const ptrdiff_t n1(last1 - first1), n2(last2 - first2); + const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + return result ? (result < 0) : (n1 < n2); + } + + inline bool // Specialization for const unsigned char*. + lexicographical_compare(const unsigned char* first1, const unsigned char* last1, const unsigned char* first2, const unsigned char* last2) + { + const ptrdiff_t n1(last1 - first1), n2(last2 - first2); + const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + return result ? (result < 0) : (n1 < n2); + } + + inline bool // Specialization for unsigned char*. + lexicographical_compare(unsigned char* first1, unsigned char* last1, unsigned char* first2, unsigned char* last2) + { + const ptrdiff_t n1(last1 - first1), n2(last2 - first2); + const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + return result ? (result < 0) : (n1 < n2); + } + + inline bool // Specialization for const signed char*. + lexicographical_compare(const signed char* first1, const signed char* last1, const signed char* first2, const signed char* last2) + { + const ptrdiff_t n1(last1 - first1), n2(last2 - first2); + const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + return result ? (result < 0) : (n1 < n2); + } + + inline bool // Specialization for signed char*. + lexicographical_compare(signed char* first1, signed char* last1, signed char* first2, signed char* last2) + { + const ptrdiff_t n1(last1 - first1), n2(last2 - first2); + const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + return result ? (result < 0) : (n1 < n2); + } + + #if defined(_MSC_VER) // If using the VC++ compiler (and thus bool is known to be a single byte)... + //Not sure if this is a good idea. + //inline bool // Specialization for const bool*. + //lexicographical_compare(const bool* first1, const bool* last1, const bool* first2, const bool* last2) + //{ + // const ptrdiff_t n1(last1 - first1), n2(last2 - first2); + // const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + // return result ? (result < 0) : (n1 < n2); + //} + // + //inline bool // Specialization for bool*. + //lexicographical_compare(bool* first1, bool* last1, bool* first2, bool* last2) + //{ + // const ptrdiff_t n1(last1 - first1), n2(last2 - first2); + // const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + // return result ? (result < 0) : (n1 < n2); + //} + #endif + + + + /// lexicographical_compare + /// + /// Returns: true if the sequence of elements defined by the range + /// [first1, last1) is lexicographically less than the sequence of + /// elements defined by the range [first2, last2). Returns false otherwise. + /// + /// Complexity: At most 'min((last1 -first1), (last2 - first2))' applications + /// of the corresponding comparison. + /// + /// Note: If two sequences have the same number of elements and their + /// corresponding elements are equivalent, then neither sequence is + /// lexicographically less than the other. If one sequence is a prefix + /// of the other, then the shorter sequence is lexicographically less + /// than the longer sequence. Otherwise, the lexicographical comparison + /// of the sequences yields the same result as the comparison of the first + /// corresponding pair of elements that are not equivalent. + /// + /// Note: False is always returned if range 1 is exhausted before range 2. + /// The result of this is that you can't do a successful reverse compare + /// (e.g. use greater<> as the comparison instead of less<>) unless the + /// two sequences are of identical length. What you want to do is reverse + /// the order of the arguments in order to get the desired effect. + /// + template + inline bool + lexicographical_compare(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, Compare compare) + { + for(; (first1 != last1) && (first2 != last2); ++first1, ++first2) + { + if(compare(*first1, *first2)) + return true; + if(compare(*first2, *first1)) + return false; + } + return (first1 == last1) && (first2 != last2); + } + + + /// mismatch + /// + /// Finds the first position where the two ranges [first1, last1) and + /// [first2, first2 + (last1 - first1)) differ. The two versions of + /// mismatch use different tests for whether elements differ. + /// + /// Returns: A pair of iterators i and j such that j == first2 + (i - first1) + /// and i is the first iterator in the range [first1, last1) for which the + /// following corresponding condition holds: !(*i == *(first2 + (i - first1))). + /// Returns the pair last1 and first2 + (last1 - first1) if such an iterator + /// i is not found. + /// + /// Complexity: At most last1 first1 applications of the corresponding predicate. + /// + template + inline eastl::pair + mismatch(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2) // , InputIterator2 last2) + { + while((first1 != last1) && (*first1 == *first2)) // && (first2 != last2) <- C++ standard mismatch function doesn't check first2/last2. + { + ++first1; + ++first2; + } + + return eastl::pair(first1, first2); + } + + + /// mismatch + /// + /// Finds the first position where the two ranges [first1, last1) and + /// [first2, first2 + (last1 - first1)) differ. The two versions of + /// mismatch use different tests for whether elements differ. + /// + /// Returns: A pair of iterators i and j such that j == first2 + (i - first1) + /// and i is the first iterator in the range [first1, last1) for which the + /// following corresponding condition holds: pred(*i, *(first2 + (i - first1))) == false. + /// Returns the pair last1 and first2 + (last1 - first1) if such an iterator + /// i is not found. + /// + /// Complexity: At most last1 first1 applications of the corresponding predicate. + /// + template + inline eastl::pair + mismatch(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, // InputIterator2 last2, + BinaryPredicate predicate) + { + while((first1 != last1) && predicate(*first1, *first2)) // && (first2 != last2) <- C++ standard mismatch function doesn't check first2/last2. + { + ++first1; + ++first2; + } + + return eastl::pair(first1, first2); + } + + + /// lower_bound + /// + /// Finds the position of the first element in a sorted range that has a value + /// greater than or equivalent to a specified value. + /// + /// Effects: Finds the first position into which value can be inserted without + /// violating the ordering. + /// + /// Returns: The furthermost iterator i in the range [first, last) such that + /// for any iterator j in the range [first, i) the following corresponding + /// condition holds: *j < value. + /// + /// Complexity: At most 'log(last - first) + 1' comparisons. + /// + /// Optimizations: We have no need to specialize this implementation for random + /// access iterators (e.g. contiguous array), as the code below will already + /// take advantage of them. + /// + template + ForwardIterator + lower_bound(ForwardIterator first, ForwardIterator last, const T& value) + { + typedef typename eastl::iterator_traits::difference_type DifferenceType; + + DifferenceType d = eastl::distance(first, last); // This will be efficient for a random access iterator such as an array. + + while(d > 0) + { + ForwardIterator i = first; + DifferenceType d2 = d >> 1; // We use '>>1' here instead of '/2' because MSVC++ for some reason generates significantly worse code for '/2'. Go figure. + + eastl::advance(i, d2); // This will be efficient for a random access iterator such as an array. + + if(*i < value) + { + // Disabled because std::lower_bound doesn't specify (23.3.3.3, p3) this can be done: EASTL_VALIDATE_COMPARE(!(value < *i)); // Validate that the compare function is sane. + first = ++i; + d -= d2 + 1; + } + else + d = d2; + } + return first; + } + + + /// lower_bound + /// + /// Finds the position of the first element in a sorted range that has a value + /// greater than or equivalent to a specified value. The input Compare function + /// takes two arguments and returns true if the first argument is less than + /// the second argument. + /// + /// Effects: Finds the first position into which value can be inserted without + /// violating the ordering. + /// + /// Returns: The furthermost iterator i in the range [first, last) such that + /// for any iterator j in the range [first, i) the following corresponding + /// condition holds: compare(*j, value) != false. + /// + /// Complexity: At most 'log(last - first) + 1' comparisons. + /// + /// Optimizations: We have no need to specialize this implementation for random + /// access iterators (e.g. contiguous array), as the code below will already + /// take advantage of them. + /// + template + ForwardIterator + lower_bound(ForwardIterator first, ForwardIterator last, const T& value, Compare compare) + { + typedef typename eastl::iterator_traits::difference_type DifferenceType; + + DifferenceType d = eastl::distance(first, last); // This will be efficient for a random access iterator such as an array. + + while(d > 0) + { + ForwardIterator i = first; + DifferenceType d2 = d >> 1; // We use '>>1' here instead of '/2' because MSVC++ for some reason generates significantly worse code for '/2'. Go figure. + + eastl::advance(i, d2); // This will be efficient for a random access iterator such as an array. + + if(compare(*i, value)) + { + // Disabled because std::lower_bound doesn't specify (23.3.3.1, p3) this can be done: EASTL_VALIDATE_COMPARE(!compare(value, *i)); // Validate that the compare function is sane. + first = ++i; + d -= d2 + 1; + } + else + d = d2; + } + return first; + } + + + + /// upper_bound + /// + /// Finds the position of the first element in a sorted range that has a + /// value that is greater than a specified value. + /// + /// Effects: Finds the furthermost position into which value can be inserted + /// without violating the ordering. + /// + /// Returns: The furthermost iterator i in the range [first, last) such that + /// for any iterator j in the range [first, i) the following corresponding + /// condition holds: !(value < *j). + /// + /// Complexity: At most 'log(last - first) + 1' comparisons. + /// + template + ForwardIterator + upper_bound(ForwardIterator first, ForwardIterator last, const T& value) + { + typedef typename eastl::iterator_traits::difference_type DifferenceType; + + DifferenceType len = eastl::distance(first, last); + + while(len > 0) + { + ForwardIterator i = first; + DifferenceType len2 = len >> 1; // We use '>>1' here instead of '/2' because MSVC++ for some reason generates significantly worse code for '/2'. Go figure. + + eastl::advance(i, len2); + + if(!(value < *i)) // Note that we always express value comparisons in terms of < or ==. + { + first = ++i; + len -= len2 + 1; + } + else + { + // Disabled because std::upper_bound doesn't specify (23.3.3.2, p3) this can be done: EASTL_VALIDATE_COMPARE(!(*i < value)); // Validate that the compare function is sane. + len = len2; + } + } + return first; + } + + + /// upper_bound + /// + /// Finds the position of the first element in a sorted range that has a + /// value that is greater than a specified value. The input Compare function + /// takes two arguments and returns true if the first argument is less than + /// the second argument. + /// + /// Effects: Finds the furthermost position into which value can be inserted + /// without violating the ordering. + /// + /// Returns: The furthermost iterator i in the range [first, last) such that + /// for any iterator j in the range [first, i) the following corresponding + /// condition holds: compare(value, *j) == false. + /// + /// Complexity: At most 'log(last - first) + 1' comparisons. + /// + template + ForwardIterator + upper_bound(ForwardIterator first, ForwardIterator last, const T& value, Compare compare) + { + typedef typename eastl::iterator_traits::difference_type DifferenceType; + + DifferenceType len = eastl::distance(first, last); + + while(len > 0) + { + ForwardIterator i = first; + DifferenceType len2 = len >> 1; // We use '>>1' here instead of '/2' because MSVC++ for some reason generates significantly worse code for '/2'. Go figure. + + eastl::advance(i, len2); + + if(!compare(value, *i)) + { + first = ++i; + len -= len2 + 1; + } + else + { + // Disabled because std::upper_bound doesn't specify (23.3.3.2, p3) this can be done: EASTL_VALIDATE_COMPARE(!compare(*i, value)); // Validate that the compare function is sane. + len = len2; + } + } + return first; + } + + + /// equal_range + /// + /// Effects: Finds the largest subrange [i, j) such that the value can be inserted + /// at any iterator k in it without violating the ordering. k satisfies the + /// corresponding conditions: !(*k < value) && !(value < *k). + /// + /// Complexity: At most '2 * log(last - first) + 1' comparisons. + /// + template + pair + equal_range(ForwardIterator first, ForwardIterator last, const T& value) + { + typedef pair ResultType; + typedef typename eastl::iterator_traits::difference_type DifferenceType; + + DifferenceType d = eastl::distance(first, last); + + while(d > 0) + { + ForwardIterator i(first); + DifferenceType d2 = d >> 1; // We use '>>1' here instead of '/2' because MSVC++ for some reason generates significantly worse code for '/2'. Go figure. + + eastl::advance(i, d2); + + if(*i < value) + { + EASTL_VALIDATE_COMPARE(!(value < *i)); // Validate that the compare function is sane. + first = ++i; + d -= d2 + 1; + } + else if(value < *i) + { + EASTL_VALIDATE_COMPARE(!(*i < value)); // Validate that the compare function is sane. + d = d2; + last = i; + } + else + { + ForwardIterator j(i); + + return ResultType(eastl::lower_bound(first, i, value), + eastl::upper_bound(++j, last, value)); + } + } + return ResultType(first, first); + } + + + /// equal_range + /// + /// Effects: Finds the largest subrange [i, j) such that the value can be inserted + /// at any iterator k in it without violating the ordering. k satisfies the + /// corresponding conditions: compare(*k, value) == false && compare(value, *k) == false. + /// + /// Complexity: At most '2 * log(last - first) + 1' comparisons. + /// + template + pair + equal_range(ForwardIterator first, ForwardIterator last, const T& value, Compare compare) + { + typedef pair ResultType; + typedef typename eastl::iterator_traits::difference_type DifferenceType; + + DifferenceType d = eastl::distance(first, last); + + while(d > 0) + { + ForwardIterator i(first); + DifferenceType d2 = d >> 1; // We use '>>1' here instead of '/2' because MSVC++ for some reason generates significantly worse code for '/2'. Go figure. + + eastl::advance(i, d2); + + if(compare(*i, value)) + { + EASTL_VALIDATE_COMPARE(!compare(value, *i)); // Validate that the compare function is sane. + first = ++i; + d -= d2 + 1; + } + else if(compare(value, *i)) + { + EASTL_VALIDATE_COMPARE(!compare(*i, value)); // Validate that the compare function is sane. + d = d2; + last = i; + } + else + { + ForwardIterator j(i); + + return ResultType(eastl::lower_bound(first, i, value, compare), + eastl::upper_bound(++j, last, value, compare)); + } + } + return ResultType(first, first); + } + + + /// replace + /// + /// Effects: Substitutes elements referred by the iterator i in the range [first, last) + /// with new_value, when the following corresponding conditions hold: *i == old_value. + /// + /// Complexity: Exactly 'last - first' applications of the corresponding predicate. + /// + /// Note: The predicate version of replace is replace_if and not another variation of replace. + /// This is because both versions would have the same parameter count and there could be ambiguity. + /// + template + inline void + replace(ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value) + { + for(; first != last; ++first) + { + if(*first == old_value) + *first = new_value; + } + } + + + /// replace_if + /// + /// Effects: Substitutes elements referred by the iterator i in the range [first, last) + /// with new_value, when the following corresponding conditions hold: predicate(*i) != false. + /// + /// Complexity: Exactly 'last - first' applications of the corresponding predicate. + /// + /// Note: The predicate version of replace_if is replace and not another variation of replace_if. + /// This is because both versions would have the same parameter count and there could be ambiguity. + /// + template + inline void + replace_if(ForwardIterator first, ForwardIterator last, Predicate predicate, const T& new_value) + { + for(; first != last; ++first) + { + if(predicate(*first)) + *first = new_value; + } + } + + + /// remove_copy + /// + /// Effects: Copies all the elements referred to by the iterator i in the range + /// [first, last) for which the following corresponding condition does not hold: + /// *i == value. + /// + /// Requires: The ranges [first, last) and [result, result + (last - first)) shall not overlap. + /// + /// Returns: The end of the resulting range. + /// + /// Complexity: Exactly 'last - first' applications of the corresponding predicate. + /// + template + inline OutputIterator + remove_copy(InputIterator first, InputIterator last, OutputIterator result, const T& value) + { + for(; first != last; ++first) + { + if(!(*first == value)) // Note that we always express value comparisons in terms of < or ==. + { + *result = *first; + ++result; + } + } + return result; + } + + + /// remove_copy_if + /// + /// Effects: Copies all the elements referred to by the iterator i in the range + /// [first, last) for which the following corresponding condition does not hold: + /// predicate(*i) != false. + /// + /// Requires: The ranges [first, last) and [result, result + (last - first)) shall not overlap. + /// + /// Returns: The end of the resulting range. + /// + /// Complexity: Exactly 'last - first' applications of the corresponding predicate. + /// + template + inline OutputIterator + remove_copy_if(InputIterator first, InputIterator last, OutputIterator result, Predicate predicate) + { + for(; first != last; ++first) + { + if(!predicate(*first)) + { + *result = *first; + ++result; + } + } + return result; + } + + + /// remove + /// + /// Effects: Eliminates all the elements referred to by iterator i in the + /// range [first, last) for which the following corresponding condition + /// holds: *i == value. + /// + /// Returns: The end of the resulting range. + /// + /// Complexity: Exactly 'last - first' applications of the corresponding predicate. + /// + /// Note: The predicate version of remove is remove_if and not another variation of remove. + /// This is because both versions would have the same parameter count and there could be ambiguity. + /// + /// Note: Since this function moves the element to the back of the heap and + /// doesn't actually remove it from the given container, the user must call + /// the container erase function if the user wants to erase the element + /// from the container. + /// + /// Example usage: + /// vector intArray; + /// ... + /// intArray.erase(remove(intArray.begin(), intArray.end(), 4), intArray.end()); // Erase all elements of value 4. + /// + template + inline ForwardIterator + remove(ForwardIterator first, ForwardIterator last, const T& value) + { + first = eastl::find(first, last, value); + if(first != last) + { + ForwardIterator i(first); + return eastl::remove_copy(++i, last, first, value); + } + return first; + } + + + /// remove_if + /// + /// Effects: Eliminates all the elements referred to by iterator i in the + /// range [first, last) for which the following corresponding condition + /// holds: predicate(*i) != false. + /// + /// Returns: The end of the resulting range. + /// + /// Complexity: Exactly 'last - first' applications of the corresponding predicate. + /// + /// Note: The predicate version of remove_if is remove and not another variation of remove_if. + /// This is because both versions would have the same parameter count and there could be ambiguity. + /// + /// Note: Since this function moves the element to the back of the heap and + /// doesn't actually remove it from the given container, the user must call + /// the container erase function if the user wants to erase the element + /// from the container. + /// + /// Example usage: + /// vector intArray; + /// ... + /// intArray.erase(remove(intArray.begin(), intArray.end(), bind2nd(less(), (int)3)), intArray.end()); // Erase all elements less than 3. + /// + template + inline ForwardIterator + remove_if(ForwardIterator first, ForwardIterator last, Predicate predicate) + { + first = eastl::find_if(first, last, predicate); + if(first != last) + { + ForwardIterator i(first); + return eastl::remove_copy_if(++i, last, first, predicate); + } + return first; + } + + + /// replace_copy + /// + /// Effects: Assigns to every iterator i in the range [result, result + (last - first)) + /// either new_value or *(first + (i - result)) depending on whether the following + /// corresponding conditions hold: *(first + (i - result)) == old_value. + /// + /// Requires: The ranges [first, last) and [result, result + (last - first)) shall not overlap. + /// + /// Returns: result + (last - first). + /// + /// Complexity: Exactly 'last - first' applications of the corresponding predicate. + /// + /// Note: The predicate version of replace_copy is replace_copy_if and not another variation of replace_copy. + /// This is because both versions would have the same parameter count and there could be ambiguity. + /// + template + inline OutputIterator + replace_copy(InputIterator first, InputIterator last, OutputIterator result, const T& old_value, const T& new_value) + { + for(; first != last; ++first, ++result) + *result = (*first == old_value) ? new_value : *first; + return result; + } + + + /// replace_copy_if + /// + /// Effects: Assigns to every iterator i in the range [result, result + (last - first)) + /// either new_value or *(first + (i - result)) depending on whether the following + /// corresponding conditions hold: predicate(*(first + (i - result))) != false. + /// + /// Requires: The ranges [first, last) and [result, result+(lastfirst)) shall not overlap. + /// + /// Returns: result + (last - first). + /// + /// Complexity: Exactly 'last - first' applications of the corresponding predicate. + /// + /// Note: The predicate version of replace_copy_if is replace_copy and not another variation of replace_copy_if. + /// This is because both versions would have the same parameter count and there could be ambiguity. + /// + template + inline OutputIterator + replace_copy_if(InputIterator first, InputIterator last, OutputIterator result, Predicate predicate, const T& new_value) + { + for(; first != last; ++first, ++result) + *result = predicate(*first) ? new_value : *first; + return result; + } + + + + + // reverse + // + // We provide helper functions which allow reverse to be implemented more + // efficiently for some types of iterators and types. + // + template + inline void reverse_impl(BidirectionalIterator first, BidirectionalIterator last, EASTL_ITC_NS::bidirectional_iterator_tag) + { + for(; (first != last) && (first != --last); ++first) // We are not allowed to use operator <, <=, >, >= with a + eastl::iter_swap(first, last); // generic (bidirectional or otherwise) iterator. + } + + template + inline void reverse_impl(RandomAccessIterator first, RandomAccessIterator last, EASTL_ITC_NS::random_access_iterator_tag) + { + if(first != last) + { + for(; first < --last; ++first) // With a random access iterator, we can use operator < to more efficiently implement + eastl::iter_swap(first, last); // this algorithm. A generic iterator doesn't necessarily have an operator < defined. + } + } + + /// reverse + /// + /// Reverses the values within the range [first, last). + /// + /// Effects: For each nonnegative integer i <= (last - first) / 2, + /// applies swap to all pairs of iterators first + i, (last i) - 1. + /// + /// Complexity: Exactly '(last - first) / 2' swaps. + /// + template + inline void reverse(BidirectionalIterator first, BidirectionalIterator last) + { + typedef typename eastl::iterator_traits::iterator_category IC; + eastl::reverse_impl(first, last, IC()); + } + + + + /// reverse_copy + /// + /// Copies the range [first, last) in reverse order to the result. + /// + /// Effects: Copies the range [first, last) to the range + /// [result, result + (last - first)) such that for any nonnegative + /// integer i < (last - first) the following assignment takes place: + /// *(result + (last - first) - i) = *(first + i) + /// + /// Requires: The ranges [first, last) and [result, result + (last - first)) + /// shall not overlap. + /// + /// Returns: result + (last - first). That is, returns the end of the output range. + /// + /// Complexity: Exactly 'last - first' assignments. + /// + template + inline OutputIterator + reverse_copy(BidirectionalIterator first, BidirectionalIterator last, OutputIterator result) + { + for(; first != last; ++result) + *result = *--last; + return result; + } + + + + /// search + /// + /// Search finds a subsequence within the range [first1, last1) that is identical to [first2, last2) + /// when compared element-by-element. It returns an iterator pointing to the beginning of that + /// subsequence, or else last1 if no such subsequence exists. As such, it is very much like + /// the C strstr function, with the primary difference being that strstr uses 0-terminated strings + /// whereas search uses an end iterator to specify the end of a string. + /// + /// Returns: The first iterator i in the range [first1, last1 - (last2 - first2)) such that for + /// any nonnegative integer n less than 'last2 - first2' the following corresponding condition holds: + /// *(i + n) == *(first2 + n). Returns last1 if no such iterator is found. + /// + /// Complexity: At most (last1 first1) * (last2 first2) applications of the corresponding predicate. + /// + template + ForwardIterator1 + search(ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2) + { + if(first2 != last2) // If there is anything to search for... + { + // We need to make a special case for a pattern of one element, + // as the logic below prevents one element patterns from working. + ForwardIterator2 temp2(first2); + ++temp2; + + if(temp2 != last2) // If what we are searching for has a length > 1... + { + ForwardIterator1 cur1(first1); + ForwardIterator2 p2; + + while(first1 != last1) + { + // The following loop is the equivalent of eastl::find(first1, last1, *first2) + while((first1 != last1) && !(*first1 == *first2)) + ++first1; + + if(first1 != last1) + { + p2 = temp2; + cur1 = first1; + + if(++cur1 != last1) + { + while(*cur1 == *p2) + { + if(++p2 == last2) + return first1; + + if(++cur1 == last1) + return last1; + } + + ++first1; + continue; + } + } + return last1; + } + + // Fall through to the end. + } + else + return eastl::find(first1, last1, *first2); + } + + return first1; + + + #if 0 + /* Another implementation which is a little more simpler but executes a little slower on average. + typedef typename eastl::iterator_traits::difference_type difference_type_1; + typedef typename eastl::iterator_traits::difference_type difference_type_2; + + const difference_type_2 d2 = eastl::distance(first2, last2); + + for(difference_type_1 d1 = eastl::distance(first1, last1); d1 >= d2; ++first1, --d1) + { + ForwardIterator1 temp1 = first1; + + for(ForwardIterator2 temp2 = first2; ; ++temp1, ++temp2) + { + if(temp2 == last2) + return first1; + if(!(*temp1 == *temp2)) + break; + } + } + + return last1; + */ + #endif + } + + + /// search + /// + /// Search finds a subsequence within the range [first1, last1) that is identical to [first2, last2) + /// when compared element-by-element. It returns an iterator pointing to the beginning of that + /// subsequence, or else last1 if no such subsequence exists. As such, it is very much like + /// the C strstr function, with the only difference being that strstr uses 0-terminated strings + /// whereas search uses an end iterator to specify the end of a string. + /// + /// Returns: The first iterator i in the range [first1, last1 - (last2 - first2)) such that for + /// any nonnegative integer n less than 'last2 - first2' the following corresponding condition holds: + /// predicate(*(i + n), *(first2 + n)) != false. Returns last1 if no such iterator is found. + /// + /// Complexity: At most (last1 first1) * (last2 first2) applications of the corresponding predicate. + /// + template + ForwardIterator1 + search(ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate predicate) + { + typedef typename eastl::iterator_traits::difference_type difference_type_1; + typedef typename eastl::iterator_traits::difference_type difference_type_2; + + difference_type_2 d2 = eastl::distance(first2, last2); + + if(d2 != 0) + { + ForwardIterator1 i(first1); + eastl::advance(i, d2); + + for(difference_type_1 d1 = eastl::distance(first1, last1); d1 >= d2; --d1) + { + if(eastl::equal(first1, i, first2, predicate)) + return first1; + if(d1 > d2) // To do: Find a way to make the algorithm more elegant. + { + ++first1; + ++i; + } + } + return last1; + } + return first1; // Just like with strstr, we return first1 if the match string is empty. + } + + + + // search_n helper functions + // + template + ForwardIterator // Generic implementation. + search_n_impl(ForwardIterator first, ForwardIterator last, Size count, const T& value, EASTL_ITC_NS::forward_iterator_tag) + { + if(count <= 0) + return first; + + Size d1 = (Size)eastl::distance(first, last); // Should d1 be of type Size, ptrdiff_t, or iterator_traits::difference_type? + // The problem with using iterator_traits::difference_type is that + if(count > d1) // ForwardIterator may not be a true iterator but instead something like a pointer. + return last; + + for(; d1 >= count; ++first, --d1) + { + ForwardIterator i(first); + + for(Size n = 0; n < count; ++n, ++i, --d1) + { + if(!(*i == value)) // Note that we always express value comparisons in terms of < or ==. + goto not_found; + } + return first; + + not_found: + first = i; + } + return last; + } + + template inline + RandomAccessIterator // Random access iterator implementation. Much faster than generic implementation. + search_n_impl(RandomAccessIterator first, RandomAccessIterator last, Size count, const T& value, EASTL_ITC_NS::random_access_iterator_tag) + { + if(count <= 0) + return first; + else if(count == 1) + return find(first, last, value); + else if(last > first) + { + RandomAccessIterator lookAhead; + RandomAccessIterator backTrack; + + Size skipOffset = (count - 1); + Size tailSize = (Size)(last - first); + Size remainder; + Size prevRemainder; + + for(lookAhead = first + skipOffset; tailSize >= count; lookAhead += count) + { + tailSize -= count; + + if(*lookAhead == value) + { + remainder = skipOffset; + + for(backTrack = lookAhead - 1; *backTrack == value; --backTrack) + { + if(--remainder == 0) + return (lookAhead - skipOffset); // success + } + + if(remainder <= tailSize) + { + prevRemainder = remainder; + + while(*(++lookAhead) == value) + { + if(--remainder == 0) + return (backTrack + 1); // success + } + tailSize -= (prevRemainder - remainder); + } + else + return last; // failure + } + + // lookAhead here is always pointing to the element of the last mismatch. + } + } + + return last; // failure + } + + + /// search_n + /// + /// Returns: The first iterator i in the range [first, last count) such that + /// for any nonnegative integer n less than count the following corresponding + /// conditions hold: *(i + n) == value, pred(*(i + n),value) != false. + /// Returns last if no such iterator is found. + /// + /// Complexity: At most '(last1 - first1) * count' applications of the corresponding predicate. + /// + template + ForwardIterator + search_n(ForwardIterator first, ForwardIterator last, Size count, const T& value) + { + typedef typename eastl::iterator_traits::iterator_category IC; + return eastl::search_n_impl(first, last, count, value, IC()); + } + + + /// binary_search + /// + /// Returns: true if there is an iterator i in the range [first last) that + /// satisfies the corresponding conditions: !(*i < value) && !(value < *i). + /// + /// Complexity: At most 'log(last - first) + 2' comparisons. + /// + /// Note: The reason binary_search returns bool instead of an iterator is + /// that search_n, lower_bound, or equal_range already return an iterator. + /// However, there are arguments that binary_search should return an iterator. + /// Note that we provide binary_search_i (STL extension) to return an iterator. + /// + /// To use search_n to find an item, do this: + /// iterator i = search_n(begin, end, 1, value); + /// To use lower_bound to find an item, do this: + /// iterator i = lower_bound(begin, end, value); + /// if((i != last) && !(value < *i)) + /// + /// It turns out that the above lower_bound method is as fast as binary_search + /// would be if it returned an iterator. + /// + template + inline bool + binary_search(ForwardIterator first, ForwardIterator last, const T& value) + { + // To do: This can be made slightly faster by not using lower_bound. + ForwardIterator i(eastl::lower_bound(first, last, value)); + return ((i != last) && !(value < *i)); // Note that we always express value comparisons in terms of < or ==. + } + + + /// binary_search + /// + /// Returns: true if there is an iterator i in the range [first last) that + /// satisfies the corresponding conditions: compare(*i, value) == false && + /// compare(value, *i) == false. + /// + /// Complexity: At most 'log(last - first) + 2' comparisons. + /// + /// Note: See comments above regarding the bool return value of binary_search. + /// + template + inline bool + binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare compare) + { + // To do: This can be made slightly faster by not using lower_bound. + ForwardIterator i(eastl::lower_bound(first, last, value, compare)); + return ((i != last) && !compare(value, *i)); + } + + + /// binary_search_i + /// + /// Returns: iterator if there is an iterator i in the range [first last) that + /// satisfies the corresponding conditions: !(*i < value) && !(value < *i). + /// Returns last if the value is not found. + /// + /// Complexity: At most 'log(last - first) + 2' comparisons. + /// + template + inline ForwardIterator + binary_search_i(ForwardIterator first, ForwardIterator last, const T& value) + { + // To do: This can be made slightly faster by not using lower_bound. + ForwardIterator i(eastl::lower_bound(first, last, value)); + if((i != last) && !(value < *i)) // Note that we always express value comparisons in terms of < or ==. + return i; + return last; + } + + + /// binary_search_i + /// + /// Returns: iterator if there is an iterator i in the range [first last) that + /// satisfies the corresponding conditions: !(*i < value) && !(value < *i). + /// Returns last if the value is not found. + /// + /// Complexity: At most 'log(last - first) + 2' comparisons. + /// + template + inline ForwardIterator + binary_search_i(ForwardIterator first, ForwardIterator last, const T& value, Compare compare) + { + // To do: This can be made slightly faster by not using lower_bound. + ForwardIterator i(eastl::lower_bound(first, last, value, compare)); + if((i != last) && !compare(value, *i)) + return i; + return last; + } + + + /// unique + /// + /// Given a sorted range, this function removes duplicated items. + /// Note that if you have a container then you will probably want + /// to call erase on the container with the return value if your + /// goal is to remove the duplicated items from the container. + /// + /// Effects: Eliminates all but the first element from every consecutive + /// group of equal elements referred to by the iterator i in the range + /// [first, last) for which the following corresponding condition holds: + /// *i == *(i - 1). + /// + /// Returns: The end of the resulting range. + /// + /// Complexity: If the range (last - first) is not empty, exactly (last - first) + /// applications of the corresponding predicate, otherwise no applications of the predicate. + /// + /// Example usage: + /// vector intArray; + /// ... + /// intArray.erase(unique(intArray.begin(), intArray.end()), intArray.end()); + /// + template + ForwardIterator unique(ForwardIterator first, ForwardIterator last) + { + first = eastl::adjacent_find(first, last); + + if(first != last) // We expect that there are duplicated items, else the user wouldn't be calling this function. + { + ForwardIterator dest(first); + + for(++first; first != last; ++first) + { + if(!(*dest == *first)) // Note that we always express value comparisons in terms of < or ==. + *++dest = *first; + } + return ++dest; + } + return last; + } + + + /// unique + /// + /// Given a sorted range, this function removes duplicated items. + /// Note that if you have a container then you will probably want + /// to call erase on the container with the return value if your + /// goal is to remove the duplicated items from the container. + /// + /// Effects: Eliminates all but the first element from every consecutive + /// group of equal elements referred to by the iterator i in the range + /// [first, last) for which the following corresponding condition holds: + /// predicate(*i, *(i - 1)) != false. + /// + /// Returns: The end of the resulting range. + /// + /// Complexity: If the range (last - first) is not empty, exactly (last - first) + /// applications of the corresponding predicate, otherwise no applications of the predicate. + /// + template + ForwardIterator unique(ForwardIterator first, ForwardIterator last, BinaryPredicate predicate) + { + first = eastl::adjacent_find(first, last, predicate); + + if(first != last) // We expect that there are duplicated items, else the user wouldn't be calling this function. + { + ForwardIterator dest(first); + + for(++first; first != last; ++first) + { + if(!predicate(*dest, *first)) + *++dest = *first; + } + return ++dest; + } + return last; + } + + + + // find_end + // + // We provide two versions here, one for a bidirectional iterators and one for + // regular forward iterators. Given that we are searching backward, it's a bit + // more efficient if we can use backwards iteration to implement our search, + // though this requires an iterator that can be reversed. + // + template + ForwardIterator1 + find_end_impl(ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + EASTL_ITC_NS::forward_iterator_tag, EASTL_ITC_NS::forward_iterator_tag) + { + if(first2 != last2) // We have to do this check because the search algorithm below will return first1 (and not last1) if the first2/last2 range is empty. + { + for(ForwardIterator1 result(last1); ; ) + { + const ForwardIterator1 resultNext(eastl::search(first1, last1, first2, last2)); + + if(resultNext != last1) // If another sequence was found... + { + first1 = result = resultNext; + ++first1; + } + else + return result; + } + } + return last1; + } + + template + BidirectionalIterator1 + find_end_impl(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + BidirectionalIterator2 first2, BidirectionalIterator2 last2, + EASTL_ITC_NS::bidirectional_iterator_tag, EASTL_ITC_NS::bidirectional_iterator_tag) + { + typedef eastl::reverse_iterator reverse_iterator1; + typedef eastl::reverse_iterator reverse_iterator2; + + reverse_iterator1 rresult(eastl::search(reverse_iterator1(last1), reverse_iterator1(first1), + reverse_iterator2(last2), reverse_iterator2(first2))); + if(rresult.base() != first1) // If we found something... + { + BidirectionalIterator1 result(rresult.base()); + + eastl::advance(result, -eastl::distance(first2, last2)); // We have an opportunity to optimize this, as the + return result; // search function already calculates this distance. + } + return last1; + } + + /// find_end + /// + /// Finds the last occurrence of the second sequence in the first sequence. + /// As such, this function is much like the C string function strrstr and it + /// is also the same as a reversed version of 'search'. It is called find_end + /// instead of the possibly more consistent search_end simply because the C++ + /// standard algorithms have such naming. + /// + /// Returns an iterator between first1 and last1 if the sequence is found. + /// returns last1 (the end of the first seqence) if the sequence is not found. + /// + template + inline ForwardIterator1 + find_end(ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2) + { + typedef typename eastl::iterator_traits::iterator_category IC1; + typedef typename eastl::iterator_traits::iterator_category IC2; + + return eastl::find_end_impl(first1, last1, first2, last2, IC1(), IC2()); + } + + + + + // To consider: Fold the predicate and non-predicate versions of + // this algorithm into a single function. + template + ForwardIterator1 + find_end_impl(ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate predicate, + EASTL_ITC_NS::forward_iterator_tag, EASTL_ITC_NS::forward_iterator_tag) + { + if(first2 != last2) // We have to do this check because the search algorithm below will return first1 (and not last1) if the first2/last2 range is empty. + { + for(ForwardIterator1 result = last1; ; ) + { + const ForwardIterator1 resultNext(eastl::search(first1, last1, first2, last2, predicate)); + + if(resultNext != last1) // If another sequence was found... + { + first1 = result = resultNext; + ++first1; + } + else + return result; + } + } + return last1; + } + + template + BidirectionalIterator1 + find_end_impl(BidirectionalIterator1 first1, BidirectionalIterator1 last1, + BidirectionalIterator2 first2, BidirectionalIterator2 last2, + BinaryPredicate predicate, + EASTL_ITC_NS::bidirectional_iterator_tag, EASTL_ITC_NS::bidirectional_iterator_tag) + { + typedef eastl::reverse_iterator reverse_iterator1; + typedef eastl::reverse_iterator reverse_iterator2; + + reverse_iterator1 rresult(eastl::search + (reverse_iterator1(last1), reverse_iterator1(first1), + reverse_iterator2(last2), reverse_iterator2(first2), + predicate)); + if(rresult.base() != first1) // If we found something... + { + BidirectionalIterator1 result(rresult.base()); + eastl::advance(result, -eastl::distance(first2, last2)); + return result; + } + return last1; + } + + + /// find_end + /// + /// Effects: Finds a subsequence of equal values in a sequence. + /// + /// Returns: The last iterator i in the range [first1, last1 - (last2 - first2)) + /// such that for any nonnegative integer n < (last2 - first2), the following + /// corresponding conditions hold: pred(*(i+n),*(first2+n)) != false. Returns + /// last1 if no such iterator is found. + /// + /// Complexity: At most (last2 - first2) * (last1 - first1 - (last2 - first2) + 1) + /// applications of the corresponding predicate. + /// + template + inline ForwardIterator1 + find_end(ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate predicate) + { + typedef typename eastl::iterator_traits::iterator_category IC1; + typedef typename eastl::iterator_traits::iterator_category IC2; + + return eastl::find_end_impl + (first1, last1, first2, last2, predicate, IC1(), IC2()); + } + + + + /// set_difference + /// + /// set_difference iterates over both input ranges and copies elements present + /// in the first range but not the second to the output range. + /// + /// Effects: Copies the elements of the range [first1, last1) which are not + /// present in the range [first2, last2) to the range beginning at result. + /// The elements in the constructed range are sorted. + /// + /// Requires: The input ranges must be sorted. + /// Requires: The output range shall not overlap with either of the original ranges. + /// + /// Returns: The end of the output range. + /// + /// Complexity: At most (2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. + /// + template + OutputIterator set_difference(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result) + { + while((first1 != last1) && (first2 != last2)) + { + if(*first1 < *first2) + { + *result = *first1; + ++first1; + ++result; + } + else if(*first2 < *first1) + ++first2; + else + { + ++first1; + ++first2; + } + } + + return eastl::copy(first1, last1, result); + } + + + template + OutputIterator set_difference(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result, Compare compare) + { + while((first1 != last1) && (first2 != last2)) + { + if(compare(*first1, *first2)) + { + EASTL_VALIDATE_COMPARE(!compare(*first2, *first1)); // Validate that the compare function is sane. + *result = *first1; + ++first1; + ++result; + } + else if(compare(*first2, *first1)) + { + EASTL_VALIDATE_COMPARE(!compare(*first1, *first2)); // Validate that the compare function is sane. + ++first2; + } + else + { + ++first1; + ++first2; + } + } + + return eastl::copy(first1, last1, result); + } + + + + /// set_symmetric_difference + /// + /// set_difference iterates over both input ranges and copies elements present + /// in the either range but not the other to the output range. + /// + /// Effects: Copies the elements of the range [first1, last1) which are not + /// present in the range [first2, last2), and the elements of the range [first2, last2) + /// which are not present in the range [first1, last1) to the range beginning at result. + /// The elements in the constructed range are sorted. + /// + /// Requires: The input ranges must be sorted. + /// Requires: The resulting range shall not overlap with either of the original ranges. + /// + /// Returns: The end of the constructed range. + /// + /// Complexity: At most (2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. + /// + template + OutputIterator set_symmetric_difference(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result) + { + while((first1 != last1) && (first2 != last2)) + { + if(*first1 < *first2) + { + *result = *first1; + ++first1; + ++result; + } + else if(*first2 < *first1) + { + *result = *first2; + ++first2; + ++result; + } + else + { + ++first1; + ++first2; + } + } + + return eastl::copy(first2, last2, eastl::copy(first1, last1, result)); + } + + + template + OutputIterator set_symmetric_difference(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result, Compare compare) + { + while((first1 != last1) && (first2 != last2)) + { + if(compare(*first1, *first2)) + { + EASTL_VALIDATE_COMPARE(!compare(*first2, *first1)); // Validate that the compare function is sane. + *result = *first1; + ++first1; + ++result; + } + else if(compare(*first2, *first1)) + { + EASTL_VALIDATE_COMPARE(!compare(*first1, *first2)); // Validate that the compare function is sane. + *result = *first2; + ++first2; + ++result; + } + else + { + ++first1; + ++first2; + } + } + + return eastl::copy(first2, last2, eastl::copy(first1, last1, result)); + } + + + + + /// set_intersection + /// + /// set_intersection over both ranges and copies elements present in + /// both ranges to the output range. + /// + /// Effects: Constructs a sorted intersection of the elements from the + /// two ranges; that is, the set of elements that are present in both of the ranges. + /// + /// Requires: The input ranges must be sorted. + /// Requires: The resulting range shall not overlap with either of the original ranges. + /// + /// Returns: The end of the constructed range. + /// + /// Complexity: At most 2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. + /// + /// Note: The copying operation is stable; if an element is present in both ranges, + /// the one from the first range is copied. + /// + template + OutputIterator set_intersection(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result) + { + while((first1 != last1) && (first2 != last2)) + { + if(*first1 < *first2) + ++first1; + else if(*first2 < *first1) + ++first2; + else + { + *result = *first1; + ++first1; + ++first2; + ++result; + } + } + + return result; + } + + + template + OutputIterator set_intersection(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result, Compare compare) + { + while((first1 != last1) && (first2 != last2)) + { + if(compare(*first1, *first2)) + { + EASTL_VALIDATE_COMPARE(!compare(*first2, *first1)); // Validate that the compare function is sane. + ++first1; + } + else if(compare(*first2, *first1)) + { + EASTL_VALIDATE_COMPARE(!compare(*first1, *first2)); // Validate that the compare function is sane. + ++first2; + } + else + { + *result = *first1; + ++first1; + ++first2; + ++result; + } + } + + return result; + } + + + + /// set_union + /// + /// set_union iterators over both ranges and copies elements present in + /// both ranges to the output range. + /// + /// Effects: Constructs a sorted union of the elements from the two ranges; + /// that is, the set of elements that are present in one or both of the ranges. + /// + /// Requires: The input ranges must be sorted. + /// Requires: The resulting range shall not overlap with either of the original ranges. + /// + /// Returns: The end of the constructed range. + /// + /// Complexity: At most (2 * ((last1 - first1) + (last2 - first2)) - 1) comparisons. + /// + /// Note: The copying operation is stable; if an element is present in both ranges, + /// the one from the first range is copied. + /// + template + OutputIterator set_union(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result) + { + while((first1 != last1) && (first2 != last2)) + { + if(*first1 < *first2) + { + *result = *first1; + ++first1; + } + else if(*first2 < *first1) + { + *result = *first2; + ++first2; + } + else + { + *result = *first1; + ++first1; + ++first2; + } + ++result; + } + + return eastl::copy(first2, last2, eastl::copy(first1, last1, result)); + } + + + template + OutputIterator set_union(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result, Compare compare) + { + while((first1 != last1) && (first2 != last2)) + { + if(compare(*first1, *first2)) + { + EASTL_VALIDATE_COMPARE(!compare(*first2, *first1)); // Validate that the compare function is sane. + *result = *first1; + ++first1; + } + else if(compare(*first2, *first1)) + { + EASTL_VALIDATE_COMPARE(!compare(*first1, *first2)); // Validate that the compare function is sane. + *result = *first2; + ++first2; + } + else + { + *result = *first1; + ++first1; + ++first2; + } + ++result; + } + + return eastl::copy(first2, last2, eastl::copy(first1, last1, result)); + } + + + /// is_permutation + /// + template + bool is_permutation(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + + // Skip past any equivalent initial elements. + while((first1 != last1) && (*first1 == *first2)) + { + ++first1; + ++first2; + } + + if(first1 != last1) + { + const difference_type first1Size = eastl::distance(first1, last1); + ForwardIterator2 last2 = first2; + eastl::advance(last2, first1Size); + + for(ForwardIterator1 i = first1; i != last1; ++i) + { + if(i == eastl::find(first1, i, *i)) + { + const difference_type c = eastl::count(first2, last2, *i); + + if((c == 0) || (c != eastl::count(i, last1, *i))) + return false; + } + } + } + + return true; + } + + /// is_permutation + /// + template + bool is_permutation(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, BinaryPredicate predicate) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + + // Skip past any equivalent initial elements. + while((first1 != last1) && predicate(*first1, *first2)) + { + ++first1; + ++first2; + } + + if(first1 != last1) + { + const difference_type first1Size = eastl::distance(first1, last1); + ForwardIterator2 last2 = first2; + eastl::advance(last2, first1Size); + + for(ForwardIterator1 i = first1; i != last1; ++i) + { + if(i == eastl::find(first1, i, *i, predicate)) + { + const difference_type c = eastl::count(first2, last2, *i, predicate); + + if((c == 0) || (c != eastl::count(i, last1, *i, predicate))) + return false; + } + } + } + + return true; + } + + + /// next_permutation + /// + /// mutates the range [first, last) to the next permutation. Returns true if the + /// new range is not the final permutation (sorted like the starting permutation). + /// Permutations start with a sorted range, and false is returned when next_permutation + /// results in the initial sorted range, or if the range has <= 1 element. + /// Note that elements are compared by operator < (as usual) and that elements deemed + /// equal via this are not rearranged. + /// + /// http://marknelson.us/2002/03/01/next-permutation/ + /// Basically we start with an ordered range and reverse it's order one specifically + /// chosen swap and reverse at a time. It happens that this require going through every + /// permutation of the range. We use the same variable names as the document above. + /// + /// To consider: Significantly improved permutation/combination functionality: + /// http://home.roadrunner.com/~hinnant/combinations.html + /// + /// Example usage: + /// vector intArray; + /// // + /// sort(intArray.begin(), intArray.end()); + /// do { + /// // + /// } while(next_permutation(intArray.begin(), intArray.end())); + /// + + template + bool next_permutation(BidirectionalIterator first, BidirectionalIterator last, Compare compare) + { + if(first != last) // If there is anything in the range... + { + BidirectionalIterator i = last; + + if(first != --i) // If the range has more than one item... + { + for(;;) + { + BidirectionalIterator ii(i), j; + + if(compare(*--i, *ii)) // Find two consecutive values where the first is less than the second. + { + j = last; + while(!compare(*i, *--j)) // Find the final value that's greater than the first (it may be equal to the second). + {} + eastl::iter_swap(i, j); // Swap the first and the final. + eastl::reverse(ii, last); // Reverse the ranget from second to last. + return true; + } + + if(i == first) // There are no two consecutive values where the first is less than the second, meaning the range is in reverse order. The reverse ordered range is always the last permutation. + { + eastl::reverse(first, last); + break; // We are done. + } + } + } + } + + return false; + } + + template + bool next_permutation(BidirectionalIterator first, BidirectionalIterator last) + { + typedef typename eastl::iterator_traits::value_type value_type; + + return next_permutation(first, last, eastl::less()); + } + + + + /// rotate + /// + /// Effects: For each non-negative integer i < (last - first), places the element from the + /// position first + i into position first + (i + (last - middle)) % (last - first). + /// + /// Returns: first + (last - middle). That is, returns where first went to. + /// + /// Remarks: This is a left rotate. + /// + /// Requires: [first,middle) and [middle,last) shall be valid ranges. ForwardIterator shall + /// satisfy the requirements of ValueSwappable (17.6.3.2). The type of *first shall satisfy + /// the requirements of MoveConstructible (Table 20) and the requirements of MoveAssignable. + /// + /// Complexity: At most last - first swaps. + /// + /// Note: While rotate works on ForwardIterators (e.g. slist) and BidirectionalIterators (e.g. list), + /// you can get much better performance (O(1) instead of O(n)) with slist and list rotation by + /// doing splice operations on those lists instead of calling this rotate function. + /// + /// http://www.cs.bell-labs.com/cm/cs/pearls/s02b.pdf / http://books.google.com/books?id=kse_7qbWbjsC&pg=PA14&lpg=PA14&dq=Programming+Pearls+flipping+hands + /// http://books.google.com/books?id=tjOlkl7ecVQC&pg=PA189&lpg=PA189&dq=stepanov+Elements+of+Programming+rotate + /// http://stackoverflow.com/questions/21160875/why-is-stdrotate-so-fast + /// + /// Strategy: + /// - We handle the special case of (middle == first) and (middle == last) no-ops + /// up front in the main rotate entry point. + /// - There's a basic ForwardIterator implementation (rotate_general_impl) which is + /// a fallback implementation that's not as fast as others but works for all cases. + /// - There's a slightly better BidirectionalIterator implementation. + /// - We have specialized versions for rotating elements that are is_trivially_move_assignable. + /// These versions will use memmove for when we have a RandomAccessIterator. + /// - We have a specialized version for rotating by only a single position, as that allows us + /// (with any iterator type) to avoid a lot of logic involved with algorithms like "flipping hands" + /// and achieve near optimal O(n) behavior. it turns out that rotate-by-one is a common use + /// case in practice. + /// + namespace Internal + { + template + ForwardIterator rotate_general_impl(ForwardIterator first, ForwardIterator middle, ForwardIterator last) + { + ForwardIterator current = middle; + + do { + swap(*first++, *current++); + + if(first == middle) + middle = current; + } while(current != last); + + ForwardIterator result = first; + current = middle; + + while(current != last) + { + swap(*first++, *current++); + + if(first == middle) + middle = current; + else if(current == last) + current = middle; + } + + return result; // result points to first + (last - middle). + } + + + template + ForwardIterator move_rotate_left_by_one(ForwardIterator first, ForwardIterator last) + { + typedef typename eastl::iterator_traits::value_type value_type; + + value_type temp(eastl::move(*first)); + ForwardIterator result = eastl::move(eastl::next(first), last, first); // Note that while our template type is BidirectionalIterator, if the actual + *result = eastl::move(temp); // iterator is a RandomAccessIterator then this move will be a memmove for trivial types. + + return result; // result points to the final element in the range. + } + + + template + BidirectionalIterator move_rotate_right_by_one(BidirectionalIterator first, BidirectionalIterator last) + { + typedef typename eastl::iterator_traits::value_type value_type; + + BidirectionalIterator beforeLast = eastl::prev(last); + value_type temp(eastl::move(*beforeLast)); + BidirectionalIterator result = eastl::move_backward(first, beforeLast, last); // Note that while our template type is BidirectionalIterator, if the actual + *first = eastl::move(temp); // iterator is a RandomAccessIterator then this move will be a memmove for trivial types. + + return result; // result points to the first element in the range. + } + + template + struct rotate_helper + { + template + static ForwardIterator rotate_impl(ForwardIterator first, ForwardIterator middle, ForwardIterator last) + { return Internal::rotate_general_impl(first, middle, last); } + }; + + template <> + struct rotate_helper + { + template + static ForwardIterator rotate_impl(ForwardIterator first, ForwardIterator middle, ForwardIterator last) + { + if(eastl::next(first) == middle) // If moving trivial types by a single element, memcpy is fast for that case. + return Internal::move_rotate_left_by_one(first, last); + return Internal::rotate_general_impl(first, middle, last); + } + }; + + template <> + struct rotate_helper + { + template + static BidirectionalIterator rotate_impl(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last) + { return Internal::rotate_general_impl(first, middle, last); } // rotate_general_impl outperforms the flipping hands algorithm. + + /* + // Simplest "flipping hands" implementation. Disabled because it's slower on average than rotate_general_impl. + template + static BidirectionalIterator rotate_impl(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last) + { + eastl::reverse(first, middle); + eastl::reverse(middle, last); + eastl::reverse(first, last); + return first + (last - middle); // This can be slow for large ranges because operator + and - are O(n). + } + + // Smarter "flipping hands" implementation, but still disabled because benchmarks are showing it to be slower than rotate_general_impl. + template + static BidirectionalIterator rotate_impl(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last) + { + // This is the "flipping hands" algorithm. + eastl::reverse_impl(first, middle, EASTL_ITC_NS::bidirectional_iterator_tag()); // Reverse the left side. + eastl::reverse_impl(middle, last, EASTL_ITC_NS::bidirectional_iterator_tag()); // Reverse the right side. + + // Reverse the entire range. + while((first != middle) && (middle != last)) + { + eastl::iter_swap(first, --last); + ++first; + } + + if(first == middle) // Finish reversing the entire range. + { + eastl::reverse_impl(middle, last, bidirectional_iterator_tag()); + return last; + } + else + { + eastl::reverse_impl(first, middle, bidirectional_iterator_tag()); + return first; + } + } + */ + }; + + template <> + struct rotate_helper + { + template + static BidirectionalIterator rotate_impl(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last) + { + if(eastl::next(first) == middle) // If moving trivial types by a single element, memcpy is fast for that case. + return Internal::move_rotate_left_by_one(first, last); + if(eastl::next(middle) == last) + return Internal::move_rotate_right_by_one(first, last); + return Internal::rotate_general_impl(first, middle, last); + } + }; + + template + inline Integer greatest_common_divisor(Integer x, Integer y) + { + do { + Integer t = (x % y); + x = y; + y = t; + } while(y); + + return x; + } + + template <> + struct rotate_helper + { + // This is the juggling algorithm, using move operations. + // In practice this implementation is about 25% faster than rotate_general_impl. We may want to + // consider sticking with just rotate_general_impl and avoid the code generation of this function. + template + static RandomAccessIterator rotate_impl(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last) + { + typedef typename iterator_traits::difference_type difference_type; + typedef typename iterator_traits::value_type value_type; + + const difference_type m1 = (middle - first); + const difference_type m2 = (last - middle); + const difference_type g = Internal::greatest_common_divisor(m1, m2); + value_type temp; + + for(RandomAccessIterator p = first + g; p != first;) + { + temp = eastl::move(*--p); + RandomAccessIterator p1 = p; + RandomAccessIterator p2 = p + m1; + do + { + *p1 = eastl::move(*p2); + p1 = p2; + const difference_type d = (last - p2); + + if(m1 < d) + p2 += m1; + else + p2 = first + (m1 - d); + } while(p2 != p); + + *p1 = eastl::move(temp); + } + + return first + m2; + } + }; + + template <> + struct rotate_helper + { + // Experiments were done which tested the performance of using an intermediate buffer + // to do memcpy's to as opposed to executing a swapping algorithm. It turns out this is + // actually slower than even rotate_general_impl, partly because the average case involves + // memcpy'ing a quarter of the element range twice. Experiments were done with various kinds + // of PODs with various element counts. + + template + static RandomAccessIterator rotate_impl(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last) + { + if(eastl::next(first) == middle) // If moving trivial types by a single element, memcpy is fast for that case. + return Internal::move_rotate_left_by_one(first, last); + if(eastl::next(middle) == last) + return Internal::move_rotate_right_by_one(first, last); + if((last - first) < 32) // For small ranges rotate_general_impl is faster. + return Internal::rotate_general_impl(first, middle, last); + return Internal::rotate_helper::rotate_impl(first, middle, last); + } + }; + + } // namespace Internal + + + template + ForwardIterator rotate(ForwardIterator first, ForwardIterator middle, ForwardIterator last) + { + if(middle != first) + { + if(middle != last) + { + typedef typename eastl::iterator_traits::iterator_category IC; + typedef typename eastl::iterator_traits::value_type value_type; + + return Internal::rotate_helper::value || // This is the best way of telling if we can move types via memmove, but without a conforming C++11 compiler it usually returns false. + eastl::is_pod::value || // This is a more conservative way of telling if we can move types via memmove, and most compilers support it, but it doesn't have as full of coverage as is_trivially_move_assignable. + eastl::is_scalar::value> // This is the most conservative means and works with all compilers, but works only for scalars. + ::rotate_impl(first, middle, last); + } + + return first; + } + + return last; + } + + + + /// rotate_copy + /// + /// Similar to rotate except writes the output to the OutputIterator and + /// returns an OutputIterator to the element past the last element copied + /// (i.e. result + (last - first)) + /// + template + OutputIterator rotate_copy(ForwardIterator first, ForwardIterator middle, ForwardIterator last, OutputIterator result) + { + return eastl::copy(first, middle, eastl::copy(middle, last, result)); + } + + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/allocator.h b/libs/eastl/include/EASTL/allocator.h new file mode 100644 index 0000000..a52948d --- /dev/null +++ b/libs/eastl/include/EASTL/allocator.h @@ -0,0 +1,407 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_ALLOCATOR_H +#define EASTL_ALLOCATOR_H + + +#include +#include +#include + + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4189) // local variable is initialized but not referenced +#endif + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// alloc_flags + /// + /// Defines allocation flags. + /// + enum alloc_flags + { + MEM_TEMP = 0, // Low memory, not necessarily actually temporary. + MEM_PERM = 1 // High memory, for things that won't be unloaded. + }; + + + /// allocator + /// + /// In this allocator class, note that it is not templated on any type and + /// instead it simply allocates blocks of memory much like the C malloc and + /// free functions. It can be thought of as similar to C++ std::allocator. + /// The flags parameter has meaning that is specific to the allocation + /// + /// C++11's std::allocator (20.6.9) doesn't have a move constructor or assignment + /// operator. This is possibly because std::allocators are associated with types + /// instead of as instances. The potential non-equivalance of C++ std::allocator + /// instances has been a source of some acknowledged design problems. + /// We don't implement support for move construction or assignment in eastl::allocator, + /// but users can define their own allocators which do have move functions and + /// the eastl containers are compatible with such allocators (i.e. nothing unexpected + /// will happen). + /// + class EASTL_API allocator + { + public: + EASTL_ALLOCATOR_EXPLICIT allocator(const char* pName = EASTL_NAME_VAL(EASTL_ALLOCATOR_DEFAULT_NAME)); + allocator(const allocator& x); + allocator(const allocator& x, const char* pName); + + allocator& operator=(const allocator& x); + + void* allocate(size_t n, int flags = 0); + void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0); + void deallocate(void* p, size_t n); + + const char* get_name() const; + void set_name(const char* pName); + + protected: + #if EASTL_NAME_ENABLED + const char* mpName; // Debug name, used to track memory. + #endif + }; + + bool operator==(const allocator& a, const allocator& b); + bool operator!=(const allocator& a, const allocator& b); + + + + /// dummy_allocator + /// + /// Defines an allocator which does nothing. It returns NULL from allocate calls. + /// + class EASTL_API dummy_allocator + { + public: + EASTL_ALLOCATOR_EXPLICIT dummy_allocator(const char* = NULL) { } + dummy_allocator(const dummy_allocator&) { } + dummy_allocator(const dummy_allocator&, const char*) { } + + dummy_allocator& operator=(const dummy_allocator&) { return *this; } + + void* allocate(size_t, int = 0) { return NULL; } + void* allocate(size_t, size_t, size_t, int = 0) { return NULL; } + void deallocate(void*, size_t) { } + + const char* get_name() const { return ""; } + void set_name(const char*) { } + }; + + inline bool operator==(const dummy_allocator&, const dummy_allocator&) { return true; } + inline bool operator!=(const dummy_allocator&, const dummy_allocator&) { return false; } + + + + /// Defines a static default allocator which is constant across all types. + /// This is different from get_default_allocator, which is is bound at + /// compile-time and expected to differ per allocator type. + /// Currently this Default Allocator applies only to CoreAllocatorAdapter. + /// To consider: This naming of this function is too similar to get_default_allocator + /// and instead should be named something like GetStaticDefaultAllocator. + EASTL_API allocator* GetDefaultAllocator(); + EASTL_API allocator* SetDefaultAllocator(allocator* pAllocator); + + + /// get_default_allocator + /// + /// This templated function allows the user to implement a default allocator + /// retrieval function that any part of EASTL can use. EASTL containers take + /// an Allocator parameter which identifies an Allocator class to use. But + /// different kinds of allocators have different mechanisms for retrieving + /// a default allocator instance, and some don't even intrinsically support + /// such functionality. The user can override this get_default_allocator + /// function in order to provide the glue between EASTL and whatever their + /// system's default allocator happens to be. + /// + /// Example usage: + /// MyAllocatorType* gpSystemAllocator; + /// + /// MyAllocatorType* get_default_allocator(const MyAllocatorType*) + /// { return gpSystemAllocator; } + /// + template + Allocator* get_default_allocator(const Allocator*); + + EASTLAllocatorType* get_default_allocator(const EASTLAllocatorType*); + + + /// default_allocfreemethod + /// + /// Implements a default allocfreemethod which uses the default global allocator. + /// This version supports only default alignment. + /// + void* default_allocfreemethod(size_t n, void* pBuffer, void* /*pContext*/); + + + /// allocate_memory + /// + /// This is a memory allocation dispatching function. + /// To do: Make aligned and unaligned specializations. + /// Note that to do this we will need to use a class with a static + /// function instead of a standalone function like below. + /// + template + void* allocate_memory(Allocator& a, size_t n, size_t alignment, size_t alignmentOffset); + + +} // namespace eastl + + + + + + +#ifndef EASTL_USER_DEFINED_ALLOCATOR // If the user hasn't declared that he has defined a different allocator implementation elsewhere... + + #ifdef _MSC_VER + #pragma warning(push, 0) + #pragma warning(disable: 4265 4365 4836 4548) + #include + #pragma warning(pop) + #else + #include + #endif + + #if !EASTL_DLL // If building a regular library and not building EASTL as a DLL... + // It is expected that the application define the following + // versions of operator new for the application. Either that or the + // user needs to override the implementation of the allocator class. + void* operator new[](size_t size, const char* pName, int flags, unsigned debugFlags, const char* file, int line); + void* operator new[](size_t size, size_t alignment, size_t alignmentOffset, const char* pName, int flags, unsigned debugFlags, const char* file, int line); + #endif + + namespace eastl + { + inline allocator::allocator(const char* EASTL_NAME(pName)) + { + #if EASTL_NAME_ENABLED + mpName = pName ? pName : EASTL_ALLOCATOR_DEFAULT_NAME; + #endif + } + + + inline allocator::allocator(const allocator& EASTL_NAME(alloc)) + { + #if EASTL_NAME_ENABLED + mpName = alloc.mpName; + #endif + } + + + inline allocator::allocator(const allocator&, const char* EASTL_NAME(pName)) + { + #if EASTL_NAME_ENABLED + mpName = pName ? pName : EASTL_ALLOCATOR_DEFAULT_NAME; + #endif + } + + + inline allocator& allocator::operator=(const allocator& EASTL_NAME(alloc)) + { + #if EASTL_NAME_ENABLED + mpName = alloc.mpName; + #endif + return *this; + } + + + inline const char* allocator::get_name() const + { + #if EASTL_NAME_ENABLED + return mpName; + #else + return EASTL_ALLOCATOR_DEFAULT_NAME; + #endif + } + + + inline void allocator::set_name(const char* EASTL_NAME(pName)) + { + #if EASTL_NAME_ENABLED + mpName = pName; + #endif + } + + + inline void* allocator::allocate(size_t n, int flags) + { + #if EASTL_NAME_ENABLED + #define pName mpName + #else + #define pName EASTL_ALLOCATOR_DEFAULT_NAME + #endif + + #if EASTL_DLL + return allocate(n, EASTL_SYSTEM_ALLOCATOR_MIN_ALIGNMENT, 0, flags); + #elif (EASTL_DEBUGPARAMS_LEVEL <= 0) + return ::new((char*)0, flags, 0, (char*)0, 0) char[n]; + #elif (EASTL_DEBUGPARAMS_LEVEL == 1) + return ::new( pName, flags, 0, (char*)0, 0) char[n]; + #else + return ::new( pName, flags, 0, __FILE__, __LINE__) char[n]; + #endif + } + + + inline void* allocator::allocate(size_t n, size_t alignment, size_t offset, int flags) + { + #if EASTL_DLL + // We currently have no support for implementing flags when + // using the C runtime library operator new function. The user + // can use SetDefaultAllocator to override the default allocator. + EA_UNUSED(offset); EA_UNUSED(flags); + + size_t adjustedAlignment = (alignment > EA_PLATFORM_PTR_SIZE) ? alignment : EA_PLATFORM_PTR_SIZE; + + void* p = new char[n + adjustedAlignment + EA_PLATFORM_PTR_SIZE]; + void* pPlusPointerSize = (void*)((uintptr_t)p + EA_PLATFORM_PTR_SIZE); + void* pAligned = (void*)(((uintptr_t)pPlusPointerSize + adjustedAlignment - 1) & ~(adjustedAlignment - 1)); + + void** pStoredPtr = (void**)pAligned - 1; + EASTL_ASSERT(pStoredPtr >= p); + *(pStoredPtr) = p; + + EASTL_ASSERT(((size_t)pAligned & ~(alignment - 1)) == (size_t)pAligned); + + return pAligned; + #elif (EASTL_DEBUGPARAMS_LEVEL <= 0) + return ::new(alignment, offset, (char*)0, flags, 0, (char*)0, 0) char[n]; + #elif (EASTL_DEBUGPARAMS_LEVEL == 1) + return ::new(alignment, offset, pName, flags, 0, (char*)0, 0) char[n]; + #else + return ::new(alignment, offset, pName, flags, 0, __FILE__, __LINE__) char[n]; + #endif + + #undef pName // See above for the definition of this. + } + + + inline void allocator::deallocate(void* p, size_t) + { + #if EASTL_DLL + if (p != nullptr) + { + void* pOriginalAllocation = *((void**)p - 1); + delete[](char*)pOriginalAllocation; + } + #else + delete[](char*)p; + #endif + } + + + inline bool operator==(const allocator&, const allocator&) + { + return true; // All allocators are considered equal, as they merely use global new/delete. + } + + + inline bool operator!=(const allocator&, const allocator&) + { + return false; // All allocators are considered equal, as they merely use global new/delete. + } + + + } // namespace eastl + + +#endif // EASTL_USER_DEFINED_ALLOCATOR + + + +namespace eastl +{ + + template + inline Allocator* get_default_allocator(const Allocator*) + { + return NULL; // By default we return NULL; the user must make specialization of this function in order to provide their own implementation. + } + + + inline EASTLAllocatorType* get_default_allocator(const EASTLAllocatorType*) + { + return EASTLAllocatorDefault(); // For the built-in allocator EASTLAllocatorType, we happen to already have a function for returning the default allocator instance, so we provide it. + } + + + inline void* default_allocfreemethod(size_t n, void* pBuffer, void* /*pContext*/) + { + EASTLAllocatorType* const pAllocator = EASTLAllocatorDefault(); + + if(pBuffer) // If freeing... + { + EASTLFree(*pAllocator, pBuffer, n); + return NULL; // The return value is meaningless for the free. + } + else // allocating + return EASTLAlloc(*pAllocator, n); + } + + + /// allocate_memory + /// + /// This is a memory allocation dispatching function. + /// To do: Make aligned and unaligned specializations. + /// Note that to do this we will need to use a class with a static + /// function instead of a standalone function like below. + /// + template + inline void* allocate_memory(Allocator& a, size_t n, size_t alignment, size_t alignmentOffset) + { + void *result; + if (alignment <= EASTL_ALLOCATOR_MIN_ALIGNMENT) + { + result = EASTLAlloc(a, n); + // Ensure the result is correctly aligned. An assertion likely indicates a mismatch between EASTL_ALLOCATOR_MIN_ALIGNMENT and the minimum alignment + // of EASTLAlloc. If there is a mismatch it may be necessary to define EASTL_ALLOCATOR_MIN_ALIGNMENT to be the minimum alignment of EASTLAlloc, or + // to increase the alignment of EASTLAlloc to match EASTL_ALLOCATOR_MIN_ALIGNMENT. + EASTL_ASSERT((reinterpret_cast(result)& ~(alignment - 1)) == reinterpret_cast(result)); + } + else + { + result = EASTLAllocAligned(a, n, alignment, alignmentOffset); + // Ensure the result is correctly aligned. An assertion here may indicate a bug in the allocator. + EASTL_ASSERT((reinterpret_cast(result)& ~(alignment - 1)) == reinterpret_cast(result)); + } + return result; + } + +} + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + + +#endif // Header include guard + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/allocator_malloc.h b/libs/eastl/include/EASTL/allocator_malloc.h new file mode 100644 index 0000000..fe59b70 --- /dev/null +++ b/libs/eastl/include/EASTL/allocator_malloc.h @@ -0,0 +1,124 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_ALLOCATOR_MALLOC_H +#define EASTL_ALLOCATOR_MALLOC_H + + +#include +#include +#include + + +// EASTL_ALIGNED_MALLOC_AVAILABLE +// +// Identifies if the standard library provides a built-in aligned version of malloc. +// Defined as 0 or 1, depending on the standard library or platform availability. +// None of the viable C functions provides for an aligned malloc with offset, so we +// don't consider that supported in any case. +// +// Options for aligned allocations: +// C11 aligned_alloc http://linux.die.net/man/3/aligned_alloc +// glibc memalign http://linux.die.net/man/3/posix_memalign +// Posix posix_memalign http://pubs.opengroup.org/onlinepubs/000095399/functions/posix_memalign.html +// VC++ _aligned_malloc http://msdn.microsoft.com/en-us/library/8z34s9c6%28VS.80%29.aspx This is not suitable, since it has a limitation that you need to free via _aligned_free. +// +#if !defined EASTL_ALIGNED_MALLOC_AVAILABLE + #if defined(EA_PLATFORM_POSIX) && !defined(EA_PLATFORM_APPLE) + // memalign is more consistently available than posix_memalign, though its location isn't consistent across + // platforms and compiler libraries. Typically it's declared in one of three headers: stdlib.h, malloc.h, or malloc/malloc.h + #include // memalign, posix_memalign. + #define EASTL_ALIGNED_MALLOC_AVAILABLE 1 + + #if defined(__clang__) + #if __has_include() + #include + #elif __has_include() + #include + #endif + #elif defined(EA_PLATFORM_BSD) + #include + #else + #include + #endif + #else + #define EASTL_ALIGNED_MALLOC_AVAILABLE 0 + #endif +#endif + + +namespace eastl +{ + + /////////////////////////////////////////////////////////////////////////////// + // allocator_malloc + // + // Implements an EASTL allocator that uses malloc/free as opposed to + // new/delete or PPMalloc Malloc/Free. + // + // Example usage: + // vector intVector; + // + class allocator_malloc + { + public: + allocator_malloc(const char* = NULL) + { } + + allocator_malloc(const allocator_malloc&) + { } + + allocator_malloc(const allocator_malloc&, const char*) + { } + + allocator_malloc& operator=(const allocator_malloc&) + { return *this; } + + bool operator==(const allocator_malloc&) + { return true; } + + bool operator!=(const allocator_malloc&) + { return false; } + + void* allocate(size_t n, int /*flags*/ = 0) + { return malloc(n); } + + void* allocate(size_t n, size_t alignment, size_t alignmentOffset, int /*flags*/ = 0) + { + #if EASTL_ALIGNED_MALLOC_AVAILABLE + if((alignmentOffset % alignment) == 0) // We check for (offset % alignmnent == 0) instead of (offset == 0) because any block which is aligned on e.g. 64 also is aligned at an offset of 64 by definition. + return memalign(alignment, n); // memalign is more consistently available than posix_memalign. + #else + if((alignment <= EASTL_SYSTEM_ALLOCATOR_MIN_ALIGNMENT) && ((alignmentOffset % alignment) == 0)) + return malloc(n); + #endif + return NULL; + } + + void deallocate(void* p, size_t /*n*/) + { free(p); } + + const char* get_name() const + { return "allocator_malloc"; } + + void set_name(const char*) + { } + }; + + +} // namespace eastl + + + +#endif // Header include guard + + + + + + + + + diff --git a/libs/eastl/include/EASTL/array.h b/libs/eastl/include/EASTL/array.h new file mode 100644 index 0000000..bc07948 --- /dev/null +++ b/libs/eastl/include/EASTL/array.h @@ -0,0 +1,496 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Implements a templated array class as per the C++ standard TR1 (technical +// report 1, which is a list of proposed C++ library amendments). +// The primary distinctions between this array and TR1 array are: +// - array::size_type is defined as eastl_size_t instead of size_t in order +// to save memory and run faster on 64 bit systems. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_ARRAY_H +#define EASTL_ARRAY_H + + +#include +#include +#include +#include +#include + +#if EASTL_EXCEPTIONS_ENABLED + #ifdef _MSC_VER + #pragma warning(push, 0) + #endif + #include // std::out_of_range, std::length_error. + #ifdef _MSC_VER + #pragma warning(pop) + #endif +#endif + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /////////////////////////////////////////////////////////////////////// + /// array + /// + /// Implements a templated array class as per the C++ standard TR1. + /// This class allows you to use a built-in C style array like an STL vector. + /// It does not let you change its size, as it is just like a C built-in array. + /// Our implementation here strives to remove function call nesting, as that + /// makes it hard for us to profile debug builds due to function call overhead. + /// Note that this is intentionally a struct with public data, as per the + /// C++ standard update proposal requirements. + /// + /// Example usage: + /// array a = { { 0, 1, 2, 3, 4 } }; // Strict compilers such as GCC require the double brackets. + /// a[2] = 4; + /// for(array::iterator i = a.begin(); i < a.end(); ++i) + /// *i = 0; + /// + template + struct array + { + public: + typedef array this_type; + typedef T value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* iterator; + typedef const value_type* const_iterator; + typedef eastl::reverse_iterator reverse_iterator; + typedef eastl::reverse_iterator const_reverse_iterator; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + + public: + enum + { + count = N + }; + + // Note that the member data is intentionally public. + // This allows for aggregate initialization of the + // object (e.g. array a = { 0, 3, 2, 4 }; ) + value_type mValue[N ? N : 1]; + + public: + // We intentionally provide no constructor, destructor, or assignment operator. + + void fill(const value_type& value); + + // Unlike the swap function for other containers, array::swap takes linear time, + // may exit via an exception, and does not cause iterators to become associated with the other container. + void swap(this_type& x) EA_NOEXCEPT_IF(eastl::is_nothrow_swappable::value); + + iterator begin() EA_NOEXCEPT; + const_iterator begin() const EA_NOEXCEPT; + const_iterator cbegin() const EA_NOEXCEPT; + + iterator end() EA_NOEXCEPT; + const_iterator end() const EA_NOEXCEPT; + const_iterator cend() const EA_NOEXCEPT; + + reverse_iterator rbegin() EA_NOEXCEPT; + const_reverse_iterator rbegin() const EA_NOEXCEPT; + const_reverse_iterator crbegin() const EA_NOEXCEPT; + + reverse_iterator rend() EA_NOEXCEPT; + const_reverse_iterator rend() const EA_NOEXCEPT; + const_reverse_iterator crend() const EA_NOEXCEPT; + + bool empty() const EA_NOEXCEPT; + size_type size() const EA_NOEXCEPT; + size_type max_size() const EA_NOEXCEPT; + + T* data() EA_NOEXCEPT; + const T* data() const EA_NOEXCEPT; + + reference operator[](size_type i); + const_reference operator[](size_type i) const; + const_reference at(size_type i) const; + reference at(size_type i); + + reference front(); + const_reference front() const; + + reference back(); + const_reference back() const; + + bool validate() const; + int validate_iterator(const_iterator i) const; + + }; // class array + + + + + /////////////////////////////////////////////////////////////////////// + // array + /////////////////////////////////////////////////////////////////////// + + + template + inline void array::fill(const value_type& value) + { + eastl::fill_n(&mValue[0], N, value); + } + + + template + inline void array::swap(this_type& x) EA_NOEXCEPT_IF(eastl::is_nothrow_swappable::value) + { + eastl::swap_ranges(&mValue[0], &mValue[N], &x.mValue[0]); + } + + + template + inline typename array::iterator + array::begin() EA_NOEXCEPT + { + return &mValue[0]; + } + + + template + inline typename array::const_iterator + array::begin() const EA_NOEXCEPT + { + return &mValue[0]; + } + + + template + inline typename array::const_iterator + array::cbegin() const EA_NOEXCEPT + { + return &mValue[0]; + } + + + template + inline typename array::iterator + array::end() EA_NOEXCEPT + { + return &mValue[N]; + } + + + template + inline typename array::const_iterator + array::end() const EA_NOEXCEPT + { + return &mValue[N]; + } + + + template + inline typename array::const_iterator + array::cend() const EA_NOEXCEPT + { + return &mValue[N]; + } + + + template + inline typename array::reverse_iterator + array::rbegin() EA_NOEXCEPT + { + return reverse_iterator(&mValue[N]); + } + + + template + inline typename array::const_reverse_iterator + array::rbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(&mValue[N]); + } + + + template + inline typename array::const_reverse_iterator + array::crbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(&mValue[N]); + } + + + template + inline typename array::reverse_iterator + array::rend() EA_NOEXCEPT + { + return reverse_iterator(&mValue[0]); + } + + + template + inline typename array::const_reverse_iterator + array::rend() const EA_NOEXCEPT + { + return const_reverse_iterator(reinterpret_cast(&mValue[0])); + } + + + template + inline typename array::const_reverse_iterator + array::crend() const EA_NOEXCEPT + { + return const_reverse_iterator(reinterpret_cast(&mValue[0])); + } + + + template + inline typename array::size_type + array::size() const EA_NOEXCEPT + { + return (size_type)N; + } + + + template + inline typename array::size_type + array::max_size() const EA_NOEXCEPT + { + return (size_type)N; + } + + + template + inline bool array::empty() const EA_NOEXCEPT + { + return (N == 0); + } + + + template + inline typename array::reference + array::operator[](size_type i) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(i >= N)) + EASTL_FAIL_MSG("array::operator[] -- out of range"); + #endif + + EA_ANALYSIS_ASSUME(i < N); + return mValue[i]; + } + + + template + inline typename array::const_reference + array::operator[](size_type i) const + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(i >= N)) + EASTL_FAIL_MSG("array::operator[] -- out of range"); + + #endif + + EA_ANALYSIS_ASSUME(i < N); + return mValue[i]; + } + + + template + inline typename array::reference + array::front() + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container. + EASTL_FAIL_MSG("array::front -- empty array"); + #endif + + return mValue[0]; + } + + + template + inline typename array::const_reference + array::front() const + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container. + EASTL_FAIL_MSG("array::front -- empty array"); + #endif + + return mValue[0]; + } + + + template + inline typename array::reference + array::back() + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container. + EASTL_FAIL_MSG("array::back -- empty array"); + #endif + + return mValue[N - 1]; + } + + + template + inline typename array::const_reference + array::back() const + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(empty())) // We don't allow the user to reference an empty container. + EASTL_FAIL_MSG("array::back -- empty array"); + #endif + + return mValue[N - 1]; + } + + + template + inline T* array::data() EA_NOEXCEPT + { + return mValue; + } + + + template + inline const T* + array::data() const EA_NOEXCEPT + { + return mValue; + } + + + template + inline typename array::const_reference + array::at(size_type i) const + { + #if EASTL_EXCEPTIONS_ENABLED + if(EASTL_UNLIKELY(i >= N)) + throw std::out_of_range("array::at -- out of range"); + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(i >= N)) + EASTL_FAIL_MSG("array::at -- out of range"); + #endif + + EA_ANALYSIS_ASSUME(i < N); + return reinterpret_cast(mValue[i]); + } + + + template + inline typename array::reference + array::at(size_type i) + { + #if EASTL_EXCEPTIONS_ENABLED + if(EASTL_UNLIKELY(i >= N)) + throw std::out_of_range("array::at -- out of range"); + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(i >= N)) + EASTL_FAIL_MSG("array::at -- out of range"); + #endif + + EA_ANALYSIS_ASSUME(i < N); + return reinterpret_cast(mValue[i]); + } + + + template + inline bool array::validate() const + { + return true; // There is nothing to do. + } + + + template + inline int array::validate_iterator(const_iterator i) const + { + if(i >= mValue) + { + if(i < (mValue + N)) + return (isf_valid | isf_current | isf_can_dereference); + + if(i <= (mValue + N)) + return (isf_valid | isf_current); + } + + return isf_none; + } + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const array& a, const array& b) + { + return eastl::equal(&a.mValue[0], &a.mValue[N], &b.mValue[0]); + } + + + template + inline bool operator<(const array& a, const array& b) + { + return eastl::lexicographical_compare(&a.mValue[0], &a.mValue[N], &b.mValue[0], &b.mValue[N]); + } + + + template + inline bool operator!=(const array& a, const array& b) + { + return !eastl::equal(&a.mValue[0], &a.mValue[N], &b.mValue[0]); + } + + + template + inline bool operator>(const array& a, const array& b) + { + return eastl::lexicographical_compare(&b.mValue[0], &b.mValue[N], &a.mValue[0], &a.mValue[N]); + } + + + template + inline bool operator<=(const array& a, const array& b) + { + return !eastl::lexicographical_compare(&b.mValue[0], &b.mValue[N], &a.mValue[0], &a.mValue[N]); + } + + + template + inline bool operator>=(const array& a, const array& b) + { + return !eastl::lexicographical_compare(&a.mValue[0], &a.mValue[N], &b.mValue[0], &b.mValue[N]); + } + + + template + inline void swap(array& a, array& b) + { + eastl::swap_ranges(&a.mValue[0], &a.mValue[N], &b.mValue[0]); + } + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/bitset.h b/libs/eastl/include/EASTL/bitset.h new file mode 100644 index 0000000..4f9a659 --- /dev/null +++ b/libs/eastl/include/EASTL/bitset.h @@ -0,0 +1,2254 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements a bitset much like the C++ std::bitset class. +// The primary distinctions between this list and std::bitset are: +// - bitset is more efficient than some other std::bitset implementations, +// notably the bitset that comes with Microsoft and other 1st party platforms. +// - bitset is savvy to an environment that doesn't have exception handling, +// as is sometimes the case with console or embedded environments. +// - bitset is savvy to environments in which 'unsigned long' is not the +// most efficient integral data type. std::bitset implementations use +// unsigned long, even if it is an inefficient integer type. +// - bitset removes as much function calls as practical, in order to allow +// debug builds to run closer in speed and code footprint to release builds. +// - bitset doesn't support string functionality. We can add this if +// it is deemed useful. +// +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_BITSET_H +#define EASTL_BITSET_H + + +#include +#include + +#ifdef _MSC_VER + #pragma warning(push, 0) +#endif +#include +#include +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#if EASTL_EXCEPTIONS_ENABLED + #ifdef _MSC_VER + #pragma warning(push, 0) + #endif + #include // std::out_of_range, std::length_error. + #ifdef _MSC_VER + #pragma warning(pop) + #endif +#endif + +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4127) // Conditional expression is constant +#endif + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + // To consider: Enable this for backwards compatibility with any user code that might be using BitsetWordType: + // #define BitsetWordType EASTL_BITSET_WORD_TYPE_DEFAULT + + + /// BITSET_WORD_COUNT + /// + /// Defines the number of words we use, based on the number of bits. + /// nBitCount refers to the number of bits in a bitset. + /// WordType refers to the type of integer word which stores bitet data. By default it is BitsetWordType. + /// + #if !defined(__GNUC__) || (__GNUC__ >= 3) // GCC 2.x can't handle the simpler declaration below. + #define BITSET_WORD_COUNT(nBitCount, WordType) (N == 0 ? 1 : ((N - 1) / (8 * sizeof(WordType)) + 1)) + #else + #define BITSET_WORD_COUNT(nBitCount, WordType) ((N - 1) / (8 * sizeof(WordType)) + 1) + #endif + + + /// EASTL_DISABLE_BITSET_ARRAYBOUNDS_WARNING + /// Before GCC 4.7 the '-Warray-bounds' buggy and was very likely to issue false positives for loops that are + /// difficult to evaluate. + /// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=45978 + /// + #if defined(__GNUC__) && (EA_COMPILER_VERSION > 4007) && defined(EA_PLATFORM_ANDROID) // Earlier than GCC 4.7 + #define EASTL_DISABLE_BITSET_ARRAYBOUNDS_WARNING 1 + #else + #define EASTL_DISABLE_BITSET_ARRAYBOUNDS_WARNING 0 + #endif + + + + /// BitsetBase + /// + /// This is a default implementation that works for any number of words. + /// + template // Templated on the number of words used to hold the bitset and the word type. + struct BitsetBase + { + typedef WordType word_type; + typedef BitsetBase this_type; + #if EASTL_BITSET_SIZE_T + typedef size_t size_type; + #else + typedef eastl_size_t size_type; + #endif + + enum { + kBitsPerWord = (8 * sizeof(word_type)), + kBitsPerWordMask = (kBitsPerWord - 1), + kBitsPerWordShift = ((kBitsPerWord == 8) ? 3 : ((kBitsPerWord == 16) ? 4 : ((kBitsPerWord == 32) ? 5 : (((kBitsPerWord == 64) ? 6 : 7))))) + }; + + public: + word_type mWord[NW]; + + public: + BitsetBase(); + BitsetBase(uint32_t value); // This exists only for compatibility with std::bitset, which has a 'long' constructor. + //BitsetBase(uint64_t value); // Disabled because it causes conflicts with the 32 bit version with existing user code. Use from_uint64 to init from a uint64_t instead. + + void operator&=(const this_type& x); + void operator|=(const this_type& x); + void operator^=(const this_type& x); + + void operator<<=(size_type n); + void operator>>=(size_type n); + + void flip(); + void set(); + void set(size_type i, bool value); + void reset(); + + bool operator==(const this_type& x) const; + + bool any() const; + size_type count() const; + + void from_uint32(uint32_t value); + void from_uint64(uint64_t value); + + unsigned long to_ulong() const; + uint32_t to_uint32() const; + uint64_t to_uint64() const; + + word_type& DoGetWord(size_type i); + word_type DoGetWord(size_type i) const; + + size_type DoFindFirst() const; + size_type DoFindNext(size_type last_find) const; + + size_type DoFindLast() const; // Returns NW * kBitsPerWord (the bit count) if no bits are set. + size_type DoFindPrev(size_type last_find) const; // Returns NW * kBitsPerWord (the bit count) if no bits are set. + + }; // class BitsetBase + + + + /// BitsetBase<1, WordType> + /// + /// This is a specialization for a bitset that fits within one word. + /// + template + struct BitsetBase<1, WordType> + { + typedef WordType word_type; + typedef BitsetBase<1, WordType> this_type; + #if EASTL_BITSET_SIZE_T + typedef size_t size_type; + #else + typedef eastl_size_t size_type; + #endif + + enum { + kBitsPerWord = (8 * sizeof(word_type)), + kBitsPerWordMask = (kBitsPerWord - 1), + kBitsPerWordShift = ((kBitsPerWord == 8) ? 3 : ((kBitsPerWord == 16) ? 4 : ((kBitsPerWord == 32) ? 5 : (((kBitsPerWord == 64) ? 6 : 7))))) + }; + + public: + word_type mWord[1]; // Defined as an array of 1 so that bitset can treat this BitsetBase like others. + + public: + BitsetBase(); + BitsetBase(uint32_t value); + //BitsetBase(uint64_t value); // Disabled because it causes conflicts with the 32 bit version with existing user code. Use from_uint64 instead. + + void operator&=(const this_type& x); + void operator|=(const this_type& x); + void operator^=(const this_type& x); + + void operator<<=(size_type n); + void operator>>=(size_type n); + + void flip(); + void set(); + void set(size_type i, bool value); + void reset(); + + bool operator==(const this_type& x) const; + + bool any() const; + size_type count() const; + + void from_uint32(uint32_t value); + void from_uint64(uint64_t value); + + unsigned long to_ulong() const; + uint32_t to_uint32() const; + uint64_t to_uint64() const; + + word_type& DoGetWord(size_type); + word_type DoGetWord(size_type) const; + + size_type DoFindFirst() const; + size_type DoFindNext(size_type last_find) const; + + size_type DoFindLast() const; // Returns 1 * kBitsPerWord (the bit count) if no bits are set. + size_type DoFindPrev(size_type last_find) const; // Returns 1 * kBitsPerWord (the bit count) if no bits are set. + + }; // BitsetBase<1, WordType> + + + + /// BitsetBase<2, WordType> + /// + /// This is a specialization for a bitset that fits within two words. + /// The difference here is that we avoid branching (ifs and loops). + /// + template + struct BitsetBase<2, WordType> + { + typedef WordType word_type; + typedef BitsetBase<2, WordType> this_type; + #if EASTL_BITSET_SIZE_T + typedef size_t size_type; + #else + typedef eastl_size_t size_type; + #endif + + enum { + kBitsPerWord = (8 * sizeof(word_type)), + kBitsPerWordMask = (kBitsPerWord - 1), + kBitsPerWordShift = ((kBitsPerWord == 8) ? 3 : ((kBitsPerWord == 16) ? 4 : ((kBitsPerWord == 32) ? 5 : (((kBitsPerWord == 64) ? 6 : 7))))) + }; + + public: + word_type mWord[2]; + + public: + BitsetBase(); + BitsetBase(uint32_t value); + //BitsetBase(uint64_t value); // Disabled because it causes conflicts with the 32 bit version with existing user code. Use from_uint64 instead. + + void operator&=(const this_type& x); + void operator|=(const this_type& x); + void operator^=(const this_type& x); + + void operator<<=(size_type n); + void operator>>=(size_type n); + + void flip(); + void set(); + void set(size_type i, bool value); + void reset(); + + bool operator==(const this_type& x) const; + + bool any() const; + size_type count() const; + + void from_uint32(uint32_t value); + void from_uint64(uint64_t value); + + unsigned long to_ulong() const; + uint32_t to_uint32() const; + uint64_t to_uint64() const; + + word_type& DoGetWord(size_type); + word_type DoGetWord(size_type) const; + + size_type DoFindFirst() const; + size_type DoFindNext(size_type last_find) const; + + size_type DoFindLast() const; // Returns 2 * kBitsPerWord (the bit count) if no bits are set. + size_type DoFindPrev(size_type last_find) const; // Returns 2 * kBitsPerWord (the bit count) if no bits are set. + + }; // BitsetBase<2, WordType> + + + + + /// bitset + /// + /// Implements a bitset much like the C++ std::bitset. + /// + /// As of this writing we don't implement a specialization of bitset<0>, + /// as it is deemed an academic exercise that nobody would actually + /// use and it would increase code space and provide little practical + /// benefit. Note that this doesn't mean bitset<0> isn't supported; + /// it means that our version of it isn't as efficient as it would be + /// if a specialization was made for it. + /// + /// - N can be any unsigned (non-zero) value, though memory usage is + /// linear with respect to N, so large values of N use large amounts of memory. + /// - WordType must be one of [uint16_t, uint32_t, uint64_t, uint128_t] + /// and the compiler must support the type. By default the WordType is + /// the largest native register type that the target platform supports. + /// + template + class bitset : private BitsetBase + { + public: + typedef BitsetBase base_type; + typedef bitset this_type; + typedef WordType word_type; + typedef typename base_type::size_type size_type; + + enum + { + kBitsPerWord = (8 * sizeof(word_type)), + kBitsPerWordMask = (kBitsPerWord - 1), + kBitsPerWordShift = ((kBitsPerWord == 8) ? 3 : ((kBitsPerWord == 16) ? 4 : ((kBitsPerWord == 32) ? 5 : (((kBitsPerWord == 64) ? 6 : 7))))), + kSize = N, // The number of bits the bitset holds + kWordSize = sizeof(word_type), // The size of individual words the bitset uses to hold the bits. + kWordCount = BITSET_WORD_COUNT(N, WordType) // The number of words the bitset uses to hold the bits. sizeof(bitset) == kWordSize * kWordCount. + }; + + using base_type::mWord; + using base_type::DoGetWord; + using base_type::DoFindFirst; + using base_type::DoFindNext; + using base_type::DoFindLast; + using base_type::DoFindPrev; + using base_type::to_ulong; + using base_type::to_uint32; + using base_type::to_uint64; + using base_type::count; + using base_type::any; + + public: + /// reference + /// + /// A reference is a reference to a specific bit in the bitset. + /// The C++ standard specifies that this be a nested class, + /// though it is not clear if a non-nested reference implementation + /// would be non-conforming. + /// + class reference + { + protected: + friend class bitset; + + word_type* mpBitWord; + size_type mnBitIndex; + + reference(){} // The C++ standard specifies that this is private. + + public: + reference(const bitset& x, size_type i); + + reference& operator=(bool value); + reference& operator=(const reference& x); + + bool operator~() const; + operator bool() const // Defined inline because CodeWarrior fails to be able to compile it outside. + { return (*mpBitWord & (static_cast(1) << (mnBitIndex & kBitsPerWordMask))) != 0; } + + reference& flip(); + }; + + public: + friend class reference; + + bitset(); + bitset(uint32_t value); + //bitset(uint64_t value); // Disabled because it causes conflicts with the 32 bit version with existing user code. Use from_uint64 instead. + + // We don't define copy constructor and operator= because + // the compiler-generated versions will suffice. + + this_type& operator&=(const this_type& x); + this_type& operator|=(const this_type& x); + this_type& operator^=(const this_type& x); + + this_type& operator<<=(size_type n); + this_type& operator>>=(size_type n); + + this_type& set(); + this_type& set(size_type i, bool value = true); + + this_type& reset(); + this_type& reset(size_type i); + + this_type& flip(); + this_type& flip(size_type i); + this_type operator~() const; + + reference operator[](size_type i); + bool operator[](size_type i) const; + + const word_type* data() const; + word_type* data(); + + void from_uint32(uint32_t value); + void from_uint64(uint64_t value); + + //unsigned long to_ulong() const; // We inherit this from the base class. + //uint32_t to_uint32() const; + //uint64_t to_uint64() const; + + //size_type count() const; // We inherit this from the base class. + size_type size() const; + + bool operator==(const this_type& x) const; + bool operator!=(const this_type& x) const; + + bool test(size_type i) const; + //bool any() const; // We inherit this from the base class. + bool all() const; + bool none() const; + + this_type operator<<(size_type n) const; + this_type operator>>(size_type n) const; + + // Finds the index of the first "on" bit, returns kSize if none are set. + size_type find_first() const; + + // Finds the index of the next "on" bit after last_find, returns kSize if none are set. + size_type find_next(size_type last_find) const; + + // Finds the index of the last "on" bit, returns kSize if none are set. + size_type find_last() const; + + // Finds the index of the last "on" bit before last_find, returns kSize if none are set. + size_type find_prev(size_type last_find) const; + + }; // bitset + + + + + + + + /// BitsetCountBits + /// + /// This is a fast trick way to count bits without branches nor memory accesses. + /// + inline uint32_t BitsetCountBits(uint64_t x) + { + // GCC 3.x's implementation of UINT64_C is broken and fails to deal with + // the code below correctly. So we make a workaround for it. Earlier and + // later versions of GCC don't have this bug. + + #if defined(__GNUC__) && (__GNUC__ == 3) + x = x - ((x >> 1) & 0x5555555555555555ULL); + x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL); + x = (x + (x >> 4)) & 0x0F0F0F0F0F0F0F0FULL; + return (uint32_t)((x * 0x0101010101010101ULL) >> 56); + #else + x = x - ((x >> 1) & UINT64_C(0x5555555555555555)); + x = (x & UINT64_C(0x3333333333333333)) + ((x >> 2) & UINT64_C(0x3333333333333333)); + x = (x + (x >> 4)) & UINT64_C(0x0F0F0F0F0F0F0F0F); + return (uint32_t)((x * UINT64_C(0x0101010101010101)) >> 56); + #endif + } + + inline uint32_t BitsetCountBits(uint32_t x) + { + x = x - ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + return (uint32_t)((x * 0x01010101) >> 24); + } + + inline uint32_t BitsetCountBits(uint16_t x) + { + return BitsetCountBits((uint32_t)x); + } + + inline uint32_t BitsetCountBits(uint8_t x) + { + return BitsetCountBits((uint32_t)x); + } + + + // const static char kBitsPerUint16[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; + #define EASTL_BITSET_COUNT_STRING "\0\1\1\2\1\2\2\3\1\2\2\3\2\3\3\4" + + + inline uint32_t GetFirstBit(uint8_t x) + { + if(x) + { + uint32_t n = 1; + + if((x & 0x0000000F) == 0) { n += 4; x >>= 4; } + if((x & 0x00000003) == 0) { n += 2; x >>= 2; } + + return (uint32_t)(n - (x & 1)); + } + + return 8; + } + + inline uint32_t GetFirstBit(uint16_t x) // To do: Update this to use VC++ _BitScanForward, _BitScanForward64; GCC __builtin_ctz, __builtin_ctzl. VC++ __lzcnt16, __lzcnt, __lzcnt64 requires recent CPUs (2013+) and probably can't be used. http://en.wikipedia.org/wiki/Haswell_%28microarchitecture%29#New_features + { + if(x) + { + uint32_t n = 1; + + if((x & 0x000000FF) == 0) { n += 8; x >>= 8; } + if((x & 0x0000000F) == 0) { n += 4; x >>= 4; } + if((x & 0x00000003) == 0) { n += 2; x >>= 2; } + + return (uint32_t)(n - (x & 1)); + } + + return 16; + } + + inline uint32_t GetFirstBit(uint32_t x) + { + if(x) + { + uint32_t n = 1; + + if((x & 0x0000FFFF) == 0) { n += 16; x >>= 16; } + if((x & 0x000000FF) == 0) { n += 8; x >>= 8; } + if((x & 0x0000000F) == 0) { n += 4; x >>= 4; } + if((x & 0x00000003) == 0) { n += 2; x >>= 2; } + + return (n - (x & 1)); + } + + return 32; + } + + inline uint32_t GetFirstBit(uint64_t x) + { + if(x) + { + uint32_t n = 1; + + if((x & 0xFFFFFFFF) == 0) { n += 32; x >>= 32; } + if((x & 0x0000FFFF) == 0) { n += 16; x >>= 16; } + if((x & 0x000000FF) == 0) { n += 8; x >>= 8; } + if((x & 0x0000000F) == 0) { n += 4; x >>= 4; } + if((x & 0x00000003) == 0) { n += 2; x >>= 2; } + + return (n - ((uint32_t)x & 1)); + } + + return 64; + } + + + #if EASTL_INT128_SUPPORTED + inline uint32_t GetFirstBit(eastl_uint128_t x) + { + if(x) + { + uint32_t n = 1; + + if((x & UINT64_C(0xFFFFFFFFFFFFFFFF)) == 0) { n += 64; x >>= 64; } + if((x & 0xFFFFFFFF) == 0) { n += 32; x >>= 32; } + if((x & 0x0000FFFF) == 0) { n += 16; x >>= 16; } + if((x & 0x000000FF) == 0) { n += 8; x >>= 8; } + if((x & 0x0000000F) == 0) { n += 4; x >>= 4; } + if((x & 0x00000003) == 0) { n += 2; x >>= 2; } + + return (n - ((uint32_t)x & 1)); + } + + return 128; + } + #endif + + inline uint32_t GetLastBit(uint8_t x) + { + if(x) + { + uint32_t n = 0; + + if(x & 0xFFF0) { n += 4; x >>= 4; } + if(x & 0xFFFC) { n += 2; x >>= 2; } + if(x & 0xFFFE) { n += 1; } + + return n; + } + + return 8; + } + + inline uint32_t GetLastBit(uint16_t x) + { + if(x) + { + uint32_t n = 0; + + if(x & 0xFF00) { n += 8; x >>= 8; } + if(x & 0xFFF0) { n += 4; x >>= 4; } + if(x & 0xFFFC) { n += 2; x >>= 2; } + if(x & 0xFFFE) { n += 1; } + + return n; + } + + return 16; + } + + inline uint32_t GetLastBit(uint32_t x) + { + if(x) + { + uint32_t n = 0; + + if(x & 0xFFFF0000) { n += 16; x >>= 16; } + if(x & 0xFFFFFF00) { n += 8; x >>= 8; } + if(x & 0xFFFFFFF0) { n += 4; x >>= 4; } + if(x & 0xFFFFFFFC) { n += 2; x >>= 2; } + if(x & 0xFFFFFFFE) { n += 1; } + + return n; + } + + return 32; + } + + inline uint32_t GetLastBit(uint64_t x) + { + if(x) + { + uint32_t n = 0; + + if(x & UINT64_C(0xFFFFFFFF00000000)) { n += 32; x >>= 32; } + if(x & 0xFFFF0000) { n += 16; x >>= 16; } + if(x & 0xFFFFFF00) { n += 8; x >>= 8; } + if(x & 0xFFFFFFF0) { n += 4; x >>= 4; } + if(x & 0xFFFFFFFC) { n += 2; x >>= 2; } + if(x & 0xFFFFFFFE) { n += 1; } + + return n; + } + + return 64; + } + + #if EASTL_INT128_SUPPORTED + inline uint32_t GetLastBit(eastl_uint128_t x) + { + if(x) + { + uint32_t n = 0; + + eastl_uint128_t mask(UINT64_C(0xFFFFFFFF00000000)); // There doesn't seem to exist compiler support for INT128_C() by any compiler. EAStdC's int128_t supports it though. + mask <<= 64; + + if(x & mask) { n += 64; x >>= 64; } + if(x & UINT64_C(0xFFFFFFFF00000000)) { n += 32; x >>= 32; } + if(x & UINT64_C(0x00000000FFFF0000)) { n += 16; x >>= 16; } + if(x & UINT64_C(0x00000000FFFFFF00)) { n += 8; x >>= 8; } + if(x & UINT64_C(0x00000000FFFFFFF0)) { n += 4; x >>= 4; } + if(x & UINT64_C(0x00000000FFFFFFFC)) { n += 2; x >>= 2; } + if(x & UINT64_C(0x00000000FFFFFFFE)) { n += 1; } + + return n; + } + + return 128; + } + #endif + + + + + /////////////////////////////////////////////////////////////////////////// + // BitsetBase + // + // We tried two forms of array access here: + // for(word_type *pWord(mWord), *pWordEnd(mWord + NW); pWord < pWordEnd; ++pWord) + // *pWord = ... + // and + // for(size_t i = 0; i < NW; i++) + // mWord[i] = ... + // + // For our tests (~NW < 16), the latter (using []) access resulted in faster code. + /////////////////////////////////////////////////////////////////////////// + + template + inline BitsetBase::BitsetBase() + { + reset(); + } + + + template + inline BitsetBase::BitsetBase(uint32_t value) + { + // This implementation assumes that sizeof(value) <= sizeof(word_type). + //EASTL_CT_ASSERT(sizeof(value) <= sizeof(word_type)); Disabled because we now have support for uint8_t and uint16_t word types. It would be nice to have a runtime assert that tested this. + + reset(); + mWord[0] = static_cast(value); + } + + + /* + template + inline BitsetBase::BitsetBase(uint64_t value) + { + reset(); + + #if(EA_PLATFORM_WORD_SIZE == 4) + mWord[0] = static_cast(value); + + EASTL_CT_ASSERT(NW > 2); // We can assume this because we have specializations of BitsetBase for <1> and <2>. + //if(NW > 1) // NW is a template constant, but it would be a little messy to take advantage of it's const-ness. + mWord[1] = static_cast(value >> 32); + #else + mWord[0] = static_cast(value); + #endif + } + */ + + + template + inline void BitsetBase::operator&=(const this_type& x) + { + for(size_t i = 0; i < NW; i++) + mWord[i] &= x.mWord[i]; + } + + + template + inline void BitsetBase::operator|=(const this_type& x) + { + for(size_t i = 0; i < NW; i++) + mWord[i] |= x.mWord[i]; + } + + + template + inline void BitsetBase::operator^=(const this_type& x) + { + for(size_t i = 0; i < NW; i++) + mWord[i] ^= x.mWord[i]; + } + + + template + inline void BitsetBase::operator<<=(size_type n) + { + const size_type nWordShift = (size_type)(n >> kBitsPerWordShift); + + if(nWordShift) + { + for(int i = (int)(NW - 1); i >= 0; --i) + mWord[i] = (nWordShift <= (size_type)i) ? mWord[i - nWordShift] : (word_type)0; + } + + if(n &= kBitsPerWordMask) + { + for(size_t i = (NW - 1); i > 0; --i) + mWord[i] = (word_type)((mWord[i] << n) | (mWord[i - 1] >> (kBitsPerWord - n))); + mWord[0] <<= n; + } + + // We let the parent class turn off any upper bits. + } + + + template + inline void BitsetBase::operator>>=(size_type n) + { + const size_type nWordShift = (size_type)(n >> kBitsPerWordShift); + + if(nWordShift) + { + for(size_t i = 0; i < NW; ++i) + mWord[i] = ((nWordShift < (NW - i)) ? mWord[i + nWordShift] : (word_type)0); + } + + if(n &= kBitsPerWordMask) + { + for(size_t i = 0; i < (NW - 1); ++i) + mWord[i] = (word_type)((mWord[i] >> n) | (mWord[i + 1] << (kBitsPerWord - n))); + mWord[NW - 1] >>= n; + } + } + + + template + inline void BitsetBase::flip() + { + for(size_t i = 0; i < NW; i++) + mWord[i] = ~mWord[i]; + // We let the parent class turn off any upper bits. + } + + + template + inline void BitsetBase::set() + { + for(size_t i = 0; i < NW; i++) + mWord[i] = static_cast(~static_cast(0)); + // We let the parent class turn off any upper bits. + } + + + template + inline void BitsetBase::set(size_type i, bool value) + { + if(value) + mWord[i >> kBitsPerWordShift] |= (static_cast(1) << (i & kBitsPerWordMask)); + else + mWord[i >> kBitsPerWordShift] &= ~(static_cast(1) << (i & kBitsPerWordMask)); + } + + + template + inline void BitsetBase::reset() + { + if(NW > 16) // This is a constant expression and should be optimized away. + { + // This will be fastest if compiler intrinsic function optimizations are enabled. + memset(mWord, 0, sizeof(mWord)); + } + else + { + for(size_t i = 0; i < NW; i++) + mWord[i] = 0; + } + } + + + template + inline bool BitsetBase::operator==(const this_type& x) const + { + for(size_t i = 0; i < NW; i++) + { + if(mWord[i] != x.mWord[i]) + return false; + } + return true; + } + + + template + inline bool BitsetBase::any() const + { + for(size_t i = 0; i < NW; i++) + { + if(mWord[i]) + return true; + } + return false; + } + + + template + inline typename BitsetBase::size_type + BitsetBase::count() const + { + size_type n = 0; + + for(size_t i = 0; i < NW; i++) + { + #if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 304) && !defined(EA_PLATFORM_ANDROID) // GCC 3.4 or later + #if(EA_PLATFORM_WORD_SIZE == 4) + n += (size_type)__builtin_popcountl(mWord[i]); + #else + n += (size_type)__builtin_popcountll(mWord[i]); + #endif + #elif defined(__GNUC__) && (__GNUC__ < 3) + n += BitsetCountBits(mWord[i]); // GCC 2.x compiler inexplicably blows up on the code below. + #else + // todo: use __popcnt16, __popcnt, __popcnt64 for msvc builds + // https://msdn.microsoft.com/en-us/library/bb385231(v=vs.140).aspx + for(word_type w = mWord[i]; w; w >>= 4) + n += EASTL_BITSET_COUNT_STRING[w & 0xF]; + + // Version which seems to run slower in benchmarks: + // n += BitsetCountBits(mWord[i]); + #endif + + } + return n; + } + + + template + inline void BitsetBase::from_uint32(uint32_t value) + { + reset(); + mWord[0] = static_cast(value); + } + + + template + inline void BitsetBase::from_uint64(uint64_t value) + { + reset(); + + #if(EA_PLATFORM_WORD_SIZE == 4) + mWord[0] = static_cast(value); + + EASTL_CT_ASSERT(NW > 2); // We can assume this because we have specializations of BitsetBase for <1> and <2>. + //if(NW > 1) // NW is a template constant, but it would be a little messy to take advantage of it's const-ness. + mWord[1] = static_cast(value >> 32); + #else + mWord[0] = static_cast(value); + #endif + } + + + template + inline unsigned long BitsetBase::to_ulong() const + { + #if EASTL_EXCEPTIONS_ENABLED + for(size_t i = 1; i < NW; ++i) + { + if(mWord[i]) + throw std::overflow_error("BitsetBase::to_ulong"); + } + #endif + return (unsigned long)mWord[0]; // Todo: We need to deal with the case whereby sizeof(word_type) < sizeof(unsigned long) + } + + + template + inline uint32_t BitsetBase::to_uint32() const + { + #if EASTL_EXCEPTIONS_ENABLED + // Verify that high words or bits are not set and thus that to_uint32 doesn't lose information. + for(size_t i = 1; i < NW; ++i) + { + if(mWord[i]) + throw std::overflow_error("BitsetBase::to_uint32"); + } + + #if(EA_PLATFORM_WORD_SIZE > 4) // if we have 64 bit words... + if(mWord[0] >> 32) + throw std::overflow_error("BitsetBase::to_uint32"); + #endif + #endif + + return (uint32_t)mWord[0]; + } + + + template + inline uint64_t BitsetBase::to_uint64() const + { + #if EASTL_EXCEPTIONS_ENABLED + // Verify that high words are not set and thus that to_uint64 doesn't lose information. + + EASTL_CT_ASSERT(NW > 2); // We can assume this because we have specializations of BitsetBase for <1> and <2>. + for(size_t i = 2; i < NW; ++i) + { + if(mWord[i]) + throw std::overflow_error("BitsetBase::to_uint64"); + } + #endif + + #if(EA_PLATFORM_WORD_SIZE == 4) + EASTL_CT_ASSERT(NW > 2); // We can assume this because we have specializations of BitsetBase for <1> and <2>. + return (mWord[1] << 32) | mWord[0]; + #else + return (uint64_t)mWord[0]; + #endif + } + + + template + inline typename BitsetBase::word_type& + BitsetBase::DoGetWord(size_type i) + { + return mWord[i >> kBitsPerWordShift]; + } + + + template + inline typename BitsetBase::word_type + BitsetBase::DoGetWord(size_type i) const + { + return mWord[i >> kBitsPerWordShift]; + } + + + template + inline typename BitsetBase::size_type + BitsetBase::DoFindFirst() const + { + for(size_type word_index = 0; word_index < NW; ++word_index) + { + const size_type fbiw = GetFirstBit(mWord[word_index]); + + if(fbiw != kBitsPerWord) + return (word_index * kBitsPerWord) + fbiw; + } + + return (size_type)NW * kBitsPerWord; + } + + +#if EASTL_DISABLE_BITSET_ARRAYBOUNDS_WARNING +EA_DISABLE_GCC_WARNING(-Warray-bounds) +#endif + + template + inline typename BitsetBase::size_type + BitsetBase::DoFindNext(size_type last_find) const + { + // Start looking from the next bit. + ++last_find; + + // Set initial state based on last find. + size_type word_index = static_cast(last_find >> kBitsPerWordShift); + size_type bit_index = static_cast(last_find & kBitsPerWordMask); + + // To do: There probably is a more elegant way to write looping below. + if(word_index < NW) + { + // Mask off previous bits of the word so our search becomes a "find first". + word_type this_word = mWord[word_index] & (~static_cast(0) << bit_index); + + for(;;) + { + const size_type fbiw = GetFirstBit(this_word); + + if(fbiw != kBitsPerWord) + return (word_index * kBitsPerWord) + fbiw; + + if(++word_index < NW) + this_word = mWord[word_index]; + else + break; + } + } + + return (size_type)NW * kBitsPerWord; + } + +#if EASTL_DISABLE_BITSET_ARRAYBOUNDS_WARNING +EA_RESTORE_GCC_WARNING() +#endif + + + + template + inline typename BitsetBase::size_type + BitsetBase::DoFindLast() const + { + for(size_type word_index = (size_type)NW; word_index > 0; --word_index) + { + const size_type lbiw = GetLastBit(mWord[word_index - 1]); + + if(lbiw != kBitsPerWord) + return ((word_index - 1) * kBitsPerWord) + lbiw; + } + + return (size_type)NW * kBitsPerWord; + } + + + template + inline typename BitsetBase::size_type + BitsetBase::DoFindPrev(size_type last_find) const + { + if(last_find > 0) + { + // Set initial state based on last find. + size_type word_index = static_cast(last_find >> kBitsPerWordShift); + size_type bit_index = static_cast(last_find & kBitsPerWordMask); + + // Mask off subsequent bits of the word so our search becomes a "find last". + word_type mask = (~static_cast(0) >> (kBitsPerWord - 1 - bit_index)) >> 1; // We do two shifts here because many CPUs ignore requests to shift 32 bit integers by 32 bits, which could be the case above. + word_type this_word = mWord[word_index] & mask; + + for(;;) + { + const size_type lbiw = GetLastBit(this_word); + + if(lbiw != kBitsPerWord) + return (word_index * kBitsPerWord) + lbiw; + + if(word_index > 0) + this_word = mWord[--word_index]; + else + break; + } + } + + return (size_type)NW * kBitsPerWord; + } + + + + /////////////////////////////////////////////////////////////////////////// + // BitsetBase<1, WordType> + /////////////////////////////////////////////////////////////////////////// + + template + inline BitsetBase<1, WordType>::BitsetBase() + { + mWord[0] = 0; + } + + + template + inline BitsetBase<1, WordType>::BitsetBase(uint32_t value) + { + // This implementation assumes that sizeof(value) <= sizeof(word_type). + //EASTL_CT_ASSERT(sizeof(value) <= sizeof(word_type)); Disabled because we now have support for uint8_t and uint16_t word types. It would be nice to have a runtime assert that tested this. + + mWord[0] = static_cast(value); + } + + + /* + template + inline BitsetBase<1, WordType>::BitsetBase(uint64_t value) + { + #if(EA_PLATFORM_WORD_SIZE == 4) + EASTL_ASSERT(value <= 0xffffffff); + mWord[0] = static_cast(value); // This potentially loses data, but that's what the user is requesting. + #else + mWord[0] = static_cast(value); + #endif + } + */ + + + template + inline void BitsetBase<1, WordType>::operator&=(const this_type& x) + { + mWord[0] &= x.mWord[0]; + } + + + template + inline void BitsetBase<1, WordType>::operator|=(const this_type& x) + { + mWord[0] |= x.mWord[0]; + } + + + template + inline void BitsetBase<1, WordType>::operator^=(const this_type& x) + { + mWord[0] ^= x.mWord[0]; + } + + + template + inline void BitsetBase<1, WordType>::operator<<=(size_type n) + { + mWord[0] <<= n; + // We let the parent class turn off any upper bits. + } + + + template + inline void BitsetBase<1, WordType>::operator>>=(size_type n) + { + mWord[0] >>= n; + } + + + template + inline void BitsetBase<1, WordType>::flip() + { + mWord[0] = ~mWord[0]; + // We let the parent class turn off any upper bits. + } + + + template + inline void BitsetBase<1, WordType>::set() + { + mWord[0] = static_cast(~static_cast(0)); + // We let the parent class turn off any upper bits. + } + + + template + inline void BitsetBase<1, WordType>::set(size_type i, bool value) + { + if(value) + mWord[0] |= (static_cast(1) << i); + else + mWord[0] &= ~(static_cast(1) << i); + } + + + template + inline void BitsetBase<1, WordType>::reset() + { + mWord[0] = 0; + } + + + template + inline bool BitsetBase<1, WordType>::operator==(const this_type& x) const + { + return mWord[0] == x.mWord[0]; + } + + + template + inline bool BitsetBase<1, WordType>::any() const + { + return mWord[0] != 0; + } + + + template + inline typename BitsetBase<1, WordType>::size_type + BitsetBase<1, WordType>::count() const + { + #if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 304) && !defined(EA_PLATFORM_ANDROID) // GCC 3.4 or later + #if(EA_PLATFORM_WORD_SIZE == 4) + return (size_type)__builtin_popcountl(mWord[0]); + #else + return (size_type)__builtin_popcountll(mWord[0]); + #endif + #elif defined(__GNUC__) && (__GNUC__ < 3) + return BitsetCountBits(mWord[0]); // GCC 2.x compiler inexplicably blows up on the code below. + #else + size_type n = 0; + for(word_type w = mWord[0]; w; w >>= 4) + n += EASTL_BITSET_COUNT_STRING[w & 0xF]; + return n; + #endif + } + + + template + inline void BitsetBase<1, WordType>::from_uint32(uint32_t value) + { + mWord[0] = static_cast(value); + } + + + template + inline void BitsetBase<1, WordType>::from_uint64(uint64_t value) + { + #if(EA_PLATFORM_WORD_SIZE == 4) + EASTL_ASSERT(value <= 0xffffffff); + mWord[0] = static_cast(value); // This potentially loses data, but that's what the user is requesting. + #else + mWord[0] = static_cast(value); + #endif + } + + + template + inline unsigned long BitsetBase<1, WordType>::to_ulong() const + { + #if EASTL_EXCEPTIONS_ENABLED + #if((EA_PLATFORM_WORD_SIZE > 4) && defined(EA_PLATFORM_MICROSOFT)) // If we are using 64 bit words but ulong is less than 64 bits... Microsoft platforms alone use a 32 bit long under 64 bit platforms. + // Verify that high bits are not set and thus that to_ulong doesn't lose information. + if(mWord[0] >> 32) + throw std::overflow_error("BitsetBase::to_ulong"); + #endif + #endif + + return static_cast(mWord[0]); + } + + + template + inline uint32_t BitsetBase<1, WordType>::to_uint32() const + { + #if EASTL_EXCEPTIONS_ENABLED + #if(EA_PLATFORM_WORD_SIZE > 4) // If we are using 64 bit words... + // Verify that high bits are not set and thus that to_uint32 doesn't lose information. + if(mWord[0] >> 32) + throw std::overflow_error("BitsetBase::to_uint32"); + #endif + #endif + + return static_cast(mWord[0]); + } + + + template + inline uint64_t BitsetBase<1, WordType>::to_uint64() const + { + // This implementation is the same regardless of the word size, and there is no possibility of overflow_error. + return static_cast(mWord[0]); + } + + + template + inline typename BitsetBase<1, WordType>::word_type& + BitsetBase<1, WordType>::DoGetWord(size_type) + { + return mWord[0]; + } + + + template + inline typename BitsetBase<1, WordType>::word_type + BitsetBase<1, WordType>::DoGetWord(size_type) const + { + return mWord[0]; + } + + + template + inline typename BitsetBase<1, WordType>::size_type + BitsetBase<1, WordType>::DoFindFirst() const + { + return GetFirstBit(mWord[0]); + } + + + template + inline typename BitsetBase<1, WordType>::size_type + BitsetBase<1, WordType>::DoFindNext(size_type last_find) const + { + if(++last_find < kBitsPerWord) + { + // Mask off previous bits of word so our search becomes a "find first". + const word_type this_word = mWord[0] & ((~static_cast(0)) << last_find); + + return GetFirstBit(this_word); + } + + return kBitsPerWord; + } + + + template + inline typename BitsetBase<1, WordType>::size_type + BitsetBase<1, WordType>::DoFindLast() const + { + return GetLastBit(mWord[0]); + } + + + template + inline typename BitsetBase<1, WordType>::size_type + BitsetBase<1, WordType>::DoFindPrev(size_type last_find) const + { + if(last_find > 0) + { + // Mask off previous bits of word so our search becomes a "find first". + const word_type this_word = mWord[0] & ((~static_cast(0)) >> (kBitsPerWord - last_find)); + + return GetLastBit(this_word); + } + + return kBitsPerWord; + } + + + + + /////////////////////////////////////////////////////////////////////////// + // BitsetBase<2, WordType> + /////////////////////////////////////////////////////////////////////////// + + template + inline BitsetBase<2, WordType>::BitsetBase() + { + mWord[0] = 0; + mWord[1] = 0; + } + + + template + inline BitsetBase<2, WordType>::BitsetBase(uint32_t value) + { + // This implementation assumes that sizeof(value) <= sizeof(word_type). + //EASTL_CT_ASSERT(sizeof(value) <= sizeof(word_type)); Disabled because we now have support for uint8_t and uint16_t word types. It would be nice to have a runtime assert that tested this. + + mWord[0] = static_cast(value); + mWord[1] = 0; + } + + + /* + template + inline BitsetBase<2, WordType>::BitsetBase(uint64_t value) + { + #if(EA_PLATFORM_WORD_SIZE == 4) + mWord[0] = static_cast(value); + mWord[1] = static_cast(value >> 32); + #else + mWord[0] = static_cast(value); + mWord[1] = 0; + #endif + } + */ + + + template + inline void BitsetBase<2, WordType>::operator&=(const this_type& x) + { + mWord[0] &= x.mWord[0]; + mWord[1] &= x.mWord[1]; + } + + + template + inline void BitsetBase<2, WordType>::operator|=(const this_type& x) + { + mWord[0] |= x.mWord[0]; + mWord[1] |= x.mWord[1]; + } + + + template + inline void BitsetBase<2, WordType>::operator^=(const this_type& x) + { + mWord[0] ^= x.mWord[0]; + mWord[1] ^= x.mWord[1]; + } + + + template + inline void BitsetBase<2, WordType>::operator<<=(size_type n) + { + if(n) // to avoid a shift by kBitsPerWord, which is undefined + { + if(EASTL_UNLIKELY(n >= kBitsPerWord)) // parent expected to handle high bits and n >= 64 + { + mWord[1] = mWord[0]; + mWord[0] = 0; + n -= kBitsPerWord; + } + + mWord[1] = (mWord[1] << n) | (mWord[0] >> (kBitsPerWord - n)); // Intentionally use | instead of +. + mWord[0] <<= n; + // We let the parent class turn off any upper bits. + } + } + + + template + inline void BitsetBase<2, WordType>::operator>>=(size_type n) + { + if(n) // to avoid a shift by kBitsPerWord, which is undefined + { + if(EASTL_UNLIKELY(n >= kBitsPerWord)) // parent expected to handle n >= 64 + { + mWord[0] = mWord[1]; + mWord[1] = 0; + n -= kBitsPerWord; + } + + mWord[0] = (mWord[0] >> n) | (mWord[1] << (kBitsPerWord - n)); // Intentionally use | instead of +. + mWord[1] >>= n; + } + } + + + template + inline void BitsetBase<2, WordType>::flip() + { + mWord[0] = ~mWord[0]; + mWord[1] = ~mWord[1]; + // We let the parent class turn off any upper bits. + } + + + template + inline void BitsetBase<2, WordType>::set() + { + mWord[0] = ~static_cast(0); + mWord[1] = ~static_cast(0); + // We let the parent class turn off any upper bits. + } + + + template + inline void BitsetBase<2, WordType>::set(size_type i, bool value) + { + if(value) + mWord[i >> kBitsPerWordShift] |= (static_cast(1) << (i & kBitsPerWordMask)); + else + mWord[i >> kBitsPerWordShift] &= ~(static_cast(1) << (i & kBitsPerWordMask)); + } + + + template + inline void BitsetBase<2, WordType>::reset() + { + mWord[0] = 0; + mWord[1] = 0; + } + + + template + inline bool BitsetBase<2, WordType>::operator==(const this_type& x) const + { + return (mWord[0] == x.mWord[0]) && (mWord[1] == x.mWord[1]); + } + + + template + inline bool BitsetBase<2, WordType>::any() const + { + // Or with two branches: { return (mWord[0] != 0) || (mWord[1] != 0); } + return (mWord[0] | mWord[1]) != 0; + } + + template + inline typename BitsetBase<2, WordType>::size_type + BitsetBase<2, WordType>::count() const + { + #if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 304) && !defined(EA_PLATFORM_ANDROID) // GCC 3.4 or later + #if(EA_PLATFORM_WORD_SIZE == 4) + return (size_type)__builtin_popcountl(mWord[0]) + (size_type)__builtin_popcountl(mWord[1]); + #else + return (size_type)__builtin_popcountll(mWord[0]) + (size_type)__builtin_popcountll(mWord[1]); + #endif + + #else + return BitsetCountBits(mWord[0]) + BitsetCountBits(mWord[1]); + #endif + } + + + template + inline void BitsetBase<2, WordType>::from_uint32(uint32_t value) + { + mWord[0] = static_cast(value); + mWord[1] = 0; + } + + + template + inline void BitsetBase<2, WordType>::from_uint64(uint64_t value) + { + #if(EA_PLATFORM_WORD_SIZE == 4) + mWord[0] = static_cast(value); + mWord[1] = static_cast(value >> 32); + #else + mWord[0] = static_cast(value); + mWord[1] = 0; + #endif + } + + + template + inline unsigned long BitsetBase<2, WordType>::to_ulong() const + { + #if EASTL_EXCEPTIONS_ENABLED + if(mWord[1]) + throw std::overflow_error("BitsetBase::to_ulong"); + #endif + return (unsigned long)mWord[0]; // Todo: We need to deal with the case whereby sizeof(word_type) < sizeof(unsigned long) + } + + + template + inline uint32_t BitsetBase<2, WordType>::to_uint32() const + { + #if EASTL_EXCEPTIONS_ENABLED + // Verify that high words or bits are not set and thus that to_uint32 doesn't lose information. + + #if(EA_PLATFORM_WORD_SIZE == 4) + if(mWord[1]) + throw std::overflow_error("BitsetBase::to_uint32"); + #else + if(mWord[1] || (mWord[0] >> 32)) + throw std::overflow_error("BitsetBase::to_uint32"); + #endif + #endif + + return (uint32_t)mWord[0]; + } + + + template + inline uint64_t BitsetBase<2, WordType>::to_uint64() const + { + #if(EA_PLATFORM_WORD_SIZE == 4) + // There can't possibly be an overflow_error here. + + return ((uint64_t)mWord[1] << 32) | mWord[0]; + #else + #if EASTL_EXCEPTIONS_ENABLED + if(mWord[1]) + throw std::overflow_error("BitsetBase::to_uint64"); + #endif + + return (uint64_t)mWord[0]; + #endif + } + + + template + inline typename BitsetBase<2, WordType>::word_type& + BitsetBase<2, WordType>::DoGetWord(size_type i) + { + return mWord[i >> kBitsPerWordShift]; + } + + + template + inline typename BitsetBase<2, WordType>::word_type + BitsetBase<2, WordType>::DoGetWord(size_type i) const + { + return mWord[i >> kBitsPerWordShift]; + } + + + template + inline typename BitsetBase<2, WordType>::size_type + BitsetBase<2, WordType>::DoFindFirst() const + { + size_type fbiw = GetFirstBit(mWord[0]); + + if(fbiw != kBitsPerWord) + return fbiw; + + fbiw = GetFirstBit(mWord[1]); + + if(fbiw != kBitsPerWord) + return kBitsPerWord + fbiw; + + return 2 * kBitsPerWord; + } + + + template + inline typename BitsetBase<2, WordType>::size_type + BitsetBase<2, WordType>::DoFindNext(size_type last_find) const + { + // If the last find was in the first word, we must check it and then possibly the second. + if(++last_find < (size_type)kBitsPerWord) + { + // Mask off previous bits of word so our search becomes a "find first". + word_type this_word = mWord[0] & ((~static_cast(0)) << last_find); + + // Step through words. + size_type fbiw = GetFirstBit(this_word); + + if(fbiw != kBitsPerWord) + return fbiw; + + fbiw = GetFirstBit(mWord[1]); + + if(fbiw != kBitsPerWord) + return kBitsPerWord + fbiw; + } + else if(last_find < (size_type)(2 * kBitsPerWord)) + { + // The last find was in the second word, remove the bit count of the first word from the find. + last_find -= kBitsPerWord; + + // Mask off previous bits of word so our search becomes a "find first". + word_type this_word = mWord[1] & ((~static_cast(0)) << last_find); + + const size_type fbiw = GetFirstBit(this_word); + + if(fbiw != kBitsPerWord) + return kBitsPerWord + fbiw; + } + + return 2 * kBitsPerWord; + } + + + template + inline typename BitsetBase<2, WordType>::size_type + BitsetBase<2, WordType>::DoFindLast() const + { + size_type lbiw = GetLastBit(mWord[1]); + + if(lbiw != kBitsPerWord) + return kBitsPerWord + lbiw; + + lbiw = GetLastBit(mWord[0]); + + if(lbiw != kBitsPerWord) + return lbiw; + + return 2 * kBitsPerWord; + } + + + template + inline typename BitsetBase<2, WordType>::size_type + BitsetBase<2, WordType>::DoFindPrev(size_type last_find) const + { + // If the last find was in the second word, we must check it and then possibly the first. + if(last_find > (size_type)kBitsPerWord) + { + // This has the same effect as last_find %= kBitsPerWord in our case. + last_find -= kBitsPerWord; + + // Mask off previous bits of word so our search becomes a "find first". + word_type this_word = mWord[1] & ((~static_cast(0)) >> (kBitsPerWord - last_find)); + + // Step through words. + size_type lbiw = GetLastBit(this_word); + + if(lbiw != kBitsPerWord) + return kBitsPerWord + lbiw; + + lbiw = GetLastBit(mWord[0]); + + if(lbiw != kBitsPerWord) + return lbiw; + } + else if(last_find != 0) + { + // Mask off previous bits of word so our search becomes a "find first". + word_type this_word = mWord[0] & ((~static_cast(0)) >> (kBitsPerWord - last_find)); + + const size_type lbiw = GetLastBit(this_word); + + if(lbiw != kBitsPerWord) + return lbiw; + } + + return 2 * kBitsPerWord; + } + + + + /////////////////////////////////////////////////////////////////////////// + // bitset::reference + /////////////////////////////////////////////////////////////////////////// + + template + inline bitset::reference::reference(const bitset& x, size_type i) + : mpBitWord(&const_cast(x).DoGetWord(i)), + mnBitIndex(i & kBitsPerWordMask) + { // We have an issue here because the above is casting away the const-ness of the source bitset. + // Empty + } + + + template + inline typename bitset::reference& + bitset::reference::operator=(bool value) + { + if(value) + *mpBitWord |= (static_cast(1) << (mnBitIndex & kBitsPerWordMask)); + else + *mpBitWord &= ~(static_cast(1) << (mnBitIndex & kBitsPerWordMask)); + return *this; + } + + + template + inline typename bitset::reference& + bitset::reference::operator=(const reference& x) + { + if(*x.mpBitWord & (static_cast(1) << (x.mnBitIndex & kBitsPerWordMask))) + *mpBitWord |= (static_cast(1) << (mnBitIndex & kBitsPerWordMask)); + else + *mpBitWord &= ~(static_cast(1) << (mnBitIndex & kBitsPerWordMask)); + return *this; + } + + + template + inline bool bitset::reference::operator~() const + { + return (*mpBitWord & (static_cast(1) << (mnBitIndex & kBitsPerWordMask))) == 0; + } + + + //Defined inline in the class because Metrowerks fails to be able to compile it here. + //template + //inline bitset::reference::operator bool() const + //{ + // return (*mpBitWord & (static_cast(1) << (mnBitIndex & kBitsPerWordMask))) != 0; + //} + + + template + inline typename bitset::reference& + bitset::reference::flip() + { + *mpBitWord ^= static_cast(1) << (mnBitIndex & kBitsPerWordMask); + return *this; + } + + + + + /////////////////////////////////////////////////////////////////////////// + // bitset + /////////////////////////////////////////////////////////////////////////// + + template + inline bitset::bitset() + : base_type() + { + // Empty. The base class will set all bits to zero. + } + + EA_DISABLE_VC_WARNING(6313) + template + inline bitset::bitset(uint32_t value) + : base_type(value) + { + if((N & kBitsPerWordMask) || (N == 0)) // If there are any high bits to clear... (If we didn't have this check, then the code below would do the wrong thing when N == 32. + mWord[kWordCount - 1] &= ~(static_cast(~static_cast(0)) << (N & kBitsPerWordMask)); // This clears any high unused bits. + } + EA_RESTORE_VC_WARNING() + + /* + template + inline bitset::bitset(uint64_t value) + : base_type(value) + { + if((N & kBitsPerWordMask) || (N == 0)) // If there are any high bits to clear... + mWord[kWordCount - 1] &= ~(~static_cast(0) << (N & kBitsPerWordMask)); // This clears any high unused bits. + } + */ + + + template + inline typename bitset::this_type& + bitset::operator&=(const this_type& x) + { + base_type::operator&=(x); + return *this; + } + + + template + inline typename bitset::this_type& + bitset::operator|=(const this_type& x) + { + base_type::operator|=(x); + return *this; + } + + + template + inline typename bitset::this_type& + bitset::operator^=(const this_type& x) + { + base_type::operator^=(x); + return *this; + } + + + template + inline typename bitset::this_type& + bitset::operator<<=(size_type n) + { + if(EASTL_LIKELY((intptr_t)n < (intptr_t)N)) + { + EA_DISABLE_VC_WARNING(6313) + base_type::operator<<=(n); + if((N & kBitsPerWordMask) || (N == 0)) // If there are any high bits to clear... (If we didn't have this check, then the code below would do the wrong thing when N == 32. + mWord[kWordCount - 1] &= ~(static_cast(~static_cast(0)) << (N & kBitsPerWordMask)); // This clears any high unused bits. We need to do this so that shift operations proceed correctly. + EA_RESTORE_VC_WARNING() + } + else + base_type::reset(); + return *this; + } + + + template + inline typename bitset::this_type& + bitset::operator>>=(size_type n) + { + if(EASTL_LIKELY(n < N)) + base_type::operator>>=(n); + else + base_type::reset(); + return *this; + } + + + template + inline typename bitset::this_type& + bitset::set() + { + base_type::set(); // This sets all bits. + if((N & kBitsPerWordMask) || (N == 0)) // If there are any high bits to clear... (If we didn't have this check, then the code below would do the wrong thing when N == 32. + mWord[kWordCount - 1] &= ~(static_cast(~static_cast(0)) << (N & kBitsPerWordMask)); // This clears any high unused bits. We need to do this so that shift operations proceed correctly. + return *this; + } + + + template + inline typename bitset::this_type& + bitset::set(size_type i, bool value) + { + if(i < N) + base_type::set(i, value); + else + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(!(i < N))) + EASTL_FAIL_MSG("bitset::set -- out of range"); + #endif + + #if EASTL_EXCEPTIONS_ENABLED + throw std::out_of_range("bitset::set"); + #endif + } + + return *this; + } + + + template + inline typename bitset::this_type& + bitset::reset() + { + base_type::reset(); + return *this; + } + + + template + inline typename bitset::this_type& + bitset::reset(size_type i) + { + if(EASTL_LIKELY(i < N)) + DoGetWord(i) &= ~(static_cast(1) << (i & kBitsPerWordMask)); + else + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(!(i < N))) + EASTL_FAIL_MSG("bitset::reset -- out of range"); + #endif + + #if EASTL_EXCEPTIONS_ENABLED + throw std::out_of_range("bitset::reset"); + #endif + } + + return *this; + } + + + template + inline typename bitset::this_type& + bitset::flip() + { + EA_DISABLE_VC_WARNING(6313) + base_type::flip(); + if((N & kBitsPerWordMask) || (N == 0)) // If there are any high bits to clear... (If we didn't have this check, then the code below would do the wrong thing when N == 32. + mWord[kWordCount - 1] &= ~(static_cast(~static_cast(0)) << (N & kBitsPerWordMask)); // This clears any high unused bits. We need to do this so that shift operations proceed correctly. + return *this; + EA_RESTORE_VC_WARNING() + } + + + template + inline typename bitset::this_type& + bitset::flip(size_type i) + { + if(EASTL_LIKELY(i < N)) + DoGetWord(i) ^= (static_cast(1) << (i & kBitsPerWordMask)); + else + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(!(i < N))) + EASTL_FAIL_MSG("bitset::flip -- out of range"); + #endif + + #if EASTL_EXCEPTIONS_ENABLED + throw std::out_of_range("bitset::flip"); + #endif + } + return *this; + } + + + template + inline typename bitset::this_type + bitset::operator~() const + { + return this_type(*this).flip(); + } + + + template + inline typename bitset::reference + bitset::operator[](size_type i) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(!(i < N))) + EASTL_FAIL_MSG("bitset::operator[] -- out of range"); + #endif + + return reference(*this, i); + } + + + template + inline bool bitset::operator[](size_type i) const + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(!(i < N))) + EASTL_FAIL_MSG("bitset::operator[] -- out of range"); + #endif + + return (DoGetWord(i) & (static_cast(1) << (i & kBitsPerWordMask))) != 0; + } + + + template + inline const typename bitset::word_type* bitset::data() const + { + return base_type::mWord; + } + + + template + inline typename bitset::word_type* bitset::data() + { + return base_type::mWord; + } + + + template + inline void bitset::from_uint32(uint32_t value) + { + base_type::from_uint32(value); + + if((N & kBitsPerWordMask) || (N == 0)) // If there are any high bits to clear... (If we didn't have this check, then the code below would do the wrong thing when N == 32. + mWord[kWordCount - 1] &= ~(static_cast(~static_cast(0)) << (N & kBitsPerWordMask)); // This clears any high unused bits. We need to do this so that shift operations proceed correctly. + } + + + template + inline void bitset::from_uint64(uint64_t value) + { + base_type::from_uint64(value); + + if((N & kBitsPerWordMask) || (N == 0)) // If there are any high bits to clear... (If we didn't have this check, then the code below would do the wrong thing when N == 32. + mWord[kWordCount - 1] &= ~(static_cast(~static_cast(0)) << (N & kBitsPerWordMask)); // This clears any high unused bits. We need to do this so that shift operations proceed correctly. + } + + + // template + // inline unsigned long bitset::to_ulong() const + // { + // return base_type::to_ulong(); + // } + + + // template + // inline uint32_t bitset::to_uint32() const + // { + // return base_type::to_uint32(); + // } + + + // template + // inline uint64_t bitset::to_uint64() const + // { + // return base_type::to_uint64(); + // } + + + // template + // inline typename bitset::size_type + // bitset::count() const + // { + // return base_type::count(); + // } + + + template + inline typename bitset::size_type + bitset::size() const + { + return (size_type)N; + } + + + template + inline bool bitset::operator==(const this_type& x) const + { + return base_type::operator==(x); + } + + + template + inline bool bitset::operator!=(const this_type& x) const + { + return !base_type::operator==(x); + } + + + template + inline bool bitset::test(size_type i) const + { + if(EASTL_UNLIKELY(i < N)) + return (DoGetWord(i) & (static_cast(1) << (i & kBitsPerWordMask))) != 0; + + #if EASTL_ASSERT_ENABLED + EASTL_FAIL_MSG("bitset::test -- out of range"); + #endif + + #if EASTL_EXCEPTIONS_ENABLED + throw std::out_of_range("bitset::test"); + #else + return false; + #endif + } + + + // template + // inline bool bitset::any() const + // { + // return base_type::any(); + // } + + + template + inline bool bitset::all() const + { + return count() == size(); + } + + + template + inline bool bitset::none() const + { + return !base_type::any(); + } + + + template + inline typename bitset::this_type + bitset::operator<<(size_type n) const + { + return this_type(*this).operator<<=(n); + } + + + template + inline typename bitset::this_type + bitset::operator>>(size_type n) const + { + return this_type(*this).operator>>=(n); + } + + + template + inline typename bitset::size_type + bitset::find_first() const + { + const size_type i = base_type::DoFindFirst(); + + if(i < kSize) + return i; + // Else i could be the base type bit count, so we clamp it to our size. + + return kSize; + } + + + template + inline typename bitset::size_type + bitset::find_next(size_type last_find) const + { + const size_type i = base_type::DoFindNext(last_find); + + if(i < kSize) + return i; + // Else i could be the base type bit count, so we clamp it to our size. + + return kSize; + } + + + template + inline typename bitset::size_type + bitset::find_last() const + { + const size_type i = base_type::DoFindLast(); + + if(i < kSize) + return i; + // Else i could be the base type bit count, so we clamp it to our size. + + return kSize; + } + + + template + inline typename bitset::size_type + bitset::find_prev(size_type last_find) const + { + const size_type i = base_type::DoFindPrev(last_find); + + if(i < kSize) + return i; + // Else i could be the base type bit count, so we clamp it to our size. + + return kSize; + } + + + + /////////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////////// + + template + inline bitset operator&(const bitset& a, const bitset& b) + { + // We get betting inlining when we don't declare temporary variables. + return bitset(a).operator&=(b); + } + + + template + inline bitset operator|(const bitset& a, const bitset& b) + { + return bitset(a).operator|=(b); + } + + + template + inline bitset operator^(const bitset& a, const bitset& b) + { + return bitset(a).operator^=(b); + } + + +} // namespace eastl + + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + + +#endif // Header include guard + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/bitvector.h b/libs/eastl/include/EASTL/bitvector.h new file mode 100644 index 0000000..b24b942 --- /dev/null +++ b/libs/eastl/include/EASTL/bitvector.h @@ -0,0 +1,1506 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Implements a bit vector, which is essentially a vector of bool but which +// uses bits instead of bytes. It is thus similar to the original std::vector. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Note: This code is not yet complete: it isn't tested and doesn't yet +// support containers other than vector. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_BITVECTOR_H +#define EASTL_BITVECTOR_H + + +#include +#include +#include +#include + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4480) // nonstandard extension used: specifying underlying type for enum +#endif + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// EASTL_BITVECTOR_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_BITVECTOR_DEFAULT_NAME + #define EASTL_BITVECTOR_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " bitvector" // Unless the user overrides something, this is "EASTL bitvector". + #endif + + /// EASTL_BITVECTOR_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_BITVECTOR_DEFAULT_ALLOCATOR + #define EASTL_BITVECTOR_DEFAULT_ALLOCATOR allocator_type(EASTL_BITVECTOR_DEFAULT_NAME) + #endif + + + + /// BitvectorWordType + /// Defines the integral data type used by bitvector. + typedef EASTL_BITSET_WORD_TYPE_DEFAULT BitvectorWordType; + + + template + class bitvector_const_iterator; + + + template + class bitvector_reference + { + public: + typedef eastl_size_t size_type; + bitvector_reference(Element* ptr, eastl_size_t i); + + bitvector_reference& operator=(bool value); + bitvector_reference& operator=(const bitvector_reference& rhs); + + operator bool() const // Defined here because some compilers fail otherwise. + { return (*mpBitWord & (Element(1) << mnBitIndex)) != 0; } + + protected: + friend class bitvector_const_iterator; + + Element* mpBitWord; + size_type mnBitIndex; + + bitvector_reference() {} + void CopyFrom(const bitvector_reference& rhs); + }; + + + + template + class bitvector_const_iterator + { + public: + typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category; + typedef bitvector_const_iterator this_type; + typedef bool value_type; + typedef bitvector_reference reference_type; + typedef ptrdiff_t difference_type; + typedef Element element_type; + typedef element_type* pointer; // This is wrong. It needs to be someting that acts as a pointer to a bit. + typedef element_type& reference; // This is not right. It needs to be someting that acts as a pointer to a bit. + typedef eastl_size_t size_type; + + protected: + reference_type mReference; + + enum + { + kBitCount = (8 * sizeof(Element)) + }; + + public: + bool operator*() const; + bool operator[](difference_type n) const; + + bitvector_const_iterator(); + bitvector_const_iterator(const element_type* p, eastl_size_t i); + bitvector_const_iterator(const reference_type& referenceType); + + bitvector_const_iterator& operator++(); + bitvector_const_iterator operator++(int); + bitvector_const_iterator& operator--(); + bitvector_const_iterator operator--(int); + + bitvector_const_iterator& operator+=(difference_type dist); + bitvector_const_iterator& operator-=(difference_type dist); + bitvector_const_iterator operator+ (difference_type dist) const; + bitvector_const_iterator operator- (difference_type dist) const; + + difference_type operator-(const this_type& rhs) const; + + bitvector_const_iterator& operator= (const this_type& rhs); + + bool operator==(const this_type& rhs) const; + bool operator!=(const this_type& rhs) const; + + bool operator< (const this_type& rhs) const; + bool operator<=(const this_type& rhs) const; + bool operator> (const this_type& rhs) const; + bool operator>=(const this_type& rhs) const; + + int validate(const element_type* pStart, const element_type* pEnd, eastl_size_t nExtraBits) const; + + protected: + template + friend class bitvector; + + reference_type& get_reference_type() { return mReference; } + }; + + + + template + class bitvector_iterator : public bitvector_const_iterator + { + public: + typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category; + typedef bitvector_iterator this_type; + typedef bitvector_const_iterator base_type; + typedef bool value_type; + typedef bitvector_reference reference_type; + typedef ptrdiff_t difference_type; + typedef Element element_type; + typedef element_type* pointer; // This is wrong. It needs to be someting that acts as a pointer to a bit. + typedef element_type& reference; // This is not right. It needs to be someting that acts as a pointer to a bit. + + public: + reference_type operator*() const; + reference_type operator[](difference_type n) const; + + bitvector_iterator(); + bitvector_iterator(element_type* p, eastl_size_t i); + bitvector_iterator(reference_type& referenceType); + + bitvector_iterator& operator++() { base_type::operator++(); return *this; } + bitvector_iterator& operator--() { base_type::operator--(); return *this; } + bitvector_iterator operator++(int); + bitvector_iterator operator--(int); + + bitvector_iterator& operator+=(difference_type dist) { base_type::operator+=(dist); return *this; } + bitvector_iterator& operator-=(difference_type dist) { base_type::operator-=(dist); return *this; } + bitvector_iterator operator+ (difference_type dist) const; + bitvector_iterator operator- (difference_type dist) const; + + // We need this here because we are overloading operator-, so for some reason the + // other overload of the function can't be found unless it's explicitly specified. + difference_type operator-(const base_type& rhs) const { return base_type::operator-(rhs); } + }; + + + + /// bitvector + /// + /// Implements an array of bits treated as boolean values. + /// bitvector is similar to vector but uses bits instead of bytes and + /// allows the user to use other containers such as deque instead of vector. + /// bitvector is different from bitset in that bitset is less flexible but + /// uses less memory and has higher performance. + /// + /// To consider: Rename the Element template parameter to WordType, for + /// consistency with bitset. + /// + template > + class bitvector + { + public: + typedef bitvector this_type; + typedef bool value_type; + typedef bitvector_reference reference; + typedef bool const_reference; + typedef bitvector_iterator iterator; + typedef bitvector_const_iterator const_iterator; + typedef eastl::reverse_iterator reverse_iterator; + typedef eastl::reverse_iterator const_reverse_iterator; + typedef Allocator allocator_type; + typedef Element element_type; + typedef Container container_type; + typedef eastl_size_t size_type; + typedef ptrdiff_t difference_type; + + #if defined(_MSC_VER) && (_MSC_VER >= 1400) && (_MSC_VER <= 1600) && !EASTL_STD_CPP_ONLY // _MSC_VER of 1400 means VS2005, 1600 means VS2010. VS2012 generates errors with usage of enum:size_type. + enum : size_type { // Use Microsoft enum language extension, allowing for smaller debug symbols than using a static const. Users have been affected by this. + npos = container_type::npos, + kMaxSize = container_type::kMaxSize + }; + #else + static const size_type npos = container_type::npos; /// 'npos' means non-valid position or simply non-position. + static const size_type kMaxSize = container_type::kMaxSize; /// -1 is reserved for 'npos'. It also happens to be slightly beneficial that kMaxSize is a value less than -1, as it helps us deal with potential integer wraparound issues. + #endif + + enum + { + kBitCount = 8 * sizeof(Element) + }; + + protected: + container_type mContainer; + size_type mFreeBitCount; // Unused bits in the last word of mContainer. + + public: + bitvector(); + explicit bitvector(const allocator_type& allocator); + explicit bitvector(size_type n, const allocator_type& allocator = EASTL_BITVECTOR_DEFAULT_ALLOCATOR); + bitvector(size_type n, value_type value, const allocator_type& allocator = EASTL_BITVECTOR_DEFAULT_ALLOCATOR); + bitvector(const bitvector& copy); + + template + bitvector(InputIterator first, InputIterator last); + + bitvector& operator=(const bitvector& x); + void swap(this_type& x); + + template + void assign(InputIterator first, InputIterator last); + + iterator begin() EA_NOEXCEPT; + const_iterator begin() const EA_NOEXCEPT; + const_iterator cbegin() const EA_NOEXCEPT; + + iterator end() EA_NOEXCEPT; + const_iterator end() const EA_NOEXCEPT; + const_iterator cend() const EA_NOEXCEPT; + + reverse_iterator rbegin() EA_NOEXCEPT; + const_reverse_iterator rbegin() const EA_NOEXCEPT; + const_reverse_iterator crbegin() const EA_NOEXCEPT; + + reverse_iterator rend() EA_NOEXCEPT; + const_reverse_iterator rend() const EA_NOEXCEPT; + const_reverse_iterator crend() const EA_NOEXCEPT; + + bool empty() const EA_NOEXCEPT; + size_type size() const EA_NOEXCEPT; + size_type capacity() const EA_NOEXCEPT; + + void resize(size_type n, value_type value); + void resize(size_type n); + void reserve(size_type n); + void set_capacity(size_type n = npos); // Revises the capacity to the user-specified value. Resizes the container to match the capacity if the requested capacity n is less than the current size. If n == npos then the capacity is reallocated (if necessary) such that capacity == size. + + void push_back(); + void push_back(value_type value); + void pop_back(); + + reference front(); + const_reference front() const; + reference back(); + const_reference back() const; + + bool test(size_type n, bool defaultValue) const; // Returns true if the bit index is < size() and set. Returns defaultValue if the bit is >= size(). + void set(size_type n, bool value); // Resizes the container to accomodate n if necessary. + + reference at(size_type n); // throws an out_of_range exception if n is invalid. + const_reference at(size_type n) const; + + reference operator[](size_type n); // behavior is undefined if n is invalid. + const_reference operator[](size_type n) const; + + /* + Work in progress: + template iterator find_first(); // Finds the lowest "on" bit. + template iterator find_next(const_iterator it); // Finds the next lowest "on" bit after it. + template iterator find_last(); // Finds the index of the last "on" bit, returns size if none are set. + template iterator find_prev(const_iterator it); // Finds the index of the last "on" bit before last_find, returns size if none are set. + + template const_iterator find_first() const; // Finds the lowest "on" bit. + template const_iterator find_next(const_iterator it) const; // Finds the next lowest "on" bit after it. + template const_iterator find_last() const; // Finds the index of the last "on" bit, returns size if none are set. + template const_iterator find_prev(const_iterator it) const; // Finds the index of the last "on" bit before last_find, returns size if none are set. + */ + + element_type* data() EA_NOEXCEPT; + const element_type* data() const EA_NOEXCEPT; + + iterator insert(const_iterator position, value_type value); + void insert(const_iterator position, size_type n, value_type value); + + // template Not yet implemented. See below for disabled definition. + // void insert(const_iterator position, InputIterator first, InputIterator last); + + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + + reverse_iterator erase(const_reverse_iterator position); + reverse_iterator erase(const_reverse_iterator first, const_reverse_iterator last); + + void clear(); + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + + container_type& get_container(); + const container_type& get_container() const; + + bool validate() const; + int validate_iterator(const_iterator i) const; + + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + }; + + + + + /////////////////////////////////////////////////////////////////////// + // bitvector_reference + /////////////////////////////////////////////////////////////////////// + + template + bitvector_reference::bitvector_reference(Element* p, eastl_size_t i) + : mpBitWord(p), + mnBitIndex(i) + { + } + + + template + bitvector_reference& + bitvector_reference::operator=(bool value) + { + const Element mask = (Element)(Element(1) << mnBitIndex); + + if(value) + *mpBitWord |= mask; + else + *mpBitWord &= ~mask; + + return *this; + } + + + template + bitvector_reference& + bitvector_reference::operator=(const bitvector_reference& rhs) + { + return (*this = (bool)rhs); + } + + + template + void bitvector_reference::CopyFrom(const bitvector_reference& rhs) + { + mpBitWord = rhs.mpBitWord; + mnBitIndex = rhs.mnBitIndex; + } + + + + + /////////////////////////////////////////////////////////////////////// + // bitvector_const_iterator + /////////////////////////////////////////////////////////////////////// + + template + bitvector_const_iterator::bitvector_const_iterator() + : mReference(0, 0) + { + } + + + template + bitvector_const_iterator::bitvector_const_iterator(const Element* p, eastl_size_t i) + : mReference(const_cast(p), i) // const_cast is safe here because we never let mReference leak and we don't modify it. + { + } + + + template + bitvector_const_iterator::bitvector_const_iterator(const reference_type& reference) + : mReference(reference) + { + } + + + template + bitvector_const_iterator& + bitvector_const_iterator::operator++() + { + ++mReference.mnBitIndex; + + if(mReference.mnBitIndex == kBitCount) + { + ++mReference.mpBitWord; + mReference.mnBitIndex = 0; + } + + return *this; + } + + + template + bitvector_const_iterator& + bitvector_const_iterator::operator--() + { + if(mReference.mnBitIndex == 0) + { + --mReference.mpBitWord; + mReference.mnBitIndex = kBitCount; + } + + --mReference.mnBitIndex; + return *this; + } + + + template + bitvector_const_iterator + bitvector_const_iterator::operator++(int) + { + bitvector_const_iterator copy(*this); + ++*this; + return copy; + } + + + template + bitvector_const_iterator + bitvector_const_iterator::operator--(int) + { + bitvector_const_iterator copy(*this); + --*this; + return copy; + } + + + template + bitvector_const_iterator& + bitvector_const_iterator::operator+=(difference_type n) + { + n += mReference.mnBitIndex; + + if(n >= difference_type(0)) + { + mReference.mpBitWord += n / kBitCount; + mReference.mnBitIndex = (size_type)(n % kBitCount); + } + else + { + // backwards is tricky + // figure out how many full words backwards we need to move + // n = [-1..-32] => 1 + // n = [-33..-64] => 2 + const size_type backwards = (size_type)(-n + kBitCount - 1); + mReference.mpBitWord -= backwards / kBitCount; + + // -1 => 31; backwards = 32; 31 - (backwards % 32) = 31 + // -2 => 30; backwards = 33; 31 - (backwards % 32) = 30 + // -3 => 29; backwards = 34 + // .. + // -32 => 0; backwards = 63; 31 - (backwards % 32) = 0 + // -33 => 31; backwards = 64; 31 - (backwards % 32) = 31 + mReference.mnBitIndex = (kBitCount - 1) - (backwards % kBitCount); + } + + return *this; + } + + + template + bitvector_const_iterator& + bitvector_const_iterator::operator-=(difference_type n) + { + return (*this += -n); + } + + + template + bitvector_const_iterator + bitvector_const_iterator::operator+(difference_type n) const + { + bitvector_const_iterator copy(*this); + copy += n; + return copy; + } + + + template + bitvector_const_iterator + bitvector_const_iterator::operator-(difference_type n) const + { + bitvector_const_iterator copy(*this); + copy -= n; + return copy; + } + + + template + typename bitvector_const_iterator::difference_type + bitvector_const_iterator::operator-(const this_type& rhs) const + { + return ((mReference.mpBitWord - rhs.mReference.mpBitWord) * kBitCount) + mReference.mnBitIndex - rhs.mReference.mnBitIndex; + } + + + template + bool bitvector_const_iterator::operator==(const this_type& rhs) const + { + return (mReference.mpBitWord == rhs.mReference.mpBitWord) && (mReference.mnBitIndex == rhs.mReference.mnBitIndex); + } + + + template + bool bitvector_const_iterator::operator!=(const this_type& rhs) const + { + return !(*this == rhs); + } + + + template + bool bitvector_const_iterator::operator<(const this_type& rhs) const + { + return (mReference.mpBitWord < rhs.mReference.mpBitWord) || + ((mReference.mpBitWord == rhs.mReference.mpBitWord) && (mReference.mnBitIndex < rhs.mReference.mnBitIndex)); + } + + + template + bool bitvector_const_iterator::operator<=(const this_type& rhs) const + { + return (mReference.mpBitWord < rhs.mReference.mpBitWord) || + ((mReference.mpBitWord == rhs.mReference.mpBitWord) && (mReference.mnBitIndex <= rhs.mReference.mnBitIndex)); + } + + + template + bool bitvector_const_iterator::operator>(const this_type& rhs) const + { + return !(*this <= rhs); + } + + + template + bool bitvector_const_iterator::operator>=(const this_type& rhs) const + { + return !(*this < rhs); + } + + + template + bool bitvector_const_iterator::operator*() const + { + return mReference; + } + + + template + bool bitvector_const_iterator::operator[](difference_type n) const + { + return *(*this + n); + } + + + template + bitvector_const_iterator& bitvector_const_iterator::operator= (const this_type& rhs) + { + mReference.CopyFrom(rhs.mReference); + return *this; + } + + + template + int bitvector_const_iterator::validate(const Element* pStart, const Element* pEnd, eastl_size_t nExtraBits) const + { + const Element* const pCurrent = mReference.mpBitWord; + + if(pCurrent >= pStart) + { + if(nExtraBits == 0) + { + if(pCurrent == pEnd && mReference) + return eastl::isf_valid | eastl::isf_current; + else if(pCurrent < pEnd) + return eastl::isf_valid | eastl::isf_current | eastl::isf_can_dereference; + } + else if(pCurrent == (pEnd - 1)) + { + const size_type bit = mReference.mnBitIndex; + const size_type lastbit = kBitCount - nExtraBits; + + if(bit == lastbit) + return eastl::isf_valid | eastl::isf_current; + else if(bit < lastbit) + return eastl::isf_valid | eastl::isf_current | eastl::isf_can_dereference; + } + else if(pCurrent < pEnd) + { + return eastl::isf_valid | eastl::isf_current | eastl::isf_can_dereference; + } + } + + return eastl::isf_none; + } + + + + /////////////////////////////////////////////////////////////////////// + // bitvector_iterator + /////////////////////////////////////////////////////////////////////// + + template + bitvector_iterator::bitvector_iterator() + : base_type() + { + } + + template + bitvector_iterator::bitvector_iterator(Element* p, eastl_size_t i) + : base_type(p, i) + { + } + + + template + bitvector_iterator::bitvector_iterator(reference_type& reference) + : base_type(reference) + { + } + + + template + typename bitvector_iterator::reference_type + bitvector_iterator::operator*() const + { + return base_type::mReference; + } + + + template + typename bitvector_iterator::reference_type + bitvector_iterator::operator[](difference_type n) const + { + return *(*this + n); + } + + + template + void MoveBits(bitvector_iterator start, + bitvector_iterator end, + bitvector_iterator dest) + { + // Slow implemenation; could optimize by moving a word at a time. + if(dest <= start) + { + while(start != end) + { + *dest = *start; + ++dest; + ++start; + } + } + else + { + // Need to move backwards + dest += (end - start); + + while(start != end) + { + --dest; + --end; + *dest = *end; + } + } + } + + + template + bitvector_iterator + bitvector_iterator::operator++(int) + { + bitvector_iterator copy(*this); + ++*this; + return copy; + } + + + template + bitvector_iterator + bitvector_iterator::operator--(int) + { + bitvector_iterator copy(*this); + --*this; + return copy; + } + + + template + bitvector_iterator + bitvector_iterator::operator+(difference_type n) const + { + bitvector_iterator copy(*this); + copy += n; + return copy; + } + + + template + bitvector_iterator + bitvector_iterator::operator-(difference_type n) const + { + bitvector_iterator copy(*this); + copy -= n; + return copy; + } + + + + + /////////////////////////////////////////////////////////////////////// + // bitvector + /////////////////////////////////////////////////////////////////////// + + template + template + void bitvector::assign(InputIterator first, InputIterator last) + { + // To consider: We can maybe specialize this on bitvector_iterator to do a fast bitwise copy. + // We can also specialize for random access iterators to figure out the size & reserve first. + + clear(); + + while(first != last) + { + push_back(*first); + ++first; + } + } + + + template + typename bitvector::iterator + bitvector::begin() EA_NOEXCEPT + { + return iterator(&mContainer[0], 0); + } + + + template + typename bitvector::const_iterator + bitvector::begin() const EA_NOEXCEPT + { + return const_iterator(&mContainer[0], 0); + } + + + template + typename bitvector::const_iterator + bitvector::cbegin() const EA_NOEXCEPT + { + return const_iterator(&mContainer[0], 0); + } + + + template + typename bitvector::iterator + bitvector::end() EA_NOEXCEPT + { + return iterator(mContainer.end(), 0) - mFreeBitCount; + } + + + template + typename bitvector::const_iterator + bitvector::end() const EA_NOEXCEPT + { + return const_iterator(mContainer.end(), 0) - mFreeBitCount; + } + + + template + typename bitvector::const_iterator + bitvector::cend() const EA_NOEXCEPT + { + return const_iterator(mContainer.end(), 0) - mFreeBitCount; + } + + + template + bool bitvector::empty() const EA_NOEXCEPT + { + return mContainer.empty(); + } + + + template + typename bitvector::size_type + bitvector::size() const EA_NOEXCEPT + { + return (mContainer.size() * kBitCount) - mFreeBitCount; + } + + + template + typename bitvector::size_type + bitvector::capacity() const EA_NOEXCEPT + { + return mContainer.capacity() * kBitCount; + } + + + template + void bitvector::set_capacity(size_type n) + { + if(n == npos) + mContainer.set_capacity(npos); + else + mContainer.set_capacity((n + kBitCount - 1) / kBitCount); + } + + + template + typename bitvector::reverse_iterator + bitvector::rbegin() EA_NOEXCEPT + { + return reverse_iterator(end()); + } + + + template + typename bitvector::const_reverse_iterator + bitvector::rbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(end()); + } + + + template + typename bitvector::const_reverse_iterator + bitvector::crbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(end()); + } + + + template + typename bitvector::reverse_iterator + bitvector::rend() EA_NOEXCEPT + { + return reverse_iterator(begin()); + } + + + template + typename bitvector::const_reverse_iterator + bitvector::rend() const EA_NOEXCEPT + { + return const_reverse_iterator(begin()); + } + + + template + typename bitvector::const_reverse_iterator + bitvector::crend() const EA_NOEXCEPT + { + return const_reverse_iterator(begin()); + } + + + template + typename bitvector::reference + bitvector::front() + { + EASTL_ASSERT(!empty()); + return reference(&mContainer[0], 0); + } + + + template + typename bitvector::const_reference + bitvector::front() const + { + EASTL_ASSERT(!empty()); + + // To consider: make a better solution to this than const_cast. + return reference(const_cast(&mContainer[0]), 0); + } + + + template + typename bitvector::reference + bitvector::back() + { + EASTL_ASSERT(!empty()); + return *(--end()); + } + + + template + typename bitvector::const_reference + bitvector::back() const + { + EASTL_ASSERT(!empty()); + return *(--end()); + } + + + template + void bitvector::push_back() + { + if(!mFreeBitCount) + { + mContainer.push_back(); + mFreeBitCount = kBitCount; + } + + --mFreeBitCount; + } + + + template + void bitvector::push_back(value_type value) + { + push_back(); + *--end() = value; + } + + + template + void bitvector::pop_back() + { + EASTL_ASSERT(!empty()); + + if(++mFreeBitCount == kBitCount) + { + mContainer.pop_back(); + mFreeBitCount = 0; + } + } + + + template + void bitvector::reserve(size_type n) + { + const size_type wordCount = (n + kBitCount - 1) / kBitCount; + mContainer.reserve(wordCount); + } + + + template + void bitvector::resize(size_type n) + { + const size_type wordCount = (n + kBitCount - 1) / kBitCount; + const size_type extra = (wordCount * kBitCount) - n; + + mContainer.resize(wordCount); + mFreeBitCount = extra; + } + + + template + void bitvector::resize(size_type n, value_type value) + { + const size_type s = size(); + if(n < s) + resize(n); + + // Fill up to the end of a word + size_type newbits = n - s; + + while(mFreeBitCount && newbits) + { + push_back(value); + --newbits; + } + + // Fill the rest a word at a time + if(newbits) + { + element_type element(0); + if(value) + element = ~element; + + const size_type words = (n + kBitCount - 1) / kBitCount; + const size_type extra = words * kBitCount - n; + mContainer.resize(words, element); + mFreeBitCount = extra; + } + } + + + template + bool bitvector::test(size_type n, bool defaultValue) const + { + if(n < size()) + return *(begin() + (difference_type)n); + + return defaultValue; + } + + + template + void bitvector::set(size_type n, bool value) + { + if(EASTL_UNLIKELY(n >= size())) + resize(n + 1); + + *(begin() + (difference_type)n) = value; + } + + + template + typename bitvector::reference + bitvector::at(size_type n) + { + // The difference between at and operator[] is that at signals + // if the requested position is out of range by throwing an + // out_of_range exception. + + #if EASTL_EXCEPTIONS_ENABLED + if(EASTL_UNLIKELY(n >= size())) + throw std::out_of_range("bitvector::at -- out of range"); + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(n >= size())) + EASTL_FAIL_MSG("bitvector::at -- out of range"); + #endif + + return *(begin() + (difference_type)n); + } + + + template + typename bitvector::const_reference + bitvector::at(size_type n) const + { + #if EASTL_EXCEPTIONS_ENABLED + if(EASTL_UNLIKELY(n >= size())) + throw std::out_of_range("bitvector::at -- out of range"); + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(n >= size())) + EASTL_FAIL_MSG("bitvector::at -- out of range"); + #endif + + return *(begin() + (difference_type)n); + } + + + template + typename bitvector::reference + bitvector::operator[](size_type n) + { + return *(begin() + (difference_type)n); + } + + + template + typename bitvector::const_reference + bitvector::operator[](size_type n) const + { + return *(begin() + (difference_type)n); + } + + +/* + template + template + typename bitvector::iterator + bitvector::find_first() + { + return begin(); + } + + template iterator find_next(const_iterator it); + template iterator find_last(); + template iterator find_prev(const_iterator it); + + template const_iterator find_first() const; + template const_iterator find_next(const_iterator it) const; + template const_iterator find_last() const; + template const_iterator find_prev(const_iterator it) const; +*/ + + + + + template + inline typename bitvector::container_type& + bitvector::get_container() + { + return mContainer; + } + + + template + inline const typename bitvector::container_type& + bitvector::get_container() const + { + return mContainer; + } + + + template + bool bitvector::validate() const + { + if(!mContainer.validate()) + return false; + + if((unsigned)mFreeBitCount >= kBitCount) + return false; + + return true; + } + + + template + int bitvector::validate_iterator(const_iterator i) const + { + return i.validate(mContainer.begin(), mContainer.end(), mFreeBitCount); + } + + + template + typename bitvector::element_type* + bitvector::data() EA_NOEXCEPT + { + return mContainer.data(); + } + + + template + const typename bitvector::element_type* + bitvector::data() const EA_NOEXCEPT + { + return mContainer.data(); + } + + + template + typename bitvector::iterator + bitvector::insert(const_iterator position, value_type value) + { + iterator iPosition(position.get_reference_type()); // This is just a non-const version of position. + + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(validate_iterator(iPosition) & eastl::isf_valid) == 0) + EASTL_FAIL_MSG("bitvector::insert -- invalid iterator"); + #endif + + // Save because we might reallocate + const typename iterator::difference_type n = iPosition - begin(); + push_back(); + iPosition = begin() + n; + + MoveBits(iPosition, --end(), ++iterator(iPosition)); + *iPosition = value; + + return iPosition; + } + + + template + void bitvector::insert(const_iterator position, size_type n, value_type value) + { + iterator iPosition(position.get_reference_type()); // This is just a non-const version of position. + + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(validate_iterator(iPosition) & eastl::isf_valid) == 0) + EASTL_FAIL_MSG("bitvector::insert -- invalid iterator"); + #endif + + // Save because we might reallocate. + const typename iterator::difference_type p = iPosition - begin(); + resize(size() + n); + iPosition = begin() + p; + + iterator insert_end = iPosition + n; + MoveBits(iPosition, end() - n, insert_end); + + // To do: Optimize this to word-at-a-time for large inserts + while(iPosition != insert_end) + { + *iPosition = value; + ++iPosition; + } + } + + + /* + The following is a placeholder for a future implementation. It turns out that a correct implementation of + insert(pos, first, last) is a non-trivial exercise that would take a few hours to implement and test. + The reasons why involve primarily the problem of handling the case where insertion source comes from + within the container itself, and the case that first and last (note they are templated) might not refer + to iterators might refer to a value/count pair. The C++ Standard requires you to handle this case and + I (Paul Pedriana) believe that it applies even for a bitvector, given that bool is an integral type. + So you have to set up a compile-time type traits function chooser. See vector, for example. + + template + template + void bitvector::insert(const_iterator position, InputIterator first, InputIterator last) + { + iterator iPosition(position.get_reference_type()); // This is just a non-const version of position. + + // This implementation is probably broken due to not handling insertion into self. + // To do: Make a more efficient version of this. + difference_type distance = (iPosition - begin()); + + while(first != last) + { + insert(iPosition, *first); + iPosition = begin() + ++distance; + ++first; + } + } + */ + + + template + typename bitvector::iterator + bitvector::erase(const_iterator position) + { + iterator iPosition(position.get_reference_type()); // This is just a non-const version of position. + + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(validate_iterator(iPosition) & eastl::isf_can_dereference) == 0) + EASTL_FAIL_MSG("bitvector::erase -- invalid iterator"); + #endif + + MoveBits(++iterator(iPosition), end(), iPosition); + resize(size() - 1); + + // Verify that no reallocation occurred. + EASTL_ASSERT(validate_iterator(iPosition) & eastl::isf_valid); + return iPosition; + } + + + template + typename bitvector::iterator + bitvector::erase(const_iterator first, const_iterator last) + { + iterator iFirst(first.get_reference_type()); // This is just a non-const version of first. + iterator iLast(last.get_reference_type()); // This is just a non-const version of last. + + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(validate_iterator(iLast) & eastl::isf_valid) == 0) + EASTL_FAIL_MSG("bitvector::erase -- invalid iterator"); + #endif + + if(!(iFirst == iLast)) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(validate_iterator(iFirst) & eastl::isf_can_dereference) == 0) + EASTL_FAIL_MSG("bitvector::erase -- invalid iterator"); + #endif + + const size_type eraseCount = (size_type)(iLast - iFirst); + MoveBits(iLast, end(), iFirst); + resize(size() - eraseCount); + + // Verify that no reallocation occurred. + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(validate_iterator(iFirst) & eastl::isf_valid) == 0) + EASTL_FAIL_MSG("bitvector::erase -- invalid iterator"); + #endif + } + + return iFirst; + } + + + template + typename bitvector::reverse_iterator + bitvector::erase(const_reverse_iterator position) + { + return reverse_iterator(erase((++position).base())); + } + + + template + typename bitvector::reverse_iterator + bitvector::erase(const_reverse_iterator first, const_reverse_iterator last) + { + // Version which erases in order from first to last. + // difference_type i(first.base() - last.base()); + // while(i--) + // first = erase(first); + // return first; + + // Version which erases in order from last to first, but is slightly more efficient: + return reverse_iterator(erase(last.base(), first.base())); + } + + + template + void bitvector::swap(this_type& rhs) + { + mContainer.swap(rhs.mContainer); + eastl::swap(mFreeBitCount, rhs.mFreeBitCount); + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + void bitvector::reset() + { + reset_lose_memory(); + } + #endif + + + template + void bitvector::reset_lose_memory() + { + mContainer.reset_lose_memory(); // intentional memory leak. + mFreeBitCount = 0; + } + + + template + void bitvector::clear() + { + mContainer.clear(); + mFreeBitCount = 0; + } + + + template + bitvector& + bitvector::operator=(const bitvector& rhs) + { + // The following is OK if (&rhs == this) + mContainer = rhs.mContainer; + mFreeBitCount = rhs.mFreeBitCount; + + return *this; + } + + + template + bitvector::bitvector() + : mContainer(), + mFreeBitCount(0) + { + } + + + template + bitvector::bitvector(const allocator_type& allocator) + : mContainer(allocator), + mFreeBitCount(0) + { + } + + + template + bitvector::bitvector(size_type n, const allocator_type& allocator) + : mContainer((n + kBitCount - 1) / kBitCount, allocator) + { + mFreeBitCount = kBitCount - (n % kBitCount); + + if(mFreeBitCount == kBitCount) + mFreeBitCount = 0; + } + + + template + bitvector::bitvector(size_type n, value_type value, const allocator_type& allocator) + : mContainer((n + kBitCount - 1) / kBitCount, value ? ~element_type(0) : element_type(0), allocator) + { + mFreeBitCount = kBitCount - (n % kBitCount); + + if(mFreeBitCount == kBitCount) + mFreeBitCount = 0; + } + + + template + bitvector::bitvector(const bitvector& copy) + : mContainer(copy.mContainer), + mFreeBitCount(copy.mFreeBitCount) + { + } + + + template + template + bitvector::bitvector(InputIterator first, InputIterator last) + : mContainer(), + mFreeBitCount(0) + { + assign(first, last); + } + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const bitvector& a, + const bitvector& b) + { + // To do: Replace this with a smart compare implementation. This is much slower than it needs to be. + return ((a.size() == b.size()) && equal(a.begin(), a.end(), b.begin())); + } + + + template + inline bool operator!=(const bitvector& a, + const bitvector& b) + { + return !operator==(a, b); + } + + + template + inline bool operator<(const bitvector& a, + const bitvector& b) + { + // To do: Replace this with a smart compare implementation. This is much slower than it needs to be. + return lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); + } + + + template + inline bool operator>(const bitvector& a, + const bitvector& b) + { + return b < a; + } + + + template + inline bool operator<=(const bitvector& a, + const bitvector& b) + { + return !(b < a); + } + + + template + inline bool operator>=(const bitvector& a, + const bitvector& b) + { + return !(a < b); + } + + template + inline void swap(bitvector& a, + bitvector& b) + { + a.swap(b); + } + + +} // namespace eastl + + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + + +#endif // Header include guard + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/bonus/adaptors.h b/libs/eastl/include/EASTL/bonus/adaptors.h new file mode 100644 index 0000000..d8c09cd --- /dev/null +++ b/libs/eastl/include/EASTL/bonus/adaptors.h @@ -0,0 +1,74 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_ADAPTORS_H +#define EASTL_ADAPTORS_H + + +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + +EA_DISABLE_VC_WARNING(4512 4626) +#if defined(_MSC_VER) && (_MSC_VER >= 1900) // VS2015+ + EA_DISABLE_VC_WARNING(5027) // move assignment operator was implicitly defined as deleted +#endif + + +namespace eastl +{ + /// reverse + /// + /// This adaptor allows reverse iteration of a container in ranged base for-loops. + /// + /// for (auto& i : reverse(c)) { ... } + /// + template + struct reverse_wrapper + { + reverse_wrapper(Container& c) : mContainer(c) {} + Container& mContainer; + }; + + template + auto begin(const reverse_wrapper& w) -> decltype(rbegin(w.mContainer)) + { return rbegin(w.mContainer); } + + template + auto end(const reverse_wrapper& w) -> decltype(rend(w.mContainer)) + { return rend(w.mContainer); } + + template + reverse_wrapper reverse(Container&& c) + { return reverse_wrapper(eastl::forward(c)); } + +} // namespace eastl + +#if defined(_MSC_VER) && (_MSC_VER >= 1900) // VS2015+ + EA_RESTORE_VC_WARNING() +#endif +EA_RESTORE_VC_WARNING() + +#endif // Header include guard + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/bonus/call_traits.h b/libs/eastl/include/EASTL/bonus/call_traits.h new file mode 100644 index 0000000..0995d05 --- /dev/null +++ b/libs/eastl/include/EASTL/bonus/call_traits.h @@ -0,0 +1,117 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// The design for call_traits here is very similar to that found in template +// metaprogramming libraries such as Boost, GCC, and Metrowerks, given that +// these libraries have established this interface as a defacto standard for +// solving this problem. Also, these are described in various books on the +// topic of template metaprogramming, such as "Modern C++ Design". +// +// See http://www.boost.org/libs/utility/call_traits.htm or search for +// call_traits in Google for a description of call_traits. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_CALL_TRAITS_H +#define EASTL_CALL_TRAITS_H + + +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + + template + struct ct_imp2 { typedef const T& param_type; }; + + template + struct ct_imp2 { typedef const T param_type; }; + + template + struct ct_imp { typedef const T& param_type; }; + + template + struct ct_imp { typedef typename ct_imp2::param_type param_type; }; + + template + struct ct_imp { typedef T const param_type; }; + + + + template + struct call_traits + { + public: + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; + typedef typename ct_imp::value, is_arithmetic::value>::param_type param_type; + }; + + + template + struct call_traits + { + typedef T& value_type; + typedef T& reference; + typedef const T& const_reference; + typedef T& param_type; + }; + + + template + struct call_traits + { + private: + typedef T array_type[N]; + + public: + typedef const T* value_type; + typedef array_type& reference; + typedef const array_type& const_reference; + typedef const T* const param_type; + }; + + + template + struct call_traits + { + private: + typedef const T array_type[N]; + + public: + typedef const T* value_type; + typedef array_type& reference; + typedef const array_type& const_reference; + typedef const T* const param_type; + }; + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/bonus/compressed_pair.h b/libs/eastl/include/EASTL/bonus/compressed_pair.h new file mode 100644 index 0000000..379642b --- /dev/null +++ b/libs/eastl/include/EASTL/bonus/compressed_pair.h @@ -0,0 +1,460 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// The compressed pair class is very similar to std::pair, but if either of the +// template arguments are empty classes, then the "empty base-class optimization" +// is applied to compress the size of the pair. +// +// The design for compressed_pair here is very similar to that found in template +// metaprogramming libraries such as Boost, GCC, and Metrowerks, given that +// these libraries have established this interface as a defacto standard for +// solving this problem. Also, these are described in various books on the +// topic of template metaprogramming, such as "Modern C++ Design". +// +// template +// class compressed_pair +// { +// public: +// typedef T1 first_type; +// typedef T2 second_type; +// typedef typename call_traits::param_type first_param_type; +// typedef typename call_traits::param_type second_param_type; +// typedef typename call_traits::reference first_reference; +// typedef typename call_traits::reference second_reference; +// typedef typename call_traits::const_reference first_const_reference; +// typedef typename call_traits::const_reference second_const_reference; +// +// compressed_pair() : base() {} +// compressed_pair(first_param_type x, second_param_type y); +// explicit compressed_pair(first_param_type x); +// explicit compressed_pair(second_param_type y); +// +// compressed_pair& operator=(const compressed_pair&); +// +// first_reference first(); +// first_const_reference first() const; +// +// second_reference second(); +// second_const_reference second() const; +// +// void swap(compressed_pair& y); +// }; +// +// The two members of the pair can be accessed using the member functions first() +// and second(). Note that not all member functions can be instantiated for all +// template parameter types. In particular compressed_pair can be instantiated for +// reference and array types, however in these cases the range of constructors that +// can be used are limited. If types T1 and T2 are the same type, then there is +// only one version of the single-argument constructor, and this constructor +// initialises both values in the pair to the passed value. +// +// Note that compressed_pair can not be instantiated if either of the template +// arguments is a union type, unless there is compiler support for is_union, +// or if is_union is specialised for the union type. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_COMPRESSED_PAIR_H +#define EASTL_COMPRESSED_PAIR_H + + +#include +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1900) // VS2015 or later + EA_DISABLE_VC_WARNING(4626 5027) // warning C4626: 'eastl::compressed_pair_imp': assignment operator was implicitly defined as deleted because a base class assignment operator is inaccessible or deleted +#endif + +namespace eastl +{ + + template + class compressed_pair; + + + template + struct compressed_pair_switch; + + template + struct compressed_pair_switch{ static const int value = 0; }; + + template + struct compressed_pair_switch { static const int value = 1; }; + + template + struct compressed_pair_switch { static const int value = 2; }; + + template + struct compressed_pair_switch { static const int value = 3; }; + + template + struct compressed_pair_switch { static const int value = 4; }; + + template + struct compressed_pair_switch { static const int value = 5; }; + + template + class compressed_pair_imp; + + + + template + inline void cp_swap(T& t1, T& t2) + { + T tTemp = t1; + t1 = t2; + t2 = tTemp; + } + + + // Derive from neither + template + class compressed_pair_imp + { + public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair_imp() {} + + compressed_pair_imp(first_param_type x, second_param_type y) + : mFirst(x), mSecond(y) {} + + compressed_pair_imp(first_param_type x) + : mFirst(x) {} + + compressed_pair_imp(second_param_type y) + : mSecond(y) {} + + first_reference first() { return mFirst; } + first_const_reference first() const { return mFirst; } + + second_reference second() { return mSecond; } + second_const_reference second() const { return mSecond; } + + void swap(compressed_pair& y) + { + cp_swap(mFirst, y.first()); + cp_swap(mSecond, y.second()); + } + + private: + first_type mFirst; + second_type mSecond; + }; + + + // Derive from T1 + template + class compressed_pair_imp : private T1 + { + public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair_imp() {} + + compressed_pair_imp(first_param_type x, second_param_type y) + : first_type(x), mSecond(y) {} + + compressed_pair_imp(first_param_type x) + : first_type(x) {} + + compressed_pair_imp(second_param_type y) + : mSecond(y) {} + + first_reference first() { return *this; } + first_const_reference first() const { return *this; } + + second_reference second() { return mSecond; } + second_const_reference second() const { return mSecond; } + + void swap(compressed_pair& y) + { + // No need to swap empty base class + cp_swap(mSecond, y.second()); + } + + private: + second_type mSecond; + }; + + + + // Derive from T2 + template + class compressed_pair_imp : private T2 + { + public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair_imp() {} + + compressed_pair_imp(first_param_type x, second_param_type y) + : second_type(y), mFirst(x) {} + + compressed_pair_imp(first_param_type x) + : mFirst(x) {} + + compressed_pair_imp(second_param_type y) + : second_type(y) {} + + first_reference first() { return mFirst; } + first_const_reference first() const { return mFirst; } + + second_reference second() { return *this; } + second_const_reference second() const { return *this; } + + void swap(compressed_pair& y) + { + // No need to swap empty base class + cp_swap(mFirst, y.first()); + } + + private: + first_type mFirst; + }; + + + + // Derive from T1 and T2 + template + class compressed_pair_imp : private T1, private T2 + { + public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair_imp() {} + + compressed_pair_imp(first_param_type x, second_param_type y) + : first_type(x), second_type(y) {} + + compressed_pair_imp(first_param_type x) + : first_type(x) {} + + compressed_pair_imp(second_param_type y) + : second_type(y) {} + + first_reference first() { return *this; } + first_const_reference first() const { return *this; } + + second_reference second() { return *this; } + second_const_reference second() const { return *this; } + + // No need to swap empty bases + void swap(compressed_pair&) + { } + }; + + + // T1 == T2, T1 and T2 are both empty + // Note does not actually store an instance of T2 at all; + // but reuses T1 base class for both first() and second(). + template + class compressed_pair_imp : private T1 + { + public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair_imp() {} + + compressed_pair_imp(first_param_type x, second_param_type) + : first_type(x) {} + + compressed_pair_imp(first_param_type x) + : first_type(x) {} + + first_reference first() { return *this; } + first_const_reference first() const { return *this; } + + second_reference second() { return *this; } + second_const_reference second() const { return *this; } + + void swap(compressed_pair&) { } + }; + + + // T1 == T2 and are not empty + template + class compressed_pair_imp + { + public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair_imp() {} + + compressed_pair_imp(first_param_type x, second_param_type y) + : mFirst(x), mSecond(y) {} + + compressed_pair_imp(first_param_type x) + : mFirst(x), mSecond(x) {} + + first_reference first() { return mFirst; } + first_const_reference first() const { return mFirst; } + + second_reference second() { return mSecond; } + second_const_reference second() const { return mSecond; } + + void swap(compressed_pair& y) + { + cp_swap(mFirst, y.first()); + cp_swap(mSecond, y.second()); + } + + private: + first_type mFirst; + second_type mSecond; + }; + + + + template + class compressed_pair + : private compressed_pair_imp::type, typename remove_cv::type>::value, + is_empty::value, + is_empty::value>::value> + { + private: + typedef compressed_pair_imp::type, typename remove_cv::type>::value, + is_empty::value, + is_empty::value>::value> base; + public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair() : base() {} + compressed_pair(first_param_type x, second_param_type y) : base(x, y) {} + explicit compressed_pair(first_param_type x) : base(x) {} + explicit compressed_pair(second_param_type y) : base(y) {} + + first_reference first() { return base::first(); } + first_const_reference first() const { return base::first(); } + + second_reference second() { return base::second(); } + second_const_reference second() const { return base::second(); } + + void swap(compressed_pair& y) { base::swap(y); } + }; + + + // Partial specialisation for case where T1 == T2: + template + class compressed_pair + : private compressed_pair_imp::type, typename remove_cv::type>::value, + is_empty::value, + is_empty::value>::value> + { + private: + typedef compressed_pair_imp::type, typename remove_cv::type>::value, + is_empty::value, + is_empty::value>::value> base; + public: + typedef T first_type; + typedef T second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair() : base() {} + compressed_pair(first_param_type x, second_param_type y) : base(x, y) {} + explicit compressed_pair(first_param_type x) : base(x) {} + + first_reference first() { return base::first(); } + first_const_reference first() const { return base::first(); } + + second_reference second() { return base::second(); } + second_const_reference second() const { return base::second(); } + + void swap(compressed_pair& y) { base::swap(y); } + }; + + + template + inline void swap(compressed_pair& x, compressed_pair& y) + { + x.swap(y); + } + + +} // namespace eastl + +#if defined(_MSC_VER) && (_MSC_VER >= 1900) // VS2015 or later + EA_RESTORE_VC_WARNING() +#endif + +#endif // Header include guard + + + diff --git a/libs/eastl/include/EASTL/bonus/fixed_string_abstract.h b/libs/eastl/include/EASTL/bonus/fixed_string_abstract.h new file mode 100644 index 0000000..2341d54 --- /dev/null +++ b/libs/eastl/include/EASTL/bonus/fixed_string_abstract.h @@ -0,0 +1,638 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements a string which uses a fixed size memory pool. +// The bEnableOverflow template parameter allows the container to resort to +// heap allocations if the memory pool is exhausted. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_FIXED_STRING_ABSTRACT_H +#define EASTL_FIXED_STRING_ABSTRACT_H + + +#include +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + /// EASTL_FIXED_STRING_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// In the case of fixed-size containers, the allocator name always refers + /// to overflow allocations. + /// + #ifndef EASTL_FIXED_STRING_DEFAULT_NAME + #define EASTL_FIXED_STRING_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_string" // Unless the user overrides something, this is "EASTL fixed_string". + #endif + + + + /// fixed_string + /// + /// A fixed_string with bEnableOverflow == true is identical to a regular + /// string in terms of its behavior. All the expectations of regular string + /// apply to it and no additional expectations come from it. When bEnableOverflow + /// is false, fixed_string behaves like regular string with the exception that + /// its capacity can never increase. All operations you do on such a fixed_string + /// which require a capacity increase will result in undefined behavior or an + /// C++ allocation exception, depending on the configuration of EASTL. + /// + /// Note: The nodeCount value is the amount of characters to allocate, which needs to + /// take into account a terminating zero. Thus if you want to store strings with a strlen + /// of 30, the nodeCount value must be at least 31. + /// + /// Template parameters: + /// T The type of object the string holds (char, wchar_t, char8_t, char16_t, char32_t). + /// nodeCount The max number of objects to contain. + /// bEnableOverflow Whether or not we should use the overflow heap if our object pool is exhausted. + /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. + /// + /// Notes: + /// The nodeCount value must be at least 2, one for a character and one for a terminating 0. + /// + /// As of this writing, the string class necessarily reallocates when an insert of + /// self is done into self. As a result, the fixed_string class doesn't support + /// inserting self into self unless the bEnableOverflow template parameter is true. + /// + /// Example usage: + /// fixed_string fixedString("hello world"); // Can hold up to a strlen of 128. + /// + /// fixedString = "hola mundo"; + /// fixedString.clear(); + /// fixedString.resize(200); + /// fixedString.sprintf("%f", 1.5f); + /// + template + class fixed_string : public basic_string > + { + public: + typedef fixed_vector_allocator fixed_allocator_type; + typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; + typedef abstract_string abstract_type; + typedef basic_string base_type; + typedef fixed_string this_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::CtorDoNotInitialize CtorDoNotInitialize; + typedef typename base_type::CtorSprintf CtorSprintf; + typedef aligned_buffer aligned_buffer_type; + + enum { kMaxSize = nodeCount - 1 }; // -1 because we need to save one element for the silent terminating null. + + using base_type::npos; + using base_type::mpBegin; + using base_type::mpEnd; + using base_type::mpCapacity; + using base_type::mAllocator; + using base_type::append; + using base_type::resize; + using base_type::clear; + using base_type::size; + using base_type::sprintf_va_list; + using base_type::mpAllocFreeMethod; + using base_type::DoAllocate; + using base_type::DoFree; + + protected: + union // We define a union in order to avoid strict pointer aliasing issues with compilers like GCC. + { + value_type mArray[1]; + aligned_buffer_type mBuffer; // Question: Why are we doing this aligned_buffer thing? Why not just do an array of value_type, given that we are using just strings of char types. + }; + + public: + fixed_string(); + explicit fixed_string(const overflow_allocator_type& overflowAllocator); // Only applicable if bEnableOverflow is true. + fixed_string(const this_type& x); // Currently we don't support overflowAllocator specification for other constructors, for simplicity. + fixed_string(const base_type& x); + fixed_string(const abstract_type& x); + fixed_string(const base_type& x, size_type position, size_type n = base_type::npos); + fixed_string(const value_type* p, size_type n); + fixed_string(const value_type* p); + fixed_string(size_type n, const value_type& value); + fixed_string(const value_type* pBegin, const value_type* pEnd); + fixed_string(CtorDoNotInitialize, size_type n); + fixed_string(CtorSprintf, const value_type* pFormat, ...); + + this_type& operator=(const this_type& x); + this_type& operator=(const base_type& x); + this_type& operator=(const abstract_type& x); + this_type& operator=(const value_type* p); + this_type& operator=(const value_type c); + + void swap(this_type& x); + + void set_capacity(size_type n); + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + size_type max_size() const; + bool full() const; // Returns true if the fixed space has been fully allocated. Note that if overflow is enabled, the container size can be greater than nodeCount but full() could return true because the fixed space may have a recently freed slot. + bool has_overflowed() const; // Returns true if the allocations spilled over into the overflow allocator. Meaningful only if overflow is enabled. + bool can_overflow() const; // Returns the value of the bEnableOverflow template parameter. + + // The inherited versions of substr/left/right call the basic_string constructor, + // which will call the overflow allocator and fail if bEnableOverflow == false + fixed_string substr(size_type position, size_type n) const; + fixed_string left(size_type n) const; + fixed_string right(size_type n) const; + + // OverflowAllocator + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT; + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT; + void set_overflow_allocator(const overflow_allocator_type& allocator); + + static void* AllocFreeMethod(size_t n, void* pBuffer, void* pContext); + + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + + }; // fixed_string + + + + + + /////////////////////////////////////////////////////////////////////// + // fixed_string + /////////////////////////////////////////////////////////////////////// + + template + inline fixed_string::fixed_string() + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpAllocFreeMethod = &fixed_string::AllocFreeMethod; + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + } + + + template + inline fixed_string::fixed_string(const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpAllocFreeMethod = &fixed_string::AllocFreeMethod; + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + } + + + template + inline fixed_string::fixed_string(const this_type& x) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + mpAllocFreeMethod = &fixed_string::AllocFreeMethod; + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(x); + } + + + template + inline fixed_string::fixed_string(const base_type& x) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.get_allocator().get_name()); + #endif + + mpAllocFreeMethod = &fixed_string::AllocFreeMethod; + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(x); + } + + + template + inline fixed_string::fixed_string(const abstract_type& x) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED // abstract_string doesn't have a predefined allocator type we can copy from. + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpAllocFreeMethod = &fixed_string::AllocFreeMethod; + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(x.data(), x.length()); + } + + + template + inline fixed_string::fixed_string(const base_type& x, size_type position, size_type n) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.get_allocator().get_name()); + #endif + + mpAllocFreeMethod = &fixed_string::AllocFreeMethod; + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(x, position, n); + } + + + template + inline fixed_string::fixed_string(const value_type* p, size_type n) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpAllocFreeMethod = &fixed_string::AllocFreeMethod; + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(p, n); + } + + + template + inline fixed_string::fixed_string(const value_type* p) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpAllocFreeMethod = &fixed_string::AllocFreeMethod; + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(p); // There better be enough space to hold the assigned string. + } + + + template + inline fixed_string::fixed_string(size_type n, const value_type& value) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpAllocFreeMethod = &fixed_string::AllocFreeMethod; + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(n, value); // There better be enough space to hold the assigned string. + } + + + template + inline fixed_string::fixed_string(const value_type* pBegin, const value_type* pEnd) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpAllocFreeMethod = &fixed_string::AllocFreeMethod; + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(pBegin, pEnd); + } + + + template + inline fixed_string::fixed_string(CtorDoNotInitialize, size_type n) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpAllocFreeMethod = &fixed_string::AllocFreeMethod; + mpBegin = mArray; + mpCapacity = mpBegin + nodeCount; + + if((mpBegin + n) < mpCapacity) + { + mpEnd = mpBegin + n; + *mpEnd = 0; + } + else + { + mpEnd = mArray; + *mpEnd = 0; + resize(n); + } + } + + + template + inline fixed_string::fixed_string(CtorSprintf, const value_type* pFormat, ...) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpAllocFreeMethod = &fixed_string::AllocFreeMethod; + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + va_list arguments; + va_start(arguments, pFormat); + sprintf_va_list(pFormat, arguments); + va_end(arguments); + } + + + template + inline typename fixed_string::this_type& + fixed_string::operator=(const this_type& x) + { + if(this != &x) + { + clear(); + append(x); + } + return *this; + } + + + template + inline typename fixed_string:: + this_type& fixed_string::operator=(const base_type& x) + { + if(static_cast(this) != &x) + { + clear(); + append(x); + } + return *this; + } + + + template + inline typename fixed_string:: + this_type& fixed_string::operator=(const abstract_type& x) + { + if(static_cast(this) != &x) + { + clear(); + append(x.data(), x.length()); + } + return *this; + } + + + template + inline typename fixed_string:: + this_type& fixed_string::operator=(const value_type* p) + { + if(mpBegin != p) + { + clear(); + append(p); + } + return *this; + } + + + template + inline typename fixed_string:: + this_type& fixed_string::operator=(const value_type c) + { + clear(); + append((size_type)1, c); + return *this; + } + + + template + inline void fixed_string::swap(this_type& x) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(*this, x); + } + + + template + inline void fixed_string::set_capacity(size_type n) + { + const size_type nPrevSize = (size_type)(mpEnd - mpBegin); + const size_type nPrevCapacity = (size_type)((mpCapacity - mpBegin) - 1); // -1 because the terminating 0 isn't included in the calculated capacity value. + + if(n == npos) // If the user means to set the capacity so that it equals the size (i.e. free excess capacity)... + n = nPrevSize; + + if(n != nPrevCapacity) // If the request results in a capacity change... + { + const size_type allocSize = (n + 1); // +1 because the terminating 0 isn't included in the supplied capacity value. So now n refers the amount of memory we need. + + if(can_overflow() && (((uintptr_t)mpBegin != (uintptr_t)mBuffer.buffer) || (allocSize > kMaxSize))) // If we are or would be using dynamically allocated memory instead of our fixed-size member buffer... + { + T* const pNewData = (allocSize <= kMaxSize) ? (T*)&mBuffer.buffer[0] : DoAllocate(allocSize); + T* const pCopyEnd = (n < nPrevSize) ? (mpBegin + n) : mpEnd; + CharStringUninitializedCopy(mpBegin, pCopyEnd, pNewData); // Copy [mpBegin, pCopyEnd) to pNewData. + if((uintptr_t)mpBegin != (uintptr_t)mBuffer.buffer) + DoFree(mpBegin, (size_type)(mpCapacity - mpBegin)); + + mpEnd = pNewData + (pCopyEnd - mpBegin); + mpBegin = pNewData; + mpCapacity = mpBegin + allocSize; + } // Else the new capacity would be within our fixed buffer. + else if(n < nPrevSize) // If the newly requested capacity is less than our size, we do what vector::set_capacity does and resize, even though we actually aren't reducing the capacity. + resize(n); + } + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void fixed_string::reset() + { + reset_lose_memory(); + } + #endif + + + template + inline void fixed_string::reset_lose_memory() + { + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + } + + + template + inline typename fixed_string:: + size_type fixed_string::max_size() const + { + return kMaxSize; + } + + + template + inline bool fixed_string::full() const + { + // If size >= capacity, then we are definitely full. + // Also, if our size is smaller but we've switched away from mBuffer due to a previous overflow, then we are considered full. + return ((size_t)(mpEnd - mpBegin) >= kMaxSize) || ((void*)mpBegin != (void*)mBuffer.buffer); + } + + + template + inline bool fixed_string::has_overflowed() const + { + // This will be incorrect for the case that bOverflowEnabled is true and the container was resized + // down to a small size where the fixed buffer could take over ownership of the data again. + // The only simple fix for this is to take on another member variable which tracks whether this overflow + // has occurred at some point in the past. + return ((void*)mpBegin != (void*)mBuffer.buffer); + } + + + template + inline bool fixed_string::can_overflow() const + { + return bEnableOverflow; + } + + + template + inline typename fixed_string:: + this_type fixed_string::substr(size_type position, size_type n) const + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(position > (size_type)(mpEnd - mpBegin)) + ThrowRangeException(); + #endif + + return fixed_string(mpBegin + position, mpBegin + position + eastl::min_alt(n, (size_type)(mpEnd - mpBegin) - position)); + } + + + template + inline typename fixed_string:: + this_type fixed_string::left(size_type n) const + { + const size_type nLength = size(); + if(n < nLength) + return fixed_string(mpBegin, mpBegin + n); + return *this; + } + + + template + inline typename fixed_string:: + this_type fixed_string::right(size_type n) const + { + const size_type nLength = size(); + if(n < nLength) + return fixed_string(mpEnd - n, mpEnd); + return *this; + } + + + template + inline void* fixed_string::AllocFreeMethod(size_t n, void* pBuffer, void* pContext) + { + // Use the basic_string method to reuse the same allocator code + // In reality, we should have a specific implementation + // We could also handle the overflow code at this level (instead of doing it at the allocator level) + return base_type::AllocFreeMethod(n, pBuffer, pContext); + } + + + template + inline const typename fixed_string:: + overflow_allocator_type& fixed_string::get_overflow_allocator() const EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline typename fixed_string:: + overflow_allocator_type& fixed_string::get_overflow_allocator() EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline void + fixed_string::set_overflow_allocator(const overflow_allocator_type& allocator) + { + mAllocator.set_overflow_allocator(allocator); + } + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + // operator ==, !=, <, >, <=, >= come from the string implementations. + + template + inline void swap(fixed_string& a, + fixed_string& b) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(a, b); + } + + +} // namespace eastl + + + +#endif // Header include guard + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/bonus/intrusive_sdlist.h b/libs/eastl/include/EASTL/bonus/intrusive_sdlist.h new file mode 100644 index 0000000..67851f5 --- /dev/null +++ b/libs/eastl/include/EASTL/bonus/intrusive_sdlist.h @@ -0,0 +1,694 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// intrusive_sdlist is a special kind of intrusive list which we say is +// "singly-doubly" linked. Instead of having a typical intrusive list node +// which looks like this: +// +// struct intrusive_sdlist_node { +// intrusive_sdlist_node *mpNext; +// intrusive_sdlist_node *mpPrev; +// }; +// +// We instead have one that looks like this: +// +// struct intrusive_sdlist_node { +// intrusive_sdlist_node* mpNext; +// intrusive_sdlist_node** mppPrevNext; +// }; +// +// This may seem to be suboptimal, but it has one specific advantage: it allows +// the intrusive_sdlist class to be the size of only one pointer instead of two. +// This may seem like a minor optimization, but some users have wanted to create +// thousands of empty instances of these. +// This is because while an intrusive_list class looks like this: +// +// class intrusive_list { +// intrusive_list_node mBaseNode; +// }; +// +// an intrusive_sdlist class looks like this: +// +// class intrusive_sdlist { +// intrusive_sdlist_node* mpNext; +// }; +// +// So here we make a list of plusses and minuses of intrusive sdlists +// compared to intrusive_lists and intrusive_slists: +// +// | list | slist | sdlist +// --------------------------------------------------------- +// min size | 8 | 4 | 4 +// node size | 8 | 4 | 8 +// anonymous erase | yes | no | yes +// reverse iteration | yes | no | no +// +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTRUSIVE_SDLIST_H +#define EASTL_INTRUSIVE_SDLIST_H + + +#include +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + + /// intrusive_sdlist_node + /// + struct intrusive_sdlist_node + { + intrusive_sdlist_node* mpNext; + intrusive_sdlist_node** mppPrevNext; + }; + + + /// IntrusiveSDListIterator + /// + template + struct IntrusiveSDListIterator + { + typedef IntrusiveSDListIterator this_type; + typedef IntrusiveSDListIterator iterator; + typedef IntrusiveSDListIterator const_iterator; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T node_type; + typedef Pointer pointer; + typedef Reference reference; + typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; + + public: + pointer mpNode; + + public: + IntrusiveSDListIterator(); + explicit IntrusiveSDListIterator(pointer pNode); // Note that you can also construct an iterator from T via this, since value_type == node_type. + IntrusiveSDListIterator(const iterator& x); + + reference operator*() const; + pointer operator->() const; + + this_type& operator++(); + this_type operator++(int); + + }; // struct IntrusiveSDListIterator + + + + + /// intrusive_sdlist_base + /// + /// Provides a template-less base class for intrusive_sdlist. + /// + class intrusive_sdlist_base + { + public: + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + + protected: + intrusive_sdlist_node* mpNext; + + public: + intrusive_sdlist_base(); + + bool empty() const; ///< Returns true if the container is empty. + size_type size() const; ///< Returns the number of elements in the list; O(n). + + void clear(); ///< Clears the list; O(1). No deallocation occurs. + void pop_front(); ///< Removes an element from the front of the list; O(1). The element must be present, but is not deallocated. + void reverse(); ///< Reverses a list so that front and back are swapped; O(n). + + //bool validate() const; ///< Scans a list for linkage inconsistencies; O(n) time, O(1) space. Returns false if errors are detected, such as loops or branching. + + }; // class intrusive_sdlist_base + + + + /// intrusive_sdlist + /// + template + class intrusive_sdlist : public intrusive_sdlist_base + { + public: + typedef intrusive_sdlist this_type; + typedef intrusive_sdlist_base base_type; + typedef T node_type; + typedef T value_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef IntrusiveSDListIterator iterator; + typedef IntrusiveSDListIterator const_iterator; + typedef eastl::reverse_iterator reverse_iterator; + typedef eastl::reverse_iterator const_reverse_iterator; + + public: + intrusive_sdlist(); ///< Creates an empty list. + intrusive_sdlist(const this_type& x); ///< Creates an empty list; ignores the argument. + this_type& operator=(const this_type& x); ///< Clears the list; ignores the argument. + + iterator begin(); ///< Returns an iterator pointing to the first element in the list. + const_iterator begin() const; ///< Returns a const_iterator pointing to the first element in the list. + const_iterator cbegin() const; ///< Returns a const_iterator pointing to the first element in the list. + + iterator end(); ///< Returns an iterator pointing one-after the last element in the list. + const_iterator end() const; ///< Returns a const_iterator pointing one-after the last element in the list. + const_iterator cend() const; ///< Returns a const_iterator pointing one-after the last element in the list. + + reference front(); ///< Returns a reference to the first element. The list must be empty. + const_reference front() const; ///< Returns a const reference to the first element. The list must be empty. + + void push_front(value_type& value); ///< Adds an element to the front of the list; O(1). The element is not copied. The element must not be in any other list. + void push_back(value_type& value); ///< Adds an element to the back of the list; O(N). The element is not copied. The element must not be in any other list. + void pop_back(); ///< Removes an element from the back of the list; O(N). The element must be present, but is not deallocated. + + bool contains(const value_type& value) const; ///< Returns true if the given element is in the list; O(n). Equivalent to (locate(x) != end()). + + iterator locate(value_type& value); ///< Converts a reference to an object in the list back to an iterator, or returns end() if it is not part of the list. O(n) + const_iterator locate(const value_type& value) const; ///< Converts a const reference to an object in the list back to a const iterator, or returns end() if it is not part of the list. O(n) + + iterator insert(iterator position, value_type& value); ///< Inserts an element before the element pointed to by the iterator. O(1) + iterator erase(iterator position); ///< Erases the element pointed to by the iterator. O(1) + iterator erase(iterator first, iterator last); ///< Erases elements within the iterator range [first, last). O(1). + void swap(intrusive_sdlist& x); ///< Swaps the contents of two intrusive lists; O(1). + + static void remove(value_type& value); ///< Erases an element from a list; O(1). Note that this is static so you don't need to know which list the element, although it must be in some list. + + void splice(iterator position, value_type& value); ///< Moves the given element into this list before the element pointed to by position; O(1). + ///< Required: x must be in some list or have first/next pointers that point it itself. + + void splice(iterator position, this_type& x); ///< Moves the contents of a list into this list before the element pointed to by position; O(1). + ///< Required: &x != this (same as std::list). + + void splice(iterator position, this_type& x, iterator xPosition); ///< Moves the given element pointed to i within the list x into the current list before + ///< the element pointed to by position; O(1). + + void splice(iterator position, this_type& x, iterator first, iterator last); ///< Moves the range of elements [first, last) from list x into the current list before + ///< the element pointed to by position; O(1). + ///< Required: position must not be in [first, last). (same as std::list). + bool validate() const; + int validate_iterator(const_iterator i) const; + + }; // intrusive_sdlist + + + + + /////////////////////////////////////////////////////////////////////// + // IntrusiveSDListIterator functions + /////////////////////////////////////////////////////////////////////// + + template + inline IntrusiveSDListIterator::IntrusiveSDListIterator() + { + #if EASTL_DEBUG + mpNode = NULL; + #endif + } + + template + inline IntrusiveSDListIterator::IntrusiveSDListIterator(pointer pNode) + : mpNode(pNode) + { + } + + template + inline IntrusiveSDListIterator::IntrusiveSDListIterator(const iterator& x) + : mpNode(x.mpNode) + { + } + + template + inline typename IntrusiveSDListIterator::reference + IntrusiveSDListIterator::operator*() const + { + return *mpNode; + } + + template + inline typename IntrusiveSDListIterator::pointer + IntrusiveSDListIterator::operator->() const + { + return mpNode; + } + + template + inline typename IntrusiveSDListIterator::this_type& + IntrusiveSDListIterator::operator++() + { + mpNode = static_cast(mpNode->mpNext); + return *this; + } + + template + inline typename IntrusiveSDListIterator::this_type + IntrusiveSDListIterator::operator++(int) + { + this_type temp = *this; + mpNode = static_cast(mpNode->mpNext); + return temp; + } + + // The C++ defect report #179 requires that we support comparisons between const and non-const iterators. + // Thus we provide additional template paremeters here to support this. The defect report does not + // require us to support comparisons between reverse_iterators and const_reverse_iterators. + template + inline bool operator==(const IntrusiveSDListIterator& a, + const IntrusiveSDListIterator& b) + { + return a.mpNode == b.mpNode; + } + + + template + inline bool operator!=(const IntrusiveSDListIterator& a, + const IntrusiveSDListIterator& b) + { + return a.mpNode != b.mpNode; + } + + + // We provide a version of operator!= for the case where the iterators are of the + // same type. This helps prevent ambiguity errors in the presence of rel_ops. + template + inline bool operator!=(const IntrusiveSDListIterator& a, + const IntrusiveSDListIterator& b) + { + return a.mpNode != b.mpNode; + } + + + + /////////////////////////////////////////////////////////////////////// + // intrusive_sdlist_base + /////////////////////////////////////////////////////////////////////// + + inline intrusive_sdlist_base::intrusive_sdlist_base() + { mpNext = NULL; } + + + inline bool intrusive_sdlist_base::empty() const + { return mpNext == NULL; } + + + inline intrusive_sdlist_base::size_type intrusive_sdlist_base::size() const + { + size_type n = 0; + for(const intrusive_sdlist_node* pCurrent = mpNext; pCurrent; pCurrent = pCurrent->mpNext) + n++; + return n; + } + + + inline void intrusive_sdlist_base::clear() + { mpNext = NULL; } // Note that we don't do anything with the list nodes. + + + inline void intrusive_sdlist_base::pop_front() + { + // To consider: Set mpNext's pointers to NULL in debug builds. + mpNext = mpNext->mpNext; + mpNext->mppPrevNext = &mpNext; + } + + + + /////////////////////////////////////////////////////////////////////// + // intrusive_sdlist + /////////////////////////////////////////////////////////////////////// + + template + inline intrusive_sdlist::intrusive_sdlist() + { + } + + + template + inline intrusive_sdlist::intrusive_sdlist(const this_type& /*x*/) + : intrusive_sdlist_base() + { + // We intentionally ignore argument x. + } + + + template + inline typename intrusive_sdlist::this_type& intrusive_sdlist::operator=(const this_type& /*x*/) + { + return *this; // We intentionally ignore argument x. + } + + + template + inline typename intrusive_sdlist::iterator intrusive_sdlist::begin() + { return iterator(static_cast(mpNext)); } + + + template + inline typename intrusive_sdlist::const_iterator intrusive_sdlist::begin() const + { return const_iterator(static_cast(const_cast(mpNext))); } + + + template + inline typename intrusive_sdlist::const_iterator intrusive_sdlist::cbegin() const + { return const_iterator(static_cast(const_cast(mpNext))); } + + + template + inline typename intrusive_sdlist::iterator intrusive_sdlist::end() + { return iterator(static_cast(NULL)); } + + + template + inline typename intrusive_sdlist::const_iterator intrusive_sdlist::end() const + { return const_iterator(static_cast(NULL)); } + + + template + inline typename intrusive_sdlist::const_iterator intrusive_sdlist::cend() const + { return const_iterator(static_cast(NULL)); } + + + template + inline typename intrusive_sdlist::reference intrusive_sdlist::front() + { return *static_cast(mpNext); } + + + template + inline typename intrusive_sdlist::const_reference intrusive_sdlist::front() const + { return *static_cast(mpNext); } + + + template + inline void intrusive_sdlist::push_front(value_type& value) + { + value.mpNext = mpNext; + value.mppPrevNext = &mpNext; + if(mpNext) + mpNext->mppPrevNext = &value.mpNext; + mpNext = &value; + } + + + template + inline void intrusive_sdlist::push_back(value_type& value) + { + intrusive_sdlist_node* pNext = mpNext; + intrusive_sdlist_node** ppPrevNext = &mpNext; + + while(pNext) + { + ppPrevNext = &pNext->mpNext; + pNext = pNext->mpNext; + } + + *ppPrevNext = &value; + value.mppPrevNext = ppPrevNext; + value.mpNext = NULL; + } + + + template + inline void intrusive_sdlist::pop_back() + { + node_type* pCurrent = static_cast(mpNext); + + while(pCurrent->mpNext) + pCurrent = static_cast(pCurrent->mpNext); + + *pCurrent->mppPrevNext = NULL; + } + + template + inline bool intrusive_sdlist::contains(const value_type& value) const + { + const intrusive_sdlist_node* pCurrent; + + for(pCurrent = mpNext; pCurrent; pCurrent = pCurrent->mpNext) + { + if(pCurrent == &value) + break; + } + + return (pCurrent != NULL); + } + + + template + inline typename intrusive_sdlist::iterator intrusive_sdlist::locate(value_type& value) + { + intrusive_sdlist_node* pCurrent; + + for(pCurrent = static_cast(mpNext); pCurrent; pCurrent = pCurrent->mpNext) + { + if(pCurrent == &value) + break; + } + + return iterator(static_cast(pCurrent)); + } + + + template + inline typename intrusive_sdlist::const_iterator intrusive_sdlist::locate(const T& value) const + { + const intrusive_sdlist_node* pCurrent; + + for(pCurrent = static_cast(mpNext); pCurrent; pCurrent = pCurrent->mpNext) + { + if(pCurrent == &value) + break; + } + + return const_iterator(static_cast(const_cast(pCurrent))); + } + + + template + inline typename intrusive_sdlist::iterator + intrusive_sdlist::insert(iterator position, value_type& value) + { + value.mppPrevNext = position.mpNode->mppPrevNext; + value.mpNext = position.mpNode; + *value.mppPrevNext = &value; + position.mpNode->mppPrevNext = &value.mpNext; + + return iterator(&value); + } + + + template + inline typename intrusive_sdlist::iterator + intrusive_sdlist::erase(iterator position) + { + *position.mpNode->mppPrevNext = position.mpNode->mpNext; + position.mpNode->mpNext->mppPrevNext = position.mpNode->mppPrevNext; + + return iterator(position.mpNode); + } + + + template + inline typename intrusive_sdlist::iterator + intrusive_sdlist::erase(iterator first, iterator last) + { + if(first.mpNode) // If not erasing the end... + { + *first.mpNode->mppPrevNext = last.mpNode; + + if(last.mpNode) // If not erasing to the end... + last.mpNode->mppPrevNext = first.mpNode->mppPrevNext; + } + + return last; + } + + + template + inline void intrusive_sdlist::remove(value_type& value) + { + *value.mppPrevNext = value.mpNext; + if(value.mpNext) + value.mpNext->mppPrevNext = value.mppPrevNext; + } + + + template + void intrusive_sdlist::swap(intrusive_sdlist& x) + { + // swap anchors + intrusive_sdlist_node* const temp(mpNext); + mpNext = x.mpNext; + x.mpNext = temp; + + if(x.mpNext) + x.mpNext->mppPrevNext = &mpNext; + + if(mpNext) + mpNext->mppPrevNext = &x.mpNext; + } + + + + + + // To do: Complete these splice functions. Might want to look at intrusive_sdlist for help. + + template + void intrusive_sdlist::splice(iterator /*position*/, value_type& /*value*/) + { + EASTL_ASSERT(false); // If you need this working, ask Paul Pedriana or submit a working version for inclusion. + } + + + template + void intrusive_sdlist::splice(iterator /*position*/, intrusive_sdlist& /*x*/) + { + EASTL_ASSERT(false); // If you need this working, ask Paul Pedriana or submit a working version for inclusion. + } + + + template + void intrusive_sdlist::splice(iterator /*position*/, intrusive_sdlist& /*x*/, iterator /*xPosition*/) + { + EASTL_ASSERT(false); // If you need this working, ask Paul Pedriana or submit a working version for inclusion. + } + + + template + void intrusive_sdlist::splice(iterator /*position*/, intrusive_sdlist& /*x*/, iterator /*first*/, iterator /*last*/) + { + EASTL_ASSERT(false); // If you need this working, ask Paul Pedriana or submit a working version for inclusion. + } + + + template + inline bool intrusive_sdlist::validate() const + { + return true; // To do. + } + + + template + inline int intrusive_sdlist::validate_iterator(const_iterator i) const + { + // To do: Come up with a more efficient mechanism of doing this. + + for(const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp) + { + if(temp == i) + return (isf_valid | isf_current | isf_can_dereference); + } + + if(i == end()) + return (isf_valid | isf_current); + + return isf_none; + } + + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + bool operator==(const intrusive_sdlist& a, const intrusive_sdlist& b) + { + // If we store an mSize member for intrusive_sdlist, we want to take advantage of it here. + typename intrusive_sdlist::const_iterator ia = a.begin(); + typename intrusive_sdlist::const_iterator ib = b.begin(); + typename intrusive_sdlist::const_iterator enda = a.end(); + typename intrusive_sdlist::const_iterator endb = b.end(); + + while((ia != enda) && (ib != endb) && (*ia == *ib)) + { + ++ia; + ++ib; + } + return (ia == enda) && (ib == endb); + } + + template + bool operator<(const intrusive_sdlist& a, const intrusive_sdlist& b) + { + return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); + } + + template + bool operator!=(const intrusive_sdlist& a, const intrusive_sdlist& b) + { + return !(a == b); + } + + template + bool operator>(const intrusive_sdlist& a, const intrusive_sdlist& b) + { + return b < a; + } + + template + bool operator<=(const intrusive_sdlist& a, const intrusive_sdlist& b) + { + return !(b < a); + } + + template + bool operator>=(const intrusive_sdlist& a, const intrusive_sdlist& b) + { + return !(a < b); + } + + template + void swap(intrusive_sdlist& a, intrusive_sdlist& b) + { + a.swap(b); + } + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/bonus/intrusive_slist.h b/libs/eastl/include/EASTL/bonus/intrusive_slist.h new file mode 100644 index 0000000..a03a031 --- /dev/null +++ b/libs/eastl/include/EASTL/bonus/intrusive_slist.h @@ -0,0 +1,321 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// *** Note *** +// This implementation is incomplete. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTRUSIVE_SLIST_H +#define EASTL_INTRUSIVE_SLIST_H + + +#include +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// intrusive_slist_node + /// + struct intrusive_slist_node + { + intrusive_slist_node* mpNext; + }; + + + /// IntrusiveSListIterator + /// + template + struct IntrusiveSListIterator + { + typedef IntrusiveSListIterator this_type; + typedef IntrusiveSListIterator iterator; + typedef IntrusiveSListIterator const_iterator; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T node_type; + typedef Pointer pointer; + typedef Reference reference; + typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; + + public: + node_type* mpNode; + + public: + IntrusiveSListIterator(); + explicit IntrusiveSListIterator(pointer pNode); // Note that you can also construct an iterator from T via this, since value_type == node_type. + IntrusiveSListIterator(const iterator& x); + + reference operator*() const; + pointer operator->() const; + + this_type& operator++(); + this_type operator++(int); + + }; // struct IntrusiveSListIterator + + + + /// intrusive_slist_base + /// + /// Provides a template-less base class for intrusive_slist. + /// + class intrusive_slist_base + { + public: + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + + protected: + intrusive_slist_node* mpNext; + + public: + intrusive_slist_base(); + + bool empty() const; ///< Returns true if the container is empty. + size_type size() const; ///< Returns the number of elements in the list; O(n). + + void clear(); ///< Clears the list; O(1). No deallocation occurs. + void pop_front(); ///< Removes an element from the front of the list; O(1). The element must be present, but is not deallocated. + void reverse(); ///< Reverses a list so that front and back are swapped; O(n). + + //bool validate() const; ///< Scans a list for linkage inconsistencies; O(n) time, O(1) space. Returns false if errors are detected, such as loops or branching. + + }; // class intrusive_slist_base + + + + /// intrusive_slist + /// + template + class intrusive_slist : public intrusive_slist_base + { + public: + typedef intrusive_slist this_type; + typedef intrusive_slist_base base_type; + typedef T node_type; + typedef T value_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef IntrusiveSListIterator iterator; + typedef IntrusiveSListIterator const_iterator; + + public: + intrusive_slist(); ///< Creates an empty list. + //intrusive_slist(const this_type& x); ///< Creates an empty list; ignores the argument. To consider: Is this a useful function? + //this_type& operator=(const this_type& x); ///< Clears the list; ignores the argument. To consider: Is this a useful function? + + iterator begin(); ///< Returns an iterator pointing to the first element in the list. O(1). + const_iterator begin() const; ///< Returns a const_iterator pointing to the first element in the list. O(1). + const_iterator cbegin() const; ///< Returns a const_iterator pointing to the first element in the list. O(1). + iterator end(); ///< Returns an iterator pointing one-after the last element in the list. O(1). + const_iterator end() const; ///< Returns a const_iterator pointing one-after the last element in the list. O(1). + const_iterator cend() const; ///< Returns a const_iterator pointing one-after the last element in the list. O(1). + iterator before_begin(); ///< Returns iterator to position before begin. O(1). + const_iterator before_begin() const; ///< Returns iterator to previous position. O(1). + const_iterator cbefore_begin() const; ///< Returns iterator to previous position. O(1). + + iterator previous(const_iterator position); ///< Returns iterator to previous position. O(n). + const_iterator previous(const_iterator position) const; ///< Returns iterator to previous position. O(n). + + reference front(); ///< Returns a reference to the first element. The list must be empty. + const_reference front() const; ///< Returns a const reference to the first element. The list must be empty. + + void push_front(value_type& value); ///< Adds an element to the front of the list; O(1). The element is not copied. The element must not be in any other list. + void pop_front(); ///< Removes an element from the back of the list; O(n). The element must be present, but is not deallocated. + + bool contains(const value_type& value) const; ///< Returns true if the given element is in the list; O(n). Equivalent to (locate(x) != end()). + + iterator locate(value_type& value); ///< Converts a reference to an object in the list back to an iterator, or returns end() if it is not part of the list. O(n) + const_iterator locate(const value_type& value) const; ///< Converts a const reference to an object in the list back to a const iterator, or returns end() if it is not part of the list. O(n) + + iterator insert(iterator position, value_type& value); ///< Inserts an element before the element pointed to by the iterator. O(n) + iterator insert_after(iterator position, value_type& value); ///< Inserts an element after the element pointed to by the iterator. O(1) + + iterator erase(iterator position); ///< Erases the element pointed to by the iterator. O(n) + iterator erase_after(iterator position); ///< Erases the element after the element pointed to by the iterator. O(1) + + iterator erase(iterator first, iterator last); ///< Erases elements within the iterator range [first, last). O(n). + iterator erase_after(iterator before_first, iterator last); ///< Erases elements within the iterator range [before_first, last). O(1). + + void swap(this_type& x); ///< Swaps the contents of two intrusive lists; O(1). + + + void splice(iterator position, value_type& value); ///< Moves the given element into this list before the element pointed to by position; O(n). + ///< Required: x must be in some list or have first/next pointers that point it itself. + + void splice(iterator position, this_type& x); ///< Moves the contents of a list into this list before the element pointed to by position; O(n). + ///< Required: &x != this (same as std::list). + + void splice(iterator position, this_type& x, iterator xPosition); ///< Moves the given element pointed to i within the list x into the current list before + ///< the element pointed to by position; O(n). + + void splice(iterator position, this_type& x, iterator first, iterator last); ///< Moves the range of elements [first, last) from list x into the current list before + ///< the element pointed to by position; O(n). + ///< Required: position must not be in [first, last). (same as std::list). + + void splice_after(iterator position, value_type& value); ///< Moves the given element into this list after the element pointed to by position; O(1). + ///< Required: x must be in some list or have first/next pointers that point it itself. + + void splice_after(iterator position, this_type& x); ///< Moves the contents of a list into this list after the element pointed to by position; O(n). + ///< Required: &x != this (same as std::list). + + void splice_after(iterator position, this_type& x, iterator xPrevious); ///< Moves the element after xPrevious to be after position. O(1). + ///< Required: &x != this (same as std::list). + + void splice_after(iterator position, this_type& x, iterator before_first, iterator before_last); ///< Moves the elements in the range of [before_first+1, before_last+1) to be after position. O(1). + + bool validate() const; + int validate_iterator(const_iterator i) const; + + }; // intrusive_slist + + + + + /////////////////////////////////////////////////////////////////////// + // IntrusiveSListIterator + /////////////////////////////////////////////////////////////////////// + + template + inline IntrusiveSListIterator::IntrusiveSListIterator() + { + #if EASTL_DEBUG + mpNode = NULL; + #endif + } + + template + inline IntrusiveSListIterator::IntrusiveSListIterator(pointer pNode) + : mpNode(pNode) + { + } + + template + inline IntrusiveSListIterator::IntrusiveSListIterator(const iterator& x) + : mpNode(x.mpNode) + { + } + + + /////////////////////////////////////////////////////////////////////// + // intrusive_slist_base + /////////////////////////////////////////////////////////////////////// + + // To do. + + + /////////////////////////////////////////////////////////////////////// + // intrusive_slist + /////////////////////////////////////////////////////////////////////// + + // To do. + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + bool operator==(const intrusive_slist& a, const intrusive_slist& b) + { + // If we store an mSize member for intrusive_slist, we want to take advantage of it here. + typename intrusive_slist::const_iterator ia = a.begin(); + typename intrusive_slist::const_iterator ib = b.begin(); + typename intrusive_slist::const_iterator enda = a.end(); + typename intrusive_slist::const_iterator endb = b.end(); + + while((ia != enda) && (ib != endb) && (*ia == *ib)) + { + ++ia; + ++ib; + } + return (ia == enda) && (ib == endb); + } + + template + bool operator<(const intrusive_slist& a, const intrusive_slist& b) + { + return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); + } + + template + bool operator!=(const intrusive_slist& a, const intrusive_slist& b) + { + return !(a == b); + } + + template + bool operator>(const intrusive_slist& a, const intrusive_slist& b) + { + return b < a; + } + + template + bool operator<=(const intrusive_slist& a, const intrusive_slist& b) + { + return !(b < a); + } + + template + bool operator>=(const intrusive_slist& a, const intrusive_slist& b) + { + return !(a < b); + } + + template + void swap(intrusive_slist& a, intrusive_slist& b) + { + a.swap(b); + } + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/bonus/list_map.h b/libs/eastl/include/EASTL/bonus/list_map.h new file mode 100644 index 0000000..1a07a60 --- /dev/null +++ b/libs/eastl/include/EASTL/bonus/list_map.h @@ -0,0 +1,937 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_LIST_MAP_H +#define EASTL_LIST_MAP_H + + +#include + + +namespace eastl +{ + + /// EASTL_MAP_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_LIST_MAP_DEFAULT_NAME + #define EASTL_LIST_MAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " list_map" // Unless the user overrides something, this is "EASTL list_map". + #endif + + /// EASTL_MAP_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_LIST_MAP_DEFAULT_ALLOCATOR + #define EASTL_LIST_MAP_DEFAULT_ALLOCATOR allocator_type(EASTL_LIST_MAP_DEFAULT_NAME) + #endif + + + /// list_map_data_base + /// + /// We define a list_map_data_base separately from list_map_data (below), because it + /// allows us to have non-templated operations, and it makes it so that the + /// list_map anchor node doesn't carry a T with it, which would waste space and + /// possibly lead to surprising the user due to extra Ts existing that the user + /// didn't explicitly create. The downside to all of this is that it makes debug + /// viewing of an list_map harder, given that the node pointers are of type + /// list_map_data_base and not list_map_data. + /// + struct list_map_data_base + { + list_map_data_base* mpNext; + list_map_data_base* mpPrev; + }; + + + /// list_map_data + /// + template + struct list_map_data : public list_map_data_base + { + typedef Value value_type; + + list_map_data(const value_type& value); + + value_type mValue; // This is a pair of key/value. + }; + + + /// list_map_iterator + /// + template + struct list_map_iterator + { + typedef list_map_iterator this_type; + typedef list_map_iterator iterator; + typedef list_map_iterator const_iterator; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef list_map_data_base base_node_type; + typedef list_map_data node_type; + typedef Pointer pointer; + typedef Reference reference; + typedef EASTL_ITC_NS::bidirectional_iterator_tag iterator_category; + + public: + node_type* mpNode; + + public: + list_map_iterator(); + list_map_iterator(const base_node_type* pNode); + list_map_iterator(const iterator& x); + + reference operator*() const; + pointer operator->() const; + + this_type& operator++(); + this_type operator++(int); + + this_type& operator--(); + this_type operator--(int); + + }; // list_map_iterator + + + /// use_value_first + /// + /// operator()(x) simply returns x.mValue.first. Used in list_map. + /// This is similar to eastl::use_first, however it assumes that the input type is an object + /// whose mValue is an eastl::pair, and the first value in the pair is the desired return. + /// + template + struct use_value_first + { + typedef Object argument_type; + typedef typename Object::value_type::first_type result_type; + + const result_type& operator()(const Object& x) const + { return x.mValue.first; } + }; + + + /// list_map + /// + /// Implements a map like container, which also provides functionality similar to a list. + /// + /// Note: Like a map, keys must still be unique. As such, push_back() and push_front() operations + /// return a bool indicating success, or failure if the entry's key is already in use. + /// + /// list_map is designed to improve performance for situations commonly implemented as: + /// A map, which must be iterated over to find the oldest entry, or purge expired entries. + /// A list, which must be iterated over to remove a player's record when they sign off. + /// + /// list_map requires a little more memory per node than either a list or map alone, + /// and many of list_map's functions have a higher operational cost (CPU time) than their + /// counterparts in list and map. However, as the node count increases, list_map quickly outperforms + /// either a list or a map when find [by-index] and front/back type operations are required. + /// + /// In essence, list_map avoids O(n) iterations at the expense of additional costs to quick (O(1) and O(log n) operations: + /// push_front(), push_back(), pop_front() and pop_back() have O(log n) operation time, similar to map::insert(), rather than O(1) time like a list, + /// however, front() and back() maintain O(1) operation time. + /// + /// As a canonical example, consider a large backlog of player group invites, which are removed when either: + /// The invitation times out - in main loop: while( !listMap.empty() && listMap.front().IsExpired() ) { listMap.pop_front(); } + /// The player rejects the outstanding invitation - on rejection: iter = listMap.find(playerId); if (iter != listMap.end()) { listMap.erase(iter); } + /// + /// For a similar example, consider a high volume pending request container which must: + /// Time out old requests (similar to invites timing out above) + /// Remove requests once they've been handled (similar to rejecting invites above) + /// + /// For such usage patterns, the performance benefits of list_map become dramatic with + /// common O(n) operations once the node count rises to hundreds or more. + /// + /// When high performance is a priority, Containers with thousands of nodes or more + /// can quickly result in unacceptable performance when executing even infrequenty O(n) operations. + /// + /// In order to maintain strong performance, avoid iterating over list_map whenever possible. + /// + /////////////////////////////////////////////////////////////////////// + /// find_as + /// In order to support the ability to have a tree of strings but + /// be able to do efficiently lookups via char pointers (i.e. so they + /// aren't converted to string objects), we provide the find_as + /// function. This function allows you to do a find with a key of a + /// type other than the tree's key type. See the find_as function + /// for more documentation on this. + /// + /////////////////////////////////////////////////////////////////////// + /// Pool allocation + /// If you want to make a custom memory pool for a list_map container, your pool + /// needs to contain items of type list_map::node_type. So if you have a memory + /// pool that has a constructor that takes the size of pool items and the + /// count of pool items, you would do this (assuming that MemoryPool implements + /// the Allocator interface): + /// typedef list_map, MemoryPool> WidgetMap; // Delare your WidgetMap type. + /// MemoryPool myPool(sizeof(WidgetMap::node_type), 100); // Make a pool of 100 Widget nodes. + /// WidgetMap myMap(&myPool); // Create a map that uses the pool. + /// + template , typename Allocator = EASTLAllocatorType> + class list_map + : protected rbtree >, Compare, Allocator, eastl::use_value_first > >, true, true> + { + public: + typedef rbtree >, Compare, Allocator, + eastl::use_value_first > >, true, true> base_type; + typedef list_map this_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::key_type key_type; + typedef T mapped_type; + typedef typename eastl::pair value_type; // This is intentionally different from base_type::value_type + typedef value_type& reference; + typedef const value_type& const_reference; + typedef typename base_type::node_type node_type; // Despite the internal and external values being different, we're keeping the node type the same as the base + // in order to allow for pool allocation. See EASTL/map.h for more information. + typedef typename eastl::list_map_iterator iterator; // This is intentionally different from base_type::iterator + typedef typename eastl::list_map_iterator const_iterator; // This is intentionally different from base_type::const_iterator + typedef eastl::reverse_iterator reverse_iterator; + typedef eastl::reverse_iterator const_reverse_iterator; + typedef typename base_type::allocator_type allocator_type; + typedef typename eastl::pair insert_return_type; // This is intentionally removed, as list_map doesn't support insert() functions, in favor of list like push_back and push_front + typedef typename eastl::use_first extract_key; // This is intentionally different from base_type::extract_key + + using base_type::get_allocator; + using base_type::set_allocator; + using base_type::key_comp; + using base_type::empty; + using base_type::size; + + protected: + typedef typename eastl::list_map_data > internal_value_type; + + protected: + // internal base node, acting as the sentinel for list like behaviors + list_map_data_base mNode; + + public: + list_map(const allocator_type& allocator = EASTL_LIST_MAP_DEFAULT_ALLOCATOR); + list_map(const Compare& compare, const allocator_type& allocator = EASTL_MAP_DEFAULT_ALLOCATOR); + + // To do: Implement the following: + + //list_map(const this_type& x); + //#if EASTL_MOVE_SEMANTICS_ENABLED + // list_map(this_type&& x); + // list_map(this_type&& x, const allocator_type& allocator); + //#endif + //list_map(std::initializer_list ilist, const Compare& compare = Compare(), const allocator_type& allocator = EASTL_LIST_MAP_DEFAULT_ALLOCATOR); + + //template + //list_map(Iterator itBegin, Iterator itEnd); + + //this_type& operator=(const this_type& x); + //this_type& operator=(std::initializer_list ilist); + + //#if EASTL_MOVE_SEMANTICS_ENABLED + // this_type& operator=(this_type&& x); + //#endif + + //void swap(this_type& x); + + public: + // iterators + iterator begin() EA_NOEXCEPT; + const_iterator begin() const EA_NOEXCEPT; + const_iterator cbegin() const EA_NOEXCEPT; + + iterator end() EA_NOEXCEPT; + const_iterator end() const EA_NOEXCEPT; + const_iterator cend() const EA_NOEXCEPT; + + reverse_iterator rbegin() EA_NOEXCEPT; + const_reverse_iterator rbegin() const EA_NOEXCEPT; + const_reverse_iterator crbegin() const EA_NOEXCEPT; + + reverse_iterator rend() EA_NOEXCEPT; + const_reverse_iterator rend() const EA_NOEXCEPT; + const_reverse_iterator crend() const EA_NOEXCEPT; + + public: + // List like methods + reference front(); + const_reference front() const; + + reference back(); + const_reference back() const; + + // push_front and push_back which takes in a key/value pair + bool push_front(const value_type& value); + bool push_back(const value_type& value); + + // push_front and push_back which take key and value separately, for convenience + bool push_front(const key_type& key, const mapped_type& value); + bool push_back(const key_type& key, const mapped_type& value); + + void pop_front(); + void pop_back(); + + public: + // Map like methods + iterator find(const key_type& key); + const_iterator find(const key_type& key) const; + + template + iterator find_as(const U& u, Compare2 compare2); + template + const_iterator find_as(const U& u, Compare2 compare2) const; + + size_type count(const key_type& key) const; + size_type erase(const key_type& key); + + public: + // Shared methods which are common to list and map + iterator erase(const_iterator position); + reverse_iterator erase(const_reverse_iterator position); + + void clear(); + void reset_lose_memory(); + + bool validate() const; + int validate_iterator(const_iterator i) const; + + public: + // list like functionality which is in consideration for implementation: + // iterator insert(const_iterator position, const value_type& value); + // void remove(const mapped_type& x); + + public: + // list like functionality which may be implemented, but is discouraged from implementation: + // due to the liklihood that they would require O(n) time to execute. + // template + // void remove_if(Predicate); + // void reverse(); + // void sort(); + // template + // void sort(Compare compare); + + public: + // map like functionality which list_map does not support, due to abmiguity with list like functionality: + #if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) + template + list_map(InputIterator first, InputIterator last, const Compare& compare, const allocator_type& allocator = EASTL_RBTREE_DEFAULT_ALLOCATOR) = delete; + + insert_return_type insert(const value_type& value) = delete; + iterator insert(const_iterator position, const value_type& value) = delete; + + template + void insert(InputIterator first, InputIterator last) = delete; + + insert_return_type insert(const key_type& key) = delete; + + iterator erase(const_iterator first, const_iterator last) = delete; + reverse_iterator erase(reverse_iterator first, reverse_iterator last) = delete; + + void erase(const key_type* first, const key_type* last) = delete; + + iterator lower_bound(const key_type& key) = delete; + const_iterator lower_bound(const key_type& key) const = delete; + + iterator upper_bound(const key_type& key) = delete; + const_iterator upper_bound(const key_type& key) const = delete; + + eastl::pair equal_range(const key_type& key) = delete; + eastl::pair equal_range(const key_type& key) const = delete; + + mapped_type& operator[](const key_type& key) = delete; // Of map, multimap, set, and multimap, only map has operator[]. + #endif + + public: + // list like functionality which list_map does not support, due to ambiguity with map like functionality: + #if 0 + reference push_front() = delete; + void* push_front_uninitialized() = delete; + + reference push_back() = delete; + void* push_back_uninitialized() = delete; + + iterator insert(const_iterator position) = delete; + + void insert(const_iterator position, size_type n, const value_type& value) = delete; + + template + void insert(const_iterator position, InputIterator first, InputIterator last) = delete; + + iterator erase(const_iterator first, const_iterator last) = delete; + reverse_iterator erase(const_reverse_iterator first, const_reverse_iterator last) = delete; + + void splice(const_iterator position, this_type& x) = delete + void splice(const_iterator position, this_type& x, const_iterator i) = delete; + void splice(const_iterator position, this_type& x, const_iterator first, const_iterator last) = delete; + + void merge(this_type& x) = delete; + + template + void merge(this_type& x, Compare compare) = delete; + + void unique() = delete; // Uniqueness is enforced by map functionality + + template + void unique(BinaryPredicate) = delete; // Uniqueness is enforced by map functionality + #endif + + }; // list_map + + + /////////////////////////////////////////////////////////////////////// + // list_map_data + /////////////////////////////////////////////////////////////////////// + + template + inline list_map_data::list_map_data(const Value& value) + : mValue(value) + { + mpNext = NULL; // GCC 4.8 is generating warnings about referencing these values in list_map::push_front unless we + mpPrev = NULL; // initialize them here. The compiler seems to be mistaken, as our code isn't actually using them unintialized. + } + + + /////////////////////////////////////////////////////////////////////// + // list_map_iterator + /////////////////////////////////////////////////////////////////////// + + template + inline list_map_iterator::list_map_iterator() + : mpNode(NULL) + { + // Empty + } + + + template + inline list_map_iterator::list_map_iterator(const base_node_type* pNode) + : mpNode(static_cast(const_cast(pNode))) + { + // Empty + } + + + template + inline list_map_iterator::list_map_iterator(const iterator& x) + : mpNode(const_cast(x.mpNode)) + { + // Empty + } + + + template + inline typename list_map_iterator::reference + list_map_iterator::operator*() const + { + return mpNode->mValue; + } + + + template + inline typename list_map_iterator::pointer + list_map_iterator::operator->() const + { + return &mpNode->mValue; + } + + + template + inline typename list_map_iterator::this_type& + list_map_iterator::operator++() + { + mpNode = static_cast(mpNode->mpNext); + return *this; + } + + + template + inline typename list_map_iterator::this_type + list_map_iterator::operator++(int) + { + this_type temp(*this); + mpNode = static_cast(mpNode->mpNext); + return temp; + } + + + template + inline typename list_map_iterator::this_type& + list_map_iterator::operator--() + { + mpNode = static_cast(mpNode->mpPrev); + return *this; + } + + + template + inline typename list_map_iterator::this_type + list_map_iterator::operator--(int) + { + this_type temp(*this); + mpNode = static_cast(mpNode->mpPrev); + return temp; + } + + + // We provide additional template paremeters here to support comparisons between const and non-const iterators. + // See C++ defect report #179, or EASTL/list.h for more information. + template + inline bool operator==(const list_map_iterator& a, + const list_map_iterator& b) + { + return a.mpNode == b.mpNode; + } + + + template + inline bool operator!=(const list_map_iterator& a, + const list_map_iterator& b) + { + return a.mpNode != b.mpNode; + } + + + // We provide a version of operator!= for the case where the iterators are of the + // same type. This helps prevent ambiguity errors in the presence of rel_ops. + template + inline bool operator!=(const list_map_iterator& a, + const list_map_iterator& b) + { + return a.mpNode != b.mpNode; + } + + + /////////////////////////////////////////////////////////////////////// + // list_map + /////////////////////////////////////////////////////////////////////// + + template + inline list_map::list_map(const allocator_type& allocator) + : base_type(allocator) + { + mNode.mpNext = &mNode; + mNode.mpPrev = &mNode; + } + + template + inline list_map::list_map(const Compare& compare, const allocator_type& allocator) + : base_type(compare, allocator) + { + mNode.mpNext = &mNode; + mNode.mpPrev = &mNode; + } + + template + inline typename list_map::iterator + list_map::begin() EA_NOEXCEPT + { + return iterator(mNode.mpNext); + } + + template + inline typename list_map::const_iterator + list_map::begin() const EA_NOEXCEPT + { + return const_iterator(mNode.mpNext); + } + + template + inline typename list_map::const_iterator + list_map::cbegin() const EA_NOEXCEPT + { + return const_iterator(mNode.mpNext); + } + + template + inline typename list_map::iterator + list_map::end() EA_NOEXCEPT + { + return iterator(&mNode); + } + + template + inline typename list_map::const_iterator + list_map::end() const EA_NOEXCEPT + { + return const_iterator(&mNode); + } + + template + inline typename list_map::const_iterator + list_map::cend() const EA_NOEXCEPT + { + return const_iterator(&mNode); + } + + template + inline typename list_map::reverse_iterator + list_map::rbegin() EA_NOEXCEPT + { + return reverse_iterator(&mNode); + } + + template + inline typename list_map::const_reverse_iterator + list_map::rbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(&mNode); + } + + template + inline typename list_map::const_reverse_iterator + list_map::crbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(&mNode); + } + + template + inline typename list_map::reverse_iterator + list_map::rend() EA_NOEXCEPT + { + return reverse_iterator(mNode.mpNext); + } + + template + inline typename list_map::const_reverse_iterator + list_map::rend() const EA_NOEXCEPT + { + return const_reverse_iterator(mNode.mpNext); + } + + template + inline typename list_map::const_reverse_iterator + list_map::crend() const EA_NOEXCEPT + { + return const_reverse_iterator(mNode.mpNext); + } + + template + inline typename list_map::reference + list_map::front() + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference an empty container. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(static_cast(mNode.mpNext) == &mNode)) + EASTL_FAIL_MSG("list_map::front -- empty container"); + #endif + + return static_cast(mNode.mpNext)->mValue; + } + + template + inline typename list_map::const_reference + list_map::front() const + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference an empty container. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(static_cast(mNode.mpNext) == &mNode)) + EASTL_FAIL_MSG("list_map::front -- empty container"); + #endif + + return static_cast(mNode.mpNext)->mValue; + } + + template + inline typename list_map::reference + list_map::back() + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference an empty container. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(static_cast(mNode.mpNext) == &mNode)) + EASTL_FAIL_MSG("list_map::back -- empty container"); + #endif + + return static_cast(mNode.mpPrev)->mValue; + } + + template + inline typename list_map::const_reference + list_map::back() const + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference an empty container. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(static_cast(mNode.mpNext) == &mNode)) + EASTL_FAIL_MSG("list_map::back -- empty container"); + #endif + + return static_cast(mNode.mpPrev)->mValue; + } + + template + bool list_map::push_front(const value_type& value) + { + internal_value_type tempValue(value); + typename base_type::insert_return_type baseReturn = base_type::insert(tempValue); + + // Did the insert succeed? + if (baseReturn.second) + { + internal_value_type* pNode = &(*baseReturn.first); + + pNode->mpNext = mNode.mpNext; + pNode->mpPrev = &mNode; + + mNode.mpNext->mpPrev = pNode; + mNode.mpNext = pNode; + + return true; + } + else + { + return false; + } + } + + template + bool list_map::push_back(const value_type& value) + { + internal_value_type tempValue(value); + typename base_type::insert_return_type baseReturn = base_type::insert(tempValue); + + // Did the insert succeed? + if (baseReturn.second) + { + internal_value_type* pNode = &(*baseReturn.first); + + pNode->mpPrev = mNode.mpPrev; + pNode->mpNext = &mNode; + + mNode.mpPrev->mpNext = pNode; + mNode.mpPrev = pNode; + + return true; + } + else + { + return false; + } + } + + template + bool list_map::push_front(const key_type& key, const mapped_type& value) + { + return push_front(eastl::make_pair(key, value)); + } + + template + bool list_map::push_back(const key_type& key, const mapped_type& value) + { + return push_back(eastl::make_pair(key, value)); + } + + template + void list_map::pop_front() + { + #if EASTL_ASSERT_ENABLED + if (EASTL_UNLIKELY(empty())) + EASTL_FAIL_MSG("list_map::pop_front -- empty container"); + #endif + + erase(static_cast(mNode.mpNext)->mValue.first); + } + + template + void list_map::pop_back() + { + #if EASTL_ASSERT_ENABLED + if (EASTL_UNLIKELY(empty())) + EASTL_FAIL_MSG("list_map::pop_back -- empty container"); + #endif + + erase(static_cast(mNode.mpPrev)->mValue.first); + } + + template + inline typename list_map::iterator + list_map::find(const key_type& key) + { + typename base_type::iterator baseIter = base_type::find(key); + if (baseIter != base_type::end()) + { + return iterator(&(*baseIter)); + } + else + { + return end(); + } + } + + template + inline typename list_map::const_iterator + list_map::find(const key_type& key) const + { + typename base_type::const_iterator baseIter = base_type::find(key); + if (baseIter != base_type::end()) + { + return const_iterator(&(*baseIter)); + } + else + { + return end(); + } + } + + template + template + inline typename list_map::iterator + list_map::find_as(const U& u, Compare2 compare2) + { + typename base_type::iterator baseIter = base_type::find_as(u, compare2); + if (baseIter != base_type::end()) + { + return iterator(&(*baseIter)); + } + else + { + return end(); + } + } + + template + template + inline typename list_map::const_iterator + list_map::find_as(const U& u, Compare2 compare2) const + { + typename base_type::const_iterator baseIter = base_type::find_as(u, compare2); + if (baseIter != base_type::end()) + { + return const_iterator(&(*baseIter)); + } + else + { + return end(); + } + } + + template + inline typename list_map::size_type + list_map::count(const key_type& key) const + { + const typename base_type::const_iterator it = base_type::find(key); + return (it != base_type::end()) ? 1 : 0; + } + + template + inline typename list_map::size_type + list_map::erase(const key_type& key) + { + typename base_type::iterator baseIter = base_type::find(key); + if (baseIter != base_type::end()) + { + internal_value_type* node = &(*baseIter); + + node->mpNext->mpPrev = node->mpPrev; + node->mpPrev->mpNext = node->mpNext; + + base_type::erase(baseIter); + + return 1; + } + return 0; + } + + template + inline typename list_map::iterator + list_map::erase(const_iterator position) + { + iterator posIter(position.mpNode); // Convert from const. + iterator eraseIter(posIter++); + erase(eraseIter->first); + return posIter; + } + + template + inline typename list_map::reverse_iterator + list_map::erase(const_reverse_iterator position) + { + return reverse_iterator(erase((++position).base())); + } + + template + void list_map::clear() + { + base_type::clear(); + + mNode.mpNext = &mNode; + mNode.mpPrev = &mNode; + } + + template + void list_map::reset_lose_memory() + { + base_type::reset_lose_memory(); + + mNode.mpNext = &mNode; + mNode.mpPrev = &mNode; + } + + template + bool list_map::validate() const + { + if (!base_type::validate()) + { + return false; + } + + size_type nodeCount(0); + list_map_data_base* node = mNode.mpNext; + while (node != &mNode) + { + internal_value_type* data = static_cast(node); + if (base_type::find(data->mValue.first) == base_type::end()) + { + return false; + } + node = node->mpNext; + ++nodeCount; + } + if (nodeCount != size()) + { + return false; + } + nodeCount = 0; + node = mNode.mpPrev; + while (node != &mNode) + { + internal_value_type* data = static_cast(node); + if (base_type::find(data->mValue.first) == base_type::end()) + { + return false; + } + node = node->mpPrev; + ++nodeCount; + } + if (nodeCount != size()) + { + return false; + } + + return true; + } + + template + int list_map::validate_iterator(const_iterator iter) const + { + for (const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp) + { + if (temp == iter) + { + return (isf_valid | isf_current | isf_can_dereference); + } + } + + if (iter == end()) + return (isf_valid | isf_current); + + return isf_none; + } + + +} // namespace eastl + + +#endif // Header include guard + + + + diff --git a/libs/eastl/include/EASTL/bonus/ring_buffer.h b/libs/eastl/include/EASTL/bonus/ring_buffer.h new file mode 100644 index 0000000..fc3387e --- /dev/null +++ b/libs/eastl/include/EASTL/bonus/ring_buffer.h @@ -0,0 +1,1557 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// A ring buffer is a FIFO (first-in, first-out) container which acts +// much like a queue. The difference is that a ring buffer is implemented +// via chasing pointers around a given container instead of like queue +// adds to the writes to the end of the container are reads from the begin. +// The benefit of a ring buffer is that memory allocations don't occur +// and new elements are neither added nor removed from the container. +// Elements in the container are simply assigned values in circles around +// the container. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_RING_BUFFER_H +#define EASTL_RING_BUFFER_H + + +#include +#include +#include +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// ring_buffer_iterator + /// + /// We force this iterator to act like a random access iterator even if + /// the underlying container doesn't support random access iteration. + /// Any BidirectionalIterator can be a RandomAccessIterator; it just + /// might be inefficient in some cases. + /// + template + struct ring_buffer_iterator + { + public: + typedef ring_buffer_iterator this_type; + typedef T value_type; + typedef Pointer pointer; + typedef Reference reference; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::iterator container_iterator; + typedef typename Container::const_iterator container_const_iterator; + typedef ring_buffer_iterator iterator; + typedef ring_buffer_iterator const_iterator; + typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category; + + public: + Container* mpContainer; + container_iterator mContainerIterator; + + public: + ring_buffer_iterator(); + ring_buffer_iterator(Container* pContainer, const container_iterator& containerIterator); + ring_buffer_iterator(const iterator& x); + + ring_buffer_iterator& operator=(const iterator& x); + + reference operator*() const; + pointer operator->() const; + + this_type& operator++(); + this_type operator++(int); + + this_type& operator--(); + this_type operator--(int); + + this_type& operator+=(difference_type n); + this_type& operator-=(difference_type n); + + this_type operator+(difference_type n) const; + this_type operator-(difference_type n) const; + + protected: + void increment(difference_type n, EASTL_ITC_NS::input_iterator_tag); + void increment(difference_type n, EASTL_ITC_NS::random_access_iterator_tag); + + }; // struct ring_buffer_iterator + + + + /// ring_buffer + /// + /// Implements a ring buffer via a given container type, which would + /// typically be a vector or array, though any container which supports + /// bidirectional iteration would work. + /// + /// A ring buffer is a FIFO (first-in, first-out) container which acts + /// much like a queue. The difference is that a ring buffer is implemented + /// via chasing pointers around a container and moving the read and write + /// positions forward (and possibly wrapping around) as the container is + /// read and written via pop_front and push_back. + /// + /// The benefit of a ring buffer is that memory allocations don't occur + /// and new elements are neither added nor removed from the container. + /// Elements in the container are simply assigned values in circles around + /// the container. + /// + /// ring_buffer is different from other containers -- including adapter + /// containers -- in how iteration is done. Iteration of a ring buffer + /// starts at the current begin position, proceeds to the end of the underlying + /// container, and continues at the begin of the underlying container until + /// the ring buffer's current end position. Thus a ring_buffer does + /// indeed have a begin and an end, though the values of begin and end + /// chase each other around the container. An empty ring_buffer is one + /// in which end == begin, and a full ring_buffer is one in which + /// end + 1 == begin. + /// + /// Example of a ring buffer layout, where + indicates queued items: + /// ++++++++++--------------------------------+++++++++ + /// ^ ^ + /// end begin + /// + /// Empty ring buffer: + /// --------------------------------------------------- + /// ^ + /// begin / end + /// + /// Full ring buffer. Note that one item is necessarily unused; it is + /// analagous to a '\0' at the end of a C string: + /// +++++++++++++++++++++++++++++++++++++++++-+++++++++ + /// ^^ + /// end begin + /// + /// A push_back operation on a ring buffer assigns the new value to end. + /// If there is no more space in the buffer, this will result in begin + /// being overwritten and the begin position being moved foward one position. + /// The user can use the full() function to detect this condition. + /// Note that elements in a ring buffer are not created or destroyed as + /// their are added and removed; they are merely assigned. Only on + /// container construction and destruction are any elements created and + /// destroyed. + /// + /// The ring buffer can be used in either direction. By this we mean that + /// you can use push_back to add items and pop_front to remove them; or you can + /// use push_front to add items and pop_back to remove them. You aren't + /// limited to these operations; you can push or pop from either side + /// arbitrarily and you can insert or erase anywhere in the container. + /// + /// The ring buffer requires the user to specify a Container type, which + /// by default is vector. However, any container with bidirectional iterators + /// will work, such as list, deque, string or any of the fixed_* versions + /// of these containers, such as fixed_string. Since ring buffer works via copying + /// elements instead of allocating and freeing nodes, inserting in the middle + /// of a ring buffer based on list (instead of vector) is no more efficient. + /// + /// To use the ring buffer, its container must be resized to the desired + /// ring buffer size. Changing the size of a ring buffer may cause ring + /// buffer iterators to invalidate. + /// + /// An alternative to using a ring buffer is to use a list with a user-created + /// node pool and custom allocator. There are various tradeoffs that result from this. + /// + /// Example usage: + /// ring_buffer< int, list > rb(100); + /// rb.push_back(1); + /// + /// Example usage: + /// // Example of creating an on-screen debug log that shows 16 + /// // strings at a time and scrolls older strings away. + /// + /// // Create ring buffer of 16 strings. + /// ring_buffer< string, vector > debugLogText(16); + /// + /// // Reserve 128 chars for each line. This can make it so that no + /// // runtime memory allocations occur. + /// for(vector::iterator it = debugLogText.get_container().begin(), + /// itEnd = debugLogText.get_container().end(); it != itEnd; ++it) + /// { + /// (*it).reserve(128); + /// } + /// + /// // Add a new string, using push_front() and front() instead of + /// // push_front(str) in order to avoid creating a temporary str. + /// debugLogText.push_front(); + /// debugLogText.front() = "Player fired weapon"; + /// + template , typename Allocator = typename Container::allocator_type> + class ring_buffer + { + public: + typedef ring_buffer this_type; + typedef Container container_type; + typedef Allocator allocator_type; + + typedef typename Container::value_type value_type; + typedef typename Container::reference reference; + typedef typename Container::const_reference const_reference; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::iterator container_iterator; + typedef typename Container::const_iterator container_const_iterator; + typedef ring_buffer_iterator iterator; + typedef ring_buffer_iterator const_iterator; + typedef eastl::reverse_iterator reverse_iterator; + typedef eastl::reverse_iterator const_reverse_iterator; + + public: // We declare public so that global comparison operators can be implemented without adding an inline level and without tripping up GCC 2.x friend declaration failures. GCC (through at least v4.0) is poor at inlining and performance wins over correctness. + Container c; // We follow the naming convention established for stack, queue, priority_queue and name this 'c'. This variable must always have a size of at least 1, as even an empty ring_buffer has an unused terminating element. + + protected: + container_iterator mBegin; // We keep track of where our begin and end are by using Container iterators. + container_iterator mEnd; + size_type mSize; + + public: + // There currently isn't a ring_buffer constructor that specifies and initial size, unlike other containers. + explicit ring_buffer(size_type cap = 0); // Construct with an initial capacity (but size of 0). + explicit ring_buffer(size_type cap, const allocator_type& allocator); + explicit ring_buffer(const Container& x); + explicit ring_buffer(const allocator_type& allocator); + ring_buffer(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + ring_buffer(this_type&& x); + ring_buffer(this_type&& x, const allocator_type& allocator); + #endif + ring_buffer(std::initializer_list ilist, const allocator_type& allocator = allocator_type()); // This function sets the capacity to be equal to the size of the initializer list. + + // No destructor necessary. Default will do. + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + template + void assign(InputIterator first, InputIterator last); + + void swap(this_type& x); + + iterator begin() EA_NOEXCEPT; + const_iterator begin() const EA_NOEXCEPT; + const_iterator cbegin() const EA_NOEXCEPT; + + iterator end() EA_NOEXCEPT; + const_iterator end() const EA_NOEXCEPT; + const_iterator cend() const EA_NOEXCEPT; + + reverse_iterator rbegin() EA_NOEXCEPT; + const_reverse_iterator rbegin() const EA_NOEXCEPT; + const_reverse_iterator crbegin() const EA_NOEXCEPT; + + reverse_iterator rend() EA_NOEXCEPT; + const_reverse_iterator rend() const EA_NOEXCEPT; + const_reverse_iterator crend() const EA_NOEXCEPT; + + bool empty() const EA_NOEXCEPT; + bool full() const EA_NOEXCEPT; + size_type size() const EA_NOEXCEPT; + void resize(size_type n); + size_type capacity() const EA_NOEXCEPT; + void set_capacity(size_type n); // Sets the capacity to the given value, including values less than the current capacity. Adjusts the size downward if n < size, by throwing out the oldest elements in the buffer. + void reserve(size_type n); // Reserve a given capacity. Doesn't decrease the capacity; it only increases it (for compatibility with other containers' behavior). + + reference front(); + const_reference front() const; + + reference back(); + const_reference back() const; + + void push_back(const value_type& value); + reference push_back(); + + void pop_back(); + + void push_front(const value_type& value); + reference push_front(); + + void pop_front(); + + reference operator[](size_type n); + const_reference operator[](size_type n) const; + + // To consider: + // size_type read(value_type* pDestination, size_type nCount); + // size_type read(iterator** pPosition1, iterator** pPosition2, size_type& nCount1, size_type& nCount2); + + /* To do: + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + void emplace_front(Args&&... args); + + template + void emplace_back(Args&&... args); + + template + iterator emplace(const_iterator position, Args&&... args); + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + void push_front(value_type&& value); + void push_back(value_type&& value); + + void emplace_front(value_type&& value); + void emplace_back(value_type&& value); + iterator emplace(const_iterator position, value_type&& value); + #endif + + void emplace_front(const value_type& value); + void emplace_back(const value_type& value); + iterator emplace(const_iterator position, const value_type& value); + #endif + */ + + iterator insert(const_iterator position, const value_type& value); + void insert(const_iterator position, size_type n, const value_type& value); + void insert(const_iterator position, std::initializer_list ilist); + + template + void insert(const_iterator position, InputIterator first, InputIterator last); + + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + + reverse_iterator erase(const_reverse_iterator position); + reverse_iterator erase(const_reverse_iterator first, const_reverse_iterator last); + + void clear(); + + container_type& get_container(); + const container_type& get_container() const; + + bool validate() const; + int validate_iterator(const_iterator i) const; + + protected: + //size_type DoGetSize(EASTL_ITC_NS::input_iterator_tag) const; + //size_type DoGetSize(EASTL_ITC_NS::random_access_iterator_tag) const; + + }; // class ring_buffer + + + + + /////////////////////////////////////////////////////////////////////// + // ring_buffer_iterator + /////////////////////////////////////////////////////////////////////// + + template + ring_buffer_iterator::ring_buffer_iterator() + : mpContainer(NULL), mContainerIterator() + { + } + + + template + ring_buffer_iterator::ring_buffer_iterator(Container* pContainer, const container_iterator& containerIterator) + : mpContainer(pContainer), mContainerIterator(containerIterator) + { + } + + + template + ring_buffer_iterator::ring_buffer_iterator(const iterator& x) + : mpContainer(x.mpContainer), mContainerIterator(x.mContainerIterator) + { + } + + + template + ring_buffer_iterator& + ring_buffer_iterator::operator=(const iterator& x) + { + mpContainer = x.mpContainer; + mContainerIterator = x.mContainerIterator; + return *this; + } + + template + typename ring_buffer_iterator::reference + ring_buffer_iterator::operator*() const + { + return *mContainerIterator; + } + + + template + typename ring_buffer_iterator::pointer + ring_buffer_iterator::operator->() const + { + return &*mContainerIterator; + } + + + template + typename ring_buffer_iterator::this_type& + ring_buffer_iterator::operator++() + { + if(EASTL_UNLIKELY(++mContainerIterator == mpContainer->end())) + mContainerIterator = mpContainer->begin(); + return *this; + } + + + template + typename ring_buffer_iterator::this_type + ring_buffer_iterator::operator++(int) + { + const this_type temp(*this); + if(EASTL_UNLIKELY(++mContainerIterator == mpContainer->end())) + mContainerIterator = mpContainer->begin(); + return temp; + } + + + template + typename ring_buffer_iterator::this_type& + ring_buffer_iterator::operator--() + { + if(EASTL_UNLIKELY(mContainerIterator == mpContainer->begin())) + mContainerIterator = mpContainer->end(); + --mContainerIterator; + return *this; + } + + + template + typename ring_buffer_iterator::this_type + ring_buffer_iterator::operator--(int) + { + const this_type temp(*this); + if(EASTL_UNLIKELY(mContainerIterator == mpContainer->begin())) + mContainerIterator = mpContainer->end(); + --mContainerIterator; + return temp; + } + + + template + typename ring_buffer_iterator::this_type& + ring_buffer_iterator::operator+=(difference_type n) + { + typedef typename eastl::iterator_traits::iterator_category IC; + increment(n, IC()); + return *this; + } + + + template + typename ring_buffer_iterator::this_type& + ring_buffer_iterator::operator-=(difference_type n) + { + typedef typename eastl::iterator_traits::iterator_category IC; + increment(-n, IC()); + return *this; + } + + + template + typename ring_buffer_iterator::this_type + ring_buffer_iterator::operator+(difference_type n) const + { + return this_type(*this).operator+=(n); + } + + + template + typename ring_buffer_iterator::this_type + ring_buffer_iterator::operator-(difference_type n) const + { + return this_type(*this).operator+=(-n); + } + + + template + void ring_buffer_iterator::increment(difference_type n, EASTL_ITC_NS::input_iterator_tag) + { + // n cannot be negative, as input iterators don't support reverse iteration. + while(n-- > 0) + operator++(); + } + + + template + void ring_buffer_iterator::increment(difference_type n, EASTL_ITC_NS::random_access_iterator_tag) + { + // We make the assumption here that the user is incrementing from a valid + // starting position to a valid ending position. Thus *this + n yields a + // valid iterator, including if n happens to be a negative value. + + if(n >= 0) + { + const difference_type d = mpContainer->end() - mContainerIterator; + + if(n < d) + mContainerIterator += n; + else + mContainerIterator = mpContainer->begin() + (n - d); + } + else + { + // Recall that n and d here will be negative and so the logic here works as intended. + const difference_type d = mpContainer->begin() - mContainerIterator; + + if(n >= d) + mContainerIterator += n; + else + mContainerIterator = mpContainer->end() + (n - d); + } + } + + + // Random access iterators must support operator + and operator -. + // You can only add an integer to an iterator, and you cannot add two iterators. + template + inline ring_buffer_iterator + operator+(ptrdiff_t n, const ring_buffer_iterator& x) + { + return x + n; // Implement (n + x) in terms of (x + n). + } + + + // You can only add an integer to an iterator, but you can subtract two iterators. + template + inline typename ring_buffer_iterator::difference_type + operator-(const ring_buffer_iterator& a, + const ring_buffer_iterator& b) + { + typedef typename ring_buffer_iterator::difference_type difference_type; + + // To do: If container_iterator is a random access iterator, then do a simple calculation. + // Otherwise, we have little choice but to iterate from a to b and count as we go. + // See the ring_buffer::size function for an implementation of this. + + // Iteration implementation: + difference_type d = 0; + + for(ring_buffer_iterator temp(b); temp != a; ++temp) + ++d; + + return d; + } + + + // The C++ defect report #179 requires that we support comparisons between const and non-const iterators. + // Thus we provide additional template paremeters here to support this. The defect report does not + // require us to support comparisons between reverse_iterators and const_reverse_iterators. + template + inline bool operator==(const ring_buffer_iterator& a, + const ring_buffer_iterator& b) + { + // Perhaps we should compare the container pointer as well. + // However, for valid iterators this shouldn't be necessary. + return a.mContainerIterator == b.mContainerIterator; + } + + + template + inline bool operator!=(const ring_buffer_iterator& a, + const ring_buffer_iterator& b) + { + // Perhaps we should compare the container pointer as well. + // However, for valid iterators this shouldn't be necessary. + return !(a.mContainerIterator == b.mContainerIterator); + } + + + // We provide a version of operator!= for the case where the iterators are of the + // same type. This helps prevent ambiguity errors in the presence of rel_ops. + template + inline bool operator!=(const ring_buffer_iterator& a, + const ring_buffer_iterator& b) + { + return !(a.mContainerIterator == b.mContainerIterator); + } + + + + + /////////////////////////////////////////////////////////////////////// + // ring_buffer + /////////////////////////////////////////////////////////////////////// + + template + ring_buffer::ring_buffer(size_type cap) + : c() // Default construction with default allocator for the container. + { + // To do: This code needs to be amended to deal with possible exceptions + // that could occur during the resize call below. + + // We add one because the element at mEnd is necessarily unused. + c.resize(cap + 1); // Possibly we could construct 'c' with size, but c may not have such a ctor, though we rely on it having a resize function. + mBegin = c.begin(); + mEnd = mBegin; + mSize = 0; + } + + + template + ring_buffer::ring_buffer(size_type cap, const allocator_type& allocator) + : c(allocator) + { + // To do: This code needs to be amended to deal with possible exceptions + // that could occur during the resize call below. + + // We add one because the element at mEnd is necessarily unused. + c.resize(cap + 1); // Possibly we could construct 'c' with size, but c may not have such a ctor, though we rely on it having a resize function. + mBegin = c.begin(); + mEnd = mBegin; + mSize = 0; + } + + + template + ring_buffer::ring_buffer(const Container& x) + : c(x) // This copies elements from x, but unless the user is doing some tricks, the only thing that matters is that c.size() == x.size(). + { + // To do: This code needs to be amended to deal with possible exceptions + // that could occur during the resize call below. + if(c.empty()) + c.resize(1); + mBegin = c.begin(); + mEnd = mBegin; + mSize = 0; + } + + + template + ring_buffer::ring_buffer(const allocator_type& allocator) + : c(allocator) + { + // To do: This code needs to be amended to deal with possible exceptions + // that could occur during the resize call below. + + // We add one because the element at mEnd is necessarily unused. + c.resize(1); // Possibly we could construct 'c' with size, but c may not have such a ctor, though we rely on it having a resize function. + mBegin = c.begin(); + mEnd = mBegin; + mSize = 0; + } + + + template + ring_buffer::ring_buffer(const this_type& x) + : c(x.c) + { + mBegin = c.begin(); + mEnd = mBegin; + mSize = x.mSize; + + eastl::advance(mBegin, eastl::distance(const_cast(x).c.begin(), x.mBegin)); // We can do a simple distance algorithm here, as there will be no wraparound. + eastl::advance(mEnd, eastl::distance(const_cast(x).c.begin(), x.mEnd)); + } + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + ring_buffer::ring_buffer(this_type&& x) + : c() // Default construction with default allocator for the container. + { + c.resize(1); // Possibly we could construct 'c' with size, but c may not have such a ctor, though we rely on it having a resize function. + mBegin = c.begin(); + mEnd = mBegin; + mSize = 0; + + swap(x); // We are leaving x in an unusual state by swapping default-initialized members with it, as it won't be usable and can be only destructible. + } + + template + ring_buffer::ring_buffer(this_type&& x, const allocator_type& allocator) + : c(allocator) + { + c.resize(1); // Possibly we could construct 'c' with size, but c may not have such a ctor, though we rely on it having a resize function. + mBegin = c.begin(); + mEnd = mBegin; + mSize = 0; + + if(c.get_allocator() == x.c.get_allocator()) + swap(x); // We are leaving x in an unusual state by swapping default-initialized members with it, as it won't be usable and can be only destructible. + else + operator=(x); + } + #endif + + + template + ring_buffer::ring_buffer(std::initializer_list ilist, const allocator_type& allocator) + : c(allocator) + { + c.resize((eastl_size_t)ilist.size() + 1); + mBegin = c.begin(); + mEnd = mBegin; + mSize = 0; + + assign(ilist.begin(), ilist.end()); + } + + + template + typename ring_buffer::this_type& + ring_buffer::operator=(const this_type& x) + { + if(&x != this) + { + c = x.c; + + mBegin = c.begin(); + mEnd = mBegin; + mSize = x.mSize; + + eastl::advance(mBegin, eastl::distance(const_cast(x).c.begin(), x.mBegin)); // We can do a simple distance algorithm here, as there will be no wraparound. + eastl::advance(mEnd, eastl::distance(const_cast(x).c.begin(), x.mEnd)); + } + + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + typename ring_buffer::this_type& + ring_buffer::operator=(this_type&& x) + { + swap(x); + return *this; + } + #endif + + + template + typename ring_buffer::this_type& + ring_buffer::operator=(std::initializer_list ilist) + { + assign(ilist.begin(), ilist.end()); + return *this; + } + + + template + template + void ring_buffer::assign(InputIterator first, InputIterator last) + { + // To consider: We can make specializations of this for pointer-based + // iterators to PODs and turn the action into a memcpy. + clear(); + + for(; first != last; ++first) + push_back(*first); + } + + + template + void ring_buffer::swap(this_type& x) + { + if(&x != this) + { + const difference_type dBegin = eastl::distance(c.begin(), mBegin); // We can do a simple distance algorithm here, as there will be no wraparound. + const difference_type dEnd = eastl::distance(c.begin(), mEnd); + + const difference_type dxBegin = eastl::distance(x.c.begin(), x.mBegin); + const difference_type dxEnd = eastl::distance(x.c.begin(), x.mEnd); + + eastl::swap(c, x.c); + eastl::swap(mSize, x.mSize); + + mBegin = c.begin(); + eastl::advance(mBegin, dxBegin); // We can do a simple advance algorithm here, as there will be no wraparound. + + mEnd = c.begin(); + eastl::advance(mEnd, dxEnd); + + x.mBegin = x.c.begin(); + eastl::advance(x.mBegin, dBegin); + + x.mEnd = x.c.begin(); + eastl::advance(x.mEnd, dEnd); + } + } + + + template + typename ring_buffer::iterator + ring_buffer::begin() EA_NOEXCEPT + { + return iterator(&c, mBegin); + } + + + template + typename ring_buffer::const_iterator + ring_buffer::begin() const EA_NOEXCEPT + { + return const_iterator(const_cast(&c), mBegin); // We trust that the const_iterator will respect const-ness. + } + + + template + typename ring_buffer::const_iterator + ring_buffer::cbegin() const EA_NOEXCEPT + { + return const_iterator(const_cast(&c), mBegin); // We trust that the const_iterator will respect const-ness. + } + + + template + typename ring_buffer::iterator + ring_buffer::end() EA_NOEXCEPT + { + return iterator(&c, mEnd); + } + + + template + typename ring_buffer::const_iterator + ring_buffer::end() const EA_NOEXCEPT + { + return const_iterator(const_cast(&c), mEnd); // We trust that the const_iterator will respect const-ness. + } + + + template + typename ring_buffer::const_iterator + ring_buffer::cend() const EA_NOEXCEPT + { + return const_iterator(const_cast(&c), mEnd); // We trust that the const_iterator will respect const-ness. + } + + + template + typename ring_buffer::reverse_iterator + ring_buffer::rbegin() EA_NOEXCEPT + { + return reverse_iterator(iterator(&c, mEnd)); + } + + + template + typename ring_buffer::const_reverse_iterator + ring_buffer::rbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(const_iterator(const_cast(&c), mEnd)); + } + + + template + typename ring_buffer::const_reverse_iterator + ring_buffer::crbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(const_iterator(const_cast(&c), mEnd)); + } + + + template + typename ring_buffer::reverse_iterator + ring_buffer::rend() EA_NOEXCEPT + { + return reverse_iterator(iterator(&c, mBegin)); + } + + + template + typename ring_buffer::const_reverse_iterator + ring_buffer::rend() const EA_NOEXCEPT + { + return const_reverse_iterator(const_iterator(const_cast(&c), mBegin)); + } + + + template + typename ring_buffer::const_reverse_iterator + ring_buffer::crend() const EA_NOEXCEPT + { + return const_reverse_iterator(const_iterator(const_cast(&c), mBegin)); + } + + + template + bool ring_buffer::empty() const EA_NOEXCEPT + { + return mBegin == mEnd; + } + + + template + bool ring_buffer::full() const EA_NOEXCEPT + { + // Implementation that relies on c.size() being a fast operation: + // return mSize == (c.size() - 1); // (c.size() - 1) == capacity(); we are attempting to reduce function calls. + + // Version that has constant speed guarantees, but is still pretty fast. + const_iterator afterEnd(end()); + ++afterEnd; + return afterEnd.mContainerIterator == mBegin; + } + + + template + typename ring_buffer::size_type + ring_buffer::size() const EA_NOEXCEPT + { + return mSize; + + // Alternatives: + // return eastl::distance(begin(), end()); + // return end() - begin(); // This is more direct than using distance(). + //typedef typename eastl::iterator_traits::iterator_category IC; + //return DoGetSize(IC()); // This is more direct than using iterator math. + } + + + /* + template + typename ring_buffer::size_type + ring_buffer::DoGetSize(EASTL_ITC_NS::input_iterator_tag) const + { + // We could alternatively just use eastl::distance() here, but we happen to + // know that such code would boil down to what we have here, and we might + // as well remove function calls where possible. + difference_type d = 0; + + for(const_iterator temp(begin()), tempEnd(end()); temp != tempEnd; ++temp) + ++d; + + return (size_type)d; + } + */ + + /* + template + typename ring_buffer::size_type + ring_buffer::DoGetSize(EASTL_ITC_NS::random_access_iterator_tag) const + { + // A simpler but less efficient implementation fo this function would be: + // return eastl::distance(mBegin, mEnd); + // + // The calculation of distance here takes advantage of the fact that random + // access iterators' distances can be calculated by simple pointer calculation. + // Thus the code below boils down to a few subtractions when using a vector, + // string, or array as the Container type. + // + const difference_type dBegin = eastl::distance(const_cast(c).begin(), mBegin); // const_cast here solves a little compiler + const difference_type dEnd = eastl::distance(const_cast(c).begin(), mEnd); // argument matching problem. + + if(dEnd >= dBegin) + return dEnd - dBegin; + + return c.size() - (dBegin - dEnd); + } + */ + + template + class ContainerTemporary + { + public: + Container* get_container(); + }; + + + template + struct ContainerTemporary + { + Container mContainer; + + public: + Container& get() + { + return mContainer; + } + }; + + + template + struct ContainerTemporary + { + EASTLAllocatorType mAllocator; + Container* mContainer; + + public: + ContainerTemporary() + : mAllocator(*EASTLAllocatorDefault(), EASTL_TEMP_DEFAULT_NAME) + , mContainer(new(mAllocator.allocate(sizeof(Container))) Container) + {} + + ~ContainerTemporary() + { + mContainer->~Container(); + mAllocator.deallocate(mContainer, sizeof(Container)); + } + + Container& get() + { + return *mContainer; + } + }; + + + template + void ring_buffer::resize(size_type n) + { + // Note that if n > size(), we just move the end position out to + // the begin + n, with the data being the old end and the new end + // being stale values from the past. This is by design, as the concept + // of arbitrarily resizing a ring buffer like this is currently deemed + // to be vague in what it intends to do. We can only assume that the + // user knows what he is doing and will deal with the stale values. + EASTL_ASSERT(c.size() >= 1); + const size_type cap = (c.size() - 1); + + mSize = n; + + if(n > cap) // If we need to grow in capacity... + { + // Given that a growing operation will always result in memory allocation, + // we currently implement this function via the usage of a temp container. + // This makes for a simple implementation, but in some cases it is less + // efficient. In particular, if the container is a node-based container like + // a (linked) list, this function would be faster if we simply added nodes + // to ourself. We would do this by inserting the nodes to be after end() + // and adjusting the begin() position if it was after end(). + + // To do: This code needs to be amended to deal with possible exceptions + // that could occur during the resize call below. + + ContainerTemporary= EASTL_MAX_STACK_USAGE> cTemp; + cTemp.get().resize(n + 1); + eastl::copy(begin(), end(), cTemp.get().begin()); + eastl::swap(c, cTemp.get()); + + mBegin = c.begin(); + mEnd = mBegin; + eastl::advance(mEnd, n); // We can do a simple advance algorithm on this because we know that mEnd will not wrap around. + } + else // We could do a check here for n != size(), but that would be costly and people don't usually resize things to their same size. + { + mEnd = mBegin; + + // eastl::advance(mEnd, n); // We *cannot* use this because there may be wraparound involved. + + // To consider: Possibly we should implement some more detailed logic to optimize the code here. + // We'd need to do different behaviour dending on whether the container iterator type is a + // random access iterator or otherwise. + + while(n--) + { + if(EASTL_UNLIKELY(++mEnd == c.end())) + mEnd = c.begin(); + } + } + } + + + template + typename ring_buffer::size_type + ring_buffer::capacity() const EA_NOEXCEPT + { + EASTL_ASSERT(c.size() >= 1); // This is required because even an empty ring_buffer has one unused termination element, somewhat like a \0 at the end of a C string. + + return (c.size() - 1); // Need to subtract one because the position at mEnd is unused. + } + + + template + void ring_buffer::set_capacity(size_type n) + { + const size_type capacity = (c.size() - 1); + + if(n != capacity) // If we need to change capacity... + { + ContainerTemporary= EASTL_MAX_STACK_USAGE> cTemp; + cTemp.get().resize(n + 1); + + iterator itCopyBegin = begin(); + + if(n < mSize) // If we are shrinking the capacity, to less than our size... + { + eastl::advance(itCopyBegin, mSize - n); + mSize = n; + } + + eastl::copy(itCopyBegin, end(), cTemp.get().begin()); // The begin-end range may in fact be larger than n, in which case values will be overwritten. + eastl::swap(c, cTemp.get()); + + mBegin = c.begin(); + mEnd = mBegin; + eastl::advance(mEnd, mSize); // We can do a simple advance algorithm on this because we know that mEnd will not wrap around. + } + } + + + template + void ring_buffer::reserve(size_type n) + { + // We follow the pattern of vector and only do something if n > capacity. + EASTL_ASSERT(c.size() >= 1); + + if(n > (c.size() - 1)) // If we need to grow in capacity... // (c.size() - 1) == capacity(); we are attempting to reduce function calls. + { + ContainerTemporary= EASTL_MAX_STACK_USAGE> cTemp; + cTemp.get().resize(n + 1); + eastl::copy(begin(), end(), cTemp.get().begin()); + eastl::swap(c, cTemp.get()); + + mBegin = c.begin(); + mEnd = mBegin; + eastl::advance(mEnd, mSize); // We can do a simple advance algorithm on this because we know that mEnd will not wrap around. + } + } + + + template + typename ring_buffer::reference + ring_buffer::front() + { + return *mBegin; + } + + + template + typename ring_buffer::const_reference + ring_buffer::front() const + { + return *mBegin; + } + + + template + typename ring_buffer::reference + ring_buffer::back() + { + // return *(end() - 1); // Can't use this because not all iterators support operator-. + + iterator temp(end()); // To do: Find a way to construct this temporary in the return statement. + return *(--temp); // We can do it by making all our containers' iterators support operator-. + } + + + template + typename ring_buffer::const_reference + ring_buffer::back() const + { + // return *(end() - 1); // Can't use this because not all iterators support operator-. + + const_iterator temp(end()); // To do: Find a way to construct this temporary in the return statement. + return *(--temp); // We can do it by making all our containers' iterators support operator-. + } + + + /// A push_back operation on a ring buffer assigns the new value to end. + /// If there is no more space in the buffer, this will result in begin + /// being overwritten and the begin position being moved foward one position. + template + void ring_buffer::push_back(const value_type& value) + { + *mEnd = value; + + if(++mEnd == c.end()) + mEnd = c.begin(); + + if(mEnd == mBegin) + { + if(++mBegin == c.end()) + mBegin = c.begin(); + } + else + ++mSize; + } + + + /// A push_back operation on a ring buffer assigns the new value to end. + /// If there is no more space in the buffer, this will result in begin + /// being overwritten and the begin position being moved foward one position. + template + typename ring_buffer::reference + ring_buffer::push_back() + { + // We don't do the following assignment, as the value at mEnd is already constructed; + // it is merely possibly not default-constructed. However, the spirit of push_back + // is that the user intends to do an assignment or data modification after the + // push_back call. The user can always execute *back() = value_type() if he wants. + //*mEnd = value_type(); + + if(++mEnd == c.end()) + mEnd = c.begin(); + + if(mEnd == mBegin) + { + if(++mBegin == c.end()) + mBegin = c.begin(); + } + else + ++mSize; + + return back(); + } + + + template + void ring_buffer::pop_back() + { + EASTL_ASSERT(mEnd != mBegin); // We assume that size() > 0 and thus that there is something to pop. + + if(EASTL_UNLIKELY(mEnd == c.begin())) + mEnd = c.end(); + --mEnd; + --mSize; + } + + + template + void ring_buffer::push_front(const value_type& value) + { + if(EASTL_UNLIKELY(mBegin == c.begin())) + mBegin = c.end(); + + if(--mBegin == mEnd) + { + if(EASTL_UNLIKELY(mEnd == c.begin())) + mEnd = c.end(); + --mEnd; + } + else + ++mSize; + + *mBegin = value; + } + + + template + typename ring_buffer::reference + ring_buffer::push_front() + { + if(EASTL_UNLIKELY(mBegin == c.begin())) + mBegin = c.end(); + + if(--mBegin == mEnd) + { + if(EASTL_UNLIKELY(mEnd == c.begin())) + mEnd = c.end(); + --mEnd; + } + else + ++mSize; + + // See comments above in push_back for why we don't execute this: + // *mBegin = value_type(); + + return *mBegin; // Same as return front(); + } + + + template + void ring_buffer::pop_front() + { + EASTL_ASSERT(mBegin != mEnd); // We assume that mEnd > mBegin and thus that there is something to pop. + + if(++mBegin == c.end()) + mBegin = c.begin(); + --mSize; + } + + + template + typename ring_buffer::reference + ring_buffer::operator[](size_type n) + { + // return *(begin() + n); // Can't use this because not all iterators support operator+. + + // This should compile to code that is nearly as efficient as that above. + // The primary difference is the possible generation of a temporary in this case. + iterator temp(begin()); + eastl::advance(temp, n); + return *(temp.mContainerIterator); + } + + + template + typename ring_buffer::const_reference + ring_buffer::operator[](size_type n) const + { + // return *(begin() + n); // Can't use this because not all iterators support operator+. + + // This should compile to code that is nearly as efficient as that above. + // The primary difference is the possible generation of a temporary in this case. + const_iterator temp(begin()); + eastl::advance(temp, n); + return *(temp.mContainerIterator); + } + + + template + typename ring_buffer::iterator + ring_buffer::insert(const_iterator position, const value_type& value) + { + // To consider: It would be faster if we could tell that position was in the first + // half of the container and instead of moving things after the position back, + // we could move things before the position forward. + + iterator afterEnd(end()); + iterator beforeEnd(afterEnd); + + ++afterEnd; + + if(afterEnd.mContainerIterator == mBegin) // If we are at full capacity... + --beforeEnd; + else + push_back(); + + iterator itPosition(position.mpContainer, position.mContainerIterator); // We merely copy from const_iterator to iterator. + eastl::copy_backward(itPosition, beforeEnd, end()); + *itPosition = value; + + return itPosition; + } + + + template + void ring_buffer::insert(const_iterator position, size_type n, const value_type& value) + { + // To do: This can be improved with a smarter version. However, + // this is a little tricky because we need to deal with the case + // whereby n is greater than the size of the container itself. + while(n--) + insert(position, value); + } + + + template + void ring_buffer::insert(const_iterator position, std::initializer_list ilist) + { + insert(position, ilist.begin(), ilist.end()); + } + + + template + template + void ring_buffer::insert(const_iterator position, InputIterator first, InputIterator last) + { + // To do: This can possibly be improved with a smarter version. + // However, this can be tricky if distance(first, last) is greater + // than the size of the container itself. + for(; first != last; ++first, ++position) + insert(position, *first); + } + + + template + typename ring_buffer::iterator + ring_buffer::erase(const_iterator position) + { + iterator itPosition(position.mpContainer, position.mContainerIterator); // We merely copy from const_iterator to iterator. + iterator iNext(itPosition); + + eastl::copy(++iNext, end(), itPosition); + pop_back(); + + return itPosition; + } + + + template + typename ring_buffer::iterator + ring_buffer::erase(const_iterator first, const_iterator last) + { + iterator itFirst(first.mpContainer, first.mContainerIterator); // We merely copy from const_iterator to iterator. + iterator itLast(last.mpContainer, last.mContainerIterator); + + typename iterator::difference_type d = eastl::distance(itFirst, itLast); + + eastl::copy(itLast, end(), itFirst); + + while(d--) // To do: improve this implementation. + pop_back(); + + return itFirst; + } + + + template + typename ring_buffer::reverse_iterator + ring_buffer::erase(const_reverse_iterator position) + { + return reverse_iterator(erase((++position).base())); + } + + + template + typename ring_buffer::reverse_iterator + ring_buffer::erase(const_reverse_iterator first, const_reverse_iterator last) + { + // Version which erases in order from first to last. + // difference_type i(first.base() - last.base()); + // while(i--) + // first = erase(first); + // return first; + + // Version which erases in order from last to first, but is slightly more efficient: + return reverse_iterator(erase((++last).base(), (++first).base())); + } + + + template + void ring_buffer::clear() + { + // Don't clear the container; we use its valid data for our elements. + mBegin = c.begin(); + mEnd = c.begin(); + mSize = 0; + } + + + template + typename ring_buffer::container_type& + ring_buffer::get_container() + { + return c; + } + + + template + const typename ring_buffer::container_type& + ring_buffer::get_container() const + { + return c; + } + + + template + inline bool ring_buffer::validate() const + { + if(!c.validate()) // This requires that the container implement the validate function. That pretty much + return false; // means that the container is an EASTL container and not a std STL container. + + if(c.empty()) // c must always have a size of at least 1, as even an empty ring_buffer has an unused terminating element. + return false; + + if(size() > capacity()) + return false; + + if((validate_iterator(begin()) & (isf_valid | isf_current)) != (isf_valid | isf_current)) + return false; + + if((validate_iterator(end()) & (isf_valid | isf_current)) != (isf_valid | isf_current)) + return false; + + // Verify that the size calculation is consistent. + size_type n = 0; + for(const_iterator i(begin()), iEnd(end()); i != iEnd; ++i) + ++n; + if(n != mSize) + return false; + + return true; + } + + + template + inline int ring_buffer::validate_iterator(const_iterator i) const + { + // To do: Replace this with a more efficient implementation if possible. + + for(const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp) + { + if(temp == i) + return (isf_valid | isf_current | isf_can_dereference); + } + + if(i == end()) + return (isf_valid | isf_current); + + return isf_none; + } + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const ring_buffer& a, const ring_buffer& b) + { + return (a.size() == b.size()) && (a.c == b.c); + } + + + template + inline bool operator<(const ring_buffer& a, const ring_buffer& b) + { + const typename ring_buffer::size_type sizeA = a.size(); + const typename ring_buffer::size_type sizeB = b.size(); + + if(sizeA == sizeB) + return (a.c < b.c); + return sizeA < sizeB; + } + + + template + inline bool operator!=(const ring_buffer& a, const ring_buffer& b) + { + return !(a == b); + } + + + template + inline bool operator>(const ring_buffer& a, const ring_buffer& b) + { + return (b < a); + } + + + template + inline bool operator<=(const ring_buffer& a, const ring_buffer& b) + { + return !(b < a); + } + + + template + inline bool operator>=(const ring_buffer& a, const ring_buffer& b) + { + return !(a < b); + } + + + template + inline void swap(ring_buffer& a, ring_buffer& b) + { + a.swap(b); + } + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/bonus/sort_extra.h b/libs/eastl/include/EASTL/bonus/sort_extra.h new file mode 100644 index 0000000..5f9a0c4 --- /dev/null +++ b/libs/eastl/include/EASTL/bonus/sort_extra.h @@ -0,0 +1,204 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// This file implements additional sort algorithms beyond the basic set. +// Included here are: +// selection_sort -- Unstable. +// shaker_sort -- Stable. +// bucket_sort -- Stable. +// +////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_SORT_EXTRA_H +#define EASTL_SORT_EXTRA_H + + +#include +#include +#include +#include +#include +#include // For backwards compatibility due to sorts moved from here to sort.h. +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + /// selection_sort + /// + /// Implements the SelectionSort algorithm. + /// + template + void selection_sort(ForwardIterator first, ForwardIterator last, StrictWeakOrdering compare) + { + ForwardIterator iCurrent, iMin; + + for(; first != last; ++first) + { + iCurrent = first; + iMin = iCurrent; + + for(++iCurrent; iCurrent != last; ++iCurrent) + { + if(compare(*iCurrent, *iMin)) + { + EASTL_VALIDATE_COMPARE(!compare(*iMin, *iCurrent)); // Validate that the compare function is sane. + iMin = iCurrent; + } + } + + if(first != iMin) + eastl::iter_swap(first, iMin); + } + } // selection_sort + + template + inline void selection_sort(ForwardIterator first, ForwardIterator last) + { + typedef eastl::less::value_type> Less; + + eastl::selection_sort(first, last, Less()); + } + + + + /// shaker_sort + /// + /// Implements the ShakerSort algorithm, which is a sorting algorithm which + /// improves on bubble_sort by sweeping both from left to right and right + /// to left, resulting in less iteration. + /// + template + void shaker_sort(BidirectionalIterator first, BidirectionalIterator last, StrictWeakOrdering compare) + { + if(first != last) + { + BidirectionalIterator iCurrent, iNext, iLastModified; + + --last; + + while(first != last) + { + iLastModified = first; + + for(iCurrent = first; iCurrent != last; iCurrent = iNext) + { + iNext = iCurrent; + ++iNext; + + if(compare(*iNext, *iCurrent)) + { + EASTL_VALIDATE_COMPARE(!compare(*iCurrent, *iNext)); // Validate that the compare function is sane. + iLastModified = iCurrent; + eastl::iter_swap(iCurrent, iNext); + } + } + + last = iLastModified; + + if(first != last) + { + for(iCurrent = last; iCurrent != first; iCurrent = iNext) + { + iNext = iCurrent; + --iNext; + + if(compare(*iCurrent, *iNext)) + { + EASTL_VALIDATE_COMPARE(!compare(*iNext, *iCurrent)); // Validate that the compare function is sane. + iLastModified = iCurrent; + eastl::iter_swap(iNext, iCurrent); + } + } + first = iLastModified; + } + } + } + } // shaker_sort + + template + inline void shaker_sort(BidirectionalIterator first, BidirectionalIterator last) + { + typedef eastl::less::value_type> Less; + + eastl::shaker_sort(first, last, Less()); + } + + + + /// bucket_sort + /// + /// Implements the BucketSort algorithm. + /// + /// Example usage: + /// const size_t kElementRange = 32; + /// vector intArray(1000); + /// + /// for(int i = 0; i < 1000; i++) + /// intArray[i] = rand() % kElementRange; + /// + /// vector< vector > bucketArray(kElementRange); + /// bucket_sort(intArray.begin(), intArray.end(), bucketArray, eastl::hash_use_self()); + /// + template + struct hash_use_self + { + T operator()(const T& x) const + { return x; } + }; + + // Requires buckeyArray to be an array of arrays with a size equal to the range of values + // returned by the hash function. The hash function is required to return a unique value + // for each uniquely sorted element. Usually the way this is done is the elements are + // integers of a limited range (e.g. 0-64) and the hash function returns the element value + // itself. If you had a case where all elements were always even numbers (e.g. 0-128), + // you could use a custom hash function that returns (element value / 2). + // + // The user is required to provide an empty bucketArray to this function. This function returns + // with the bucketArray non-empty. This function doesn't clear the bucketArray because that takes + // time and the user might not need it to be cleared, at least at that time. + // + template + void bucket_sort(ForwardIterator first, ForwardIterator last, ContainerArray& bucketArray, HashFunction hash /*= hash_use_self*/) + { + for(ForwardIterator iInput = first; iInput != last; ++iInput) + bucketArray[hash(*iInput)].push_back(*iInput); + + for(typename ContainerArray::const_iterator iBucket = bucketArray.begin(); iBucket != bucketArray.end(); ++iBucket) + first = eastl::copy((*iBucket).begin(), (*iBucket).end(), first); + } + + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/bonus/sparse_matrix.h b/libs/eastl/include/EASTL/bonus/sparse_matrix.h new file mode 100644 index 0000000..a570085 --- /dev/null +++ b/libs/eastl/include/EASTL/bonus/sparse_matrix.h @@ -0,0 +1,1581 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// *** Note *** +// This implementation is incomplete. +// +// Additionally, this current implementation is not yet entirely in line with +// EASTL conventions and thus may appear a little out of place to the observant. +// The goal is to bring thus file up to current standards in a future version. +/////////////////////////////////////////////////////////////////////////////// + + +// To do: +// Remove forward declarations of classes. +// Remove mCol variable from matrix_cell. +// Make iterators have const and non-const versions. +// Remove mpCell from sparse_matrix_col_iterator. +// Remove mpRow from sparse_matrix_row_iterator. +// Remove mpMatrix from iterators. + + +/////////////////////////////////////////////////////////////////////////////// +// This file implements a sparse matrix, which is a 2 dimensional array of +// cells of an arbitrary type T. It is useful for situations where you need +// to store data in a very sparse way. The cost of storing an individual cell +// is higher than with a 2D array (or vector of vectors), but if the array is +// sparse, then a sparse matrix can save memory. It can also iterate non-empty +// cells faster than a regular 2D array, as only used cells are stored. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_SPARSE_MATRIX_H +#define EASTL_SPARSE_MATRIX_H + +#if 0 + +#include +#include +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + // kRowColIndexNone + // Refers to a row that is non-existant. If you call a function that returns a + // row or col index, and get kSparseMatrixIndexNone, the row or col doesn't exist. + static const int32_t kSparseMatrixIntMin = (-2147483647 - 1); + static const int32_t kSparseMatrixIntMax = 2147483647; + + + /////////////////////////////////////////////////////////////////////////////// + // Forward declarations + // + template struct matrix_cell; + template struct matrix_row; + template class sparse_matrix; + template class sparse_matrix_row_iterator; + template class sparse_matrix_col_iterator; + template class sparse_matrix_iterator; + + + + /////////////////////////////////////////////////////////////////////////////// + /// matrix_cell + /// + template + struct matrix_cell + { + public: + typedef matrix_cell this_type; + typedef T value_type; + + public: + int mCol; + value_type mValue; + + public: + matrix_cell(int nCol = 0); + matrix_cell(int nCol, const value_type& value); + + }; // matrix_cell + + + + /////////////////////////////////////////////////////////////////////////// + /// matrix_row + /// + template + struct matrix_row + { + public: + typedef Allocator allocator_type; + typedef matrix_row this_type; + typedef T value_type; + typedef matrix_cell cell_type; + typedef eastl::map, allocator_type> CellMap; + + public: + int mRow; + CellMap mCellRow; + + public: + matrix_row(int nRow = 0); + + // This function finds the given column in this row, if present. + // The result is a cell, and the pointer to the cell data itself + // is returned in the 'pCell' argument. + bool GetMatrixCol(int nCol, cell_type*& pCell); + + }; // matrix_row + + + + + /////////////////////////////////////////////////////////////////////////////// + /// sparse_matrix_row_iterator + /// + /// Iterates cells in a given row of a sparse matrix. + /// + template + class sparse_matrix_row_iterator + { + public: + typedef sparse_matrix_row_iterator this_type; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T& reference; + typedef T* pointer; + typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; + + typedef sparse_matrix MatrixType; + typedef matrix_row row_type; + typedef matrix_cell cell_type; + typedef eastl::map RowMap; + typedef typename row_type::CellMap CellMap; + + public: + MatrixType* mpMatrix; + row_type* mpRow; + typename CellMap::iterator mCellMapIterator; + + public: + sparse_matrix_row_iterator(MatrixType* pMatrix, row_type* pRow, const typename CellMap::iterator& ic) + : mpMatrix(pMatrix), mpRow(pRow), mCellMapIterator(ic) + { + } + + sparse_matrix_row_iterator(MatrixType* pMatrix = NULL) + : mpMatrix(pMatrix), mpRow(NULL) + { + } + + int GetCol() // Returns kSparseMatrixIntMin if iterator is 'empty'. We don't + { // return -1 because sparse matrix is not limited to rows/cols >= 0. + if(mpRow) // You can have a matrix that starts at column -100 and row -500. + { + const cell_type& cell = (*mCellMapIterator).second; + return cell.mCol; + } + return kSparseMatrixIntMin; + } + + int GetRow() + { + if(mpRow) + return mpRow->mRow; + return kSparseMatrixIntMin; + } + + bool operator==(const this_type& x) const + { + if(!mpRow && !x.mpRow) // If we are comparing 'empty' iterators... + return true; + + // The first check below wouldn't be necessary if we had a guarantee the iterators can compare between different rows. + return (mpRow == x.mpRow) && (mCellMapIterator == x.mCellMapIterator); + } + + bool operator!=(const this_type& x) const + { + return !operator==(x); + } + + reference operator*() const + { + const cell_type& cell = (*mCellMapIterator).second; + return cell.mValue; + } + + pointer operator->() const + { + const cell_type& cell = (*mCellMapIterator).second; + return &cell.mValue; + } + + this_type& operator++() + { + ++mCellMapIterator; + return *this; + } + + this_type operator++(int) + { + this_type tempCopy = *this; + ++*this; + return tempCopy; + } + + }; // sparse_matrix_row_iterator + + + + /////////////////////////////////////////////////////////////////////////////// + /// sparse_matrix_col_iterator + /// + /// Iterates cells in a given column of a sparse matrix. Do not modify the + /// sparse_matrix while iterating through it. You can do this with some + /// STL classes, but I'd rather not have to support this kind of code in + /// the future here. + /// + template + class sparse_matrix_col_iterator + { + public: + typedef sparse_matrix_col_iterator this_type; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T& reference; + typedef T* pointer; + typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; + + typedef sparse_matrix MatrixType; + typedef matrix_row row_type; + typedef matrix_cell cell_type; + typedef eastl::map RowMap; + typedef typename row_type::CellMap CellMap; + + public: + MatrixType* mpMatrix; + typename RowMap::iterator mRowMapIterator; + cell_type* mpCell; + + public: + sparse_matrix_col_iterator(MatrixType* pMatrix, const typename RowMap::iterator& i, cell_type* pCell) + : mpMatrix(pMatrix), mRowMapIterator(i), mpCell(pCell) + { + } + + sparse_matrix_col_iterator(MatrixType* pMatrix = NULL) + : mpMatrix(pMatrix), mpCell(NULL) + { + } + + int GetCol() // Returns kSparseMatrixIntMin if iterator is 'empty'. We don't return -1 + { // because sparse matrix is not limited to rows/cols >= 0. + if(mpCell) // You can have a matrix that starts at column -100 and row -500. + return mpCell->mCol; + return kSparseMatrixIntMin; + } + + int GetRow() + { + if(mpCell) // This might look strange, but we are using 'pCell' to + return (*mRowMapIterator).second.mRow; // simply tell us if the iterator is 'empty' or not. + return kSparseMatrixIntMin; + } + + bool operator==(const this_type& x) const + { + if(!mpCell && !x.mpCell) // If we are comparing 'empty' iterators... + return true; + + // The second check below wouldn't be necessary if we had a guarantee the iterators can compare between different maps. + return (mRowMapIterator == x.mRowMapIterator) && (mpCell == x.mpCell); + } + + bool operator!=(const this_type& x) const + { + return !operator==(x); + } + + reference operator*() const + { + return mpCell->mValue; + } + + reference operator->() const + { + return &mpCell->mValue; + } + + this_type& operator++() + { + ++mRowMapIterator; + + while(mRowMapIterator != mpMatrix->mRowMap.end()) + { + row_type& row = (*mRowMapIterator).second; + + // Can't we just use row.mCellRow.find(cell)? + typename CellMap::const_iterator it = row.mCellRow.find(mpCell->mCol); + + if(it != row.mCellRow.end()) + { + mpCell = const_cast(&(*it).second); // Trust me, we won't be modifying the data. + return *this; + } + + // Linear search: + //for(typename CellMap::iterator it(row.mCellRow.begin()); it != row.mCellRow.end(); ++it) + //{ + // const cell_type& cell = (*it).second; + // + // if(cell.mCol == mpCell->mCol) + // { + // mpCell = const_cast(&cell); // Trust me, we won't be modifying the data. + // return *this; + // } + //} + + ++mRowMapIterator; + } + + mpCell = NULL; + return *this; + } + + this_type operator++(int) + { + this_type tempCopy = *this; + ++*this; + return tempCopy; + } + + }; // sparse_matrix_col_iterator + + + + /////////////////////////////////////////////////////////////////////////////// + /// sparse_matrix_iterator + /// + /// Iterates cells of a sparse matrix, by rows and columns. Each row is iterated + /// and each column within that row is iterated in order. + /// + template + class sparse_matrix_iterator + { + public: + typedef sparse_matrix_iterator this_type; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T& reference; + typedef T* pointer; + typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; + + typedef sparse_matrix MatrixType; + typedef matrix_row row_type; + typedef matrix_cell cell_type; + typedef eastl::map RowMap; + typedef typename row_type::CellMap CellMap; + + public: + MatrixType* mpMatrix; + typename RowMap::iterator mRowMapIterator; + typename CellMap::iterator mCellMapIterator; + + public: + sparse_matrix_iterator(MatrixType* pMatrix, const typename RowMap::iterator& ir, const typename CellMap::iterator& ic) + : mpMatrix(pMatrix), mRowMapIterator(ir), mCellMapIterator(ic) + { + } + + sparse_matrix_iterator(MatrixType* pMatrix, const typename RowMap::iterator& ir) + : mpMatrix(pMatrix), mRowMapIterator(ir), mCellMapIterator() + { + } + + int GetCol() + { + const cell_type& cell = (*mCellMapIterator).second; + return cell.mCol; + } + + int GetRow() + { + const row_type& row = (*mRowMapIterator).second; + return row.mRow; + } + + bool operator==(const this_type& x) const + { + return (mRowMapIterator == x.mRowMapIterator) && (mCellMapIterator == x.mCellMapIterator); + } + + bool operator!=(const this_type& x) const + { + return (mRowMapIterator != x.mRowMapIterator) || (mCellMapIterator != x.mCellMapIterator); + } + + reference operator*() const + { + cell_type& cell = (*mCellMapIterator).second; + return cell.mValue; + } + + this_type& operator++() + { + ++mCellMapIterator; // Increment the current cell (column) in the current row. + + row_type& row = (*mRowMapIterator).second; + + if(mCellMapIterator == row.mCellRow.end()) // If we hit the end of the current row... + { + ++mRowMapIterator; + + while(mRowMapIterator != mpMatrix->mRowMap.end()) // While we haven't hit the end of rows... + { + row_type& row = (*mRowMapIterator).second; + + if(!row.mCellRow.empty()) // If there are any cells (columns) in this row... + { + mCellMapIterator = row.mCellRow.begin(); + break; + } + + ++mRowMapIterator; + } + } + + return *this; + } + + this_type operator++(int) + { + this_type tempCopy = *this; + operator++(); + return tempCopy; + } + + }; // sparse_matrix_iterator + + + + /////////////////////////////////////////////////////////////////////////////// + /// sparse_matrix + /// + template + class sparse_matrix + { + public: + typedef sparse_matrix this_type; + typedef T value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef ptrdiff_t difference_type; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef sparse_matrix_row_iterator row_iterator; + typedef sparse_matrix_col_iterator col_iterator; + typedef sparse_matrix_iterator iterator; + typedef sparse_matrix_iterator const_iterator; // To do: Fix this. + typedef Allocator allocator_type; + typedef matrix_row row_type; + typedef typename row_type::CellMap CellMap; + typedef eastl::map RowMap; + + // iterator friends + friend class sparse_matrix_row_iterator; + friend class sparse_matrix_col_iterator; + friend class sparse_matrix_iterator; + + // kRowColIndexNone + static const int32_t kRowColIndexNone = kSparseMatrixIntMin; + + // UserCell + // We don't internally use this struct to store data, because that would + // be inefficient. However, whenever the user of this class needs to query for + // individual cells, especially in batches, it is useful to have a struct that + // identifies both the cell coordinates and cell data for the user. + struct UserCell + { + int mCol; + int mRow; + T mValue; + }; + + public: + sparse_matrix(); + sparse_matrix(const sparse_matrix& x); + ~sparse_matrix(); + + this_type& operator=(const this_type& x); + + void swap(); + + // Iterators + row_iterator row_begin(int nRow); + row_iterator row_end(int nRow); + col_iterator col_begin(int nCol); + col_iterator col_end(int nCol); + iterator begin(); + iterator end(); + + // Standard interface functions + bool empty() const; // Returns true if no cells are used. + size_type size() const; // Returns total number of non-empty cells. + + int GetMinUsedRow(int& nResultCol) const; // Returns first row that has data. Fills in column that has that data. Returns kRowUnused if no row has data. + int GetMaxUsedRow(int& nResultCol) const; // Returns last row that has data. Fills in column that has that data. Returns kRowUnused if no row has data. + bool GetMinMaxUsedColForRow(int nRow, int& nMinCol, int& nMaxCol) const; // Sets the min and max column and returns true if any found. + bool GetMinMaxUsedRowForCol(int nCol, int& nMinRow, int& nMaxRow) const; // Sets the min and max row and returns true if any found. + size_type GetColCountForRow(int nRow) const; // You specify the row, it gives you the used cell count. + + int GetMinUsedCol(int& nResultRow) const; // Returns first column that has data. Fills in row that has that data. Returns kColUnused if no column has data. + int GetMaxUsedCol(int& nResultRow) const; // Returns last column that has data. Fills in row that has that data. Returns kColUnused if no column has data. + size_type GetRowCountForCol(int nCol) const; // + int GetRowWithMaxColCount(size_type& nColCount) const; // + + bool remove(int nRow, int nCol, T* pPreviousT = NULL); // If you pass in a 'pPreviousT', it will copy in value to it before removing the cell. + bool remove_row(int nRow, size_type nCount = 1); // Removes 'nCount' rows, starting at 'nRow'. + bool remove_col(int nCol, size_type nCount = 1); // Removes 'nCount' cols, starting at 'nCol'. + bool clear(); // Removes all cells. + void insert(int nRow, int nCol, const value_type& t, value_type* pPrevValue = NULL); // If you pass in a 'pPreviousT', it will copy in value to it before changing the cell. + bool IsCellUsed(int nRow, int nCol); // Returns true if cell is non-empty + + bool GetCell(int nRow, int nCol, value_type* pValue = NULL); // + bool GetCellPtr(int nRow, int nCol, value_type** pValue); // Gets a pointer to the cell itself, for direct manipulation. + size_type GetCellCountForRange(int nRowStart, int nRowEnd, + int nColStart, int nColEnd); // Counts cells in range. Range is inclusive. + int GetCellRange(int nRowStart, int nRowEnd, + int nColStart, int nColEnd, UserCell* pCellArray = NULL); // Copies cell data into the array of UserCells provided by the caller. + int FindCell(const value_type& t, UserCell* pCellArray = NULL); // Finds all cells that match the given argument cell. Call this function with NULL pCellArray to simply get the count. + + bool validate(); + int validate_iterator(const_iterator i) const; + + protected: + bool GetMatrixRow(int nRow, row_type*& pRow); + + protected: + RowMap mRowMap; /// Map of all row data. It is a map of maps. + size_type mnSize; /// The count of all cells. This is equal to the sums of the sizes of the maps in mRowMap. + allocator_type mAllocator; /// The allocator for all data. + + }; // sparse_matrix + + + + + + + + /////////////////////////////////////////////////////////////////////////////// + // matrix_cell + /////////////////////////////////////////////////////////////////////////////// + + template + matrix_cell::matrix_cell(int nCol = 0) + : mCol(nCol), mValue() + { + } + + template + matrix_cell::matrix_cell(int nCol, const value_type& value) + : mCol(nCol), mValue(value) + { + } + + + + + /////////////////////////////////////////////////////////////////////////////// + // matrix_row + /////////////////////////////////////////////////////////////////////////////// + + template + matrix_row::matrix_row(int nRow = 0) + : mRow(nRow), mCellRow() + { + } + + template + bool matrix_row::GetMatrixCol(int nCol, cell_type*& pCell) + { + #if EASTL_ASSERT_ENABLED + int nPreviousCol(sparse_matrix::kRowColIndexNone); + EASTL_ASSERT((nCol < kSparseMatrixIntMax / 2) && (nCol > kSparseMatrixIntMin / 2)); + #endif + + typename CellMap::iterator it(mCellRow.find(nCol)); + + if(it != mCellRow.end()) + { + cell_type& cell = (*it).second; + pCell = &cell; + return true; + } + + return false; + } + + template + inline bool operator==(const matrix_row& a, const matrix_row& b) + { + return (a.mRow == b.mRow) && (a.mCellRow == b.mCellRow); + } + + template + inline bool operator==(const matrix_cell& a, const matrix_cell& b) + { + return (a.mValue == b.mValue); + } + + + + + /////////////////////////////////////////////////////////////////////////////// + // sparse_matrix + /////////////////////////////////////////////////////////////////////////////// + + template + inline sparse_matrix::sparse_matrix() + : mRowMap(), mnSize(0) + { + } + + + template + inline sparse_matrix::sparse_matrix(const this_type& x) + { + mnSize = x.mnSize; + mRowMap = x.mRowMap; + } + + + template + inline sparse_matrix::~sparse_matrix() + { + // Nothing to do. + } + + + template + inline typename sparse_matrix::this_type& + sparse_matrix::operator=(const this_type& x) + { + // Check for self-asignment is not needed, as the assignments below already do it. + mnSize = x.mnSize; + mRowMap = x.mRowMap; + return *this; + } + + + template + inline void sparse_matrix& sparse_matrix::swap() + { + eastl::swap(mnSize, x.mnSize); + eastl::swap(mRowMap, x.mRowMap); + } + + + template + inline bool sparse_matrix::empty() const + { + return (mnSize == 0); + } + + + template + inline typename sparse_matrix::size_type + sparse_matrix::size() const + { + return mnSize; + } + + + /////////////////////////////////////////////////////////////////////////////// + // row_begin + // + // This function returns a sparse matrix row iterator. It allows you to + // iterate all used cells in a given row. You pass in the row index and it + // returns an iterator for the first used cell. You can dereference the + // iterator to get the cell data. Just like STL containers, the end iterator + // is one-past the past the last valid iterator. A row iterator returned + // by this function is good only for that row; likewise, you can only use + // such a row iterator with the end iterator for that row and not with an + // end iterator for any other row. + // + // Here is an example of using a row iterator to iterate all used cells + // in row index 3 of a sparse matrix of 'int': + // sparse_matrix::row_iterator it = intMatrix.row_begin(3); + // sparse_matrix::row_iterator itEnd = intMatrix.row_end(3); + // + // while(it != itEnd) + // { + // printf("Col=%d, row=%d, value=%d\n", it.GetCol(), it.GetRow(), *it); + // ++it; + // } + // + template + typename sparse_matrix::row_iterator + sparse_matrix::row_begin(int nRow) + { + EASTL_ASSERT((nRow < kSparseMatrixIntMax / 2) && (nRow > kSparseMatrixIntMin / 2)); + + row_type* pRow; + + if(GetMatrixRow(nRow, pRow)) + return sparse_matrix_row_iterator(this, pRow, pRow->mCellRow.begin()); + return sparse_matrix_row_iterator(this); //Create an 'empty' iterator. + } + + + /////////////////////////////////////////////////////////////////////////////// + // row_end + // + // Returns the end iterator for a given row. See the row_begin function for more. + // + template + inline typename sparse_matrix::row_iterator + sparse_matrix::row_end(int nRow) + { + EASTL_ASSERT((nRow < kSparseMatrixIntMax / 2) && (nRow > kSparseMatrixIntMin / 2)); + + row_type* pRow; + + if(GetMatrixRow(nRow, pRow)) + return sparse_matrix_row_iterator(this, pRow, pRow->mCellRow.end()); + return sparse_matrix_row_iterator(this); //Create an 'empty' iterator. + } + + + /////////////////////////////////////////////////////////////////////////////// + // col_begin + // + // This function returns a sparse matrix column iterator. A column iterator + // acts just like a row iterator except it iterates cells in a column instead + // of cells in a row. + // + // Here is an example of using a column iterator to iterate all used cells + // in column index 0 (the first column) of a sparse matrix of 'int': + // sparse_matrix::col_iterator it = intMatrix.col_begin(0); + // sparse_matrix::col_iterator itEnd = intMatrix.col_end(0); + // + // while(it != itEnd) + // { + // printf("Col=%d, row=%d, value=%d\n", it.GetCol(), it.GetRow(), *it); + // ++it; + // } + // + template + typename sparse_matrix::col_iterator + sparse_matrix::col_begin(int nCol) + { + EASTL_ASSERT((nCol < kSparseMatrixIntMax / 2) && (nCol > kSparseMatrixIntMin / 2)); + + for(typename RowMap::iterator it(mRowMap.begin()); it != mRowMap.end(); ++it) + { + const row_type& matrixRowConst = (*it).second; + row_type& row = const_cast(matrixRowConst); + + for(typename CellMap::iterator it1(row.mCellRow.begin()); it1!=row.mCellRow.end(); ++it1) + { + const cell_type& cellConst = (*it1).second; + cell_type& cell = const_cast(cellConst); + + if(cell.mCol == nCol) + return sparse_matrix_col_iterator(this, it, &cell); + } + } + return sparse_matrix_col_iterator(this, mRowMap.end(), NULL); + } + + + /////////////////////////////////////////////////////////////////////////////// + // col_end + // + // Returns the end iterator for a given colum. See the col_begin function for more. + // + template + inline typename sparse_matrix::col_iterator + sparse_matrix::col_end(int nCol) + { + EASTL_ASSERT((nCol < kSparseMatrixIntMax / 2) && (nCol > kSparseMatrixIntMin / 2)); + + return sparse_matrix_col_iterator(this, mRowMap.end(), NULL); + } + + + /////////////////////////////////////////////////////////////////////////////// + // begin + // + // This function returns a sparse matrix cell iterator. It iterates all used + // cells in the sparse matrix. The cells are returned in column,row order + // (as opposed to row,column order). Thus, all columns for a given row will + // be iterated before moving onto the next row. + // + // Here is an example of using an iterator to iterate all used cells: + // sparse_matrix::iterator it = intMatrix.begin(); + // sparse_matrix::iterator itEnd = intMatrix.end(); + // + // while(it != itEnd) + // { + // printf("Col=%d, row=%d, value=%d\n", it.GetCol(), it.GetRow(), *it); + // ++it; + // } + // + template + typename sparse_matrix::iterator + sparse_matrix::begin() + { + for(typename RowMap::iterator it(mRowMap.begin()); it != mRowMap.end(); ++it) + { + row_type& row = (*it).second; + + if(!row.mCellRow.empty()) + return sparse_matrix_iterator(this, it, row.mCellRow.begin()); + } + return sparse_matrix_iterator(this, mRowMap.end()); + } + + + template + inline typename sparse_matrix::iterator + sparse_matrix::end() + { + return sparse_matrix_iterator(this, mRowMap.end()); + } + + + template + int sparse_matrix::GetMinUsedRow(int& nResultCol) const + { + if(!mRowMap.empty()) + { + const row_type& row = (*mRowMap.begin()).second; // Get the last row. + const cell_type& cell = (*row.mCellRow.begin()).second; // Get the first cell in that row, though it doesn't really matter which one we get. + + nResultCol = cell.mCol; + + return row.mRow; // Return the row of the last item in the map. + } + + nResultCol = kRowColIndexNone; + return kRowColIndexNone; + } + + + template + int sparse_matrix::GetMaxUsedRow(int& nResultCol) const + { + if(!mRowMap.empty()) + { + const row_type& row = (*mRowMap.rbegin()).second; // Get the last row. + const cell_type& cell = (*row.mCellRow.begin()).second; // Get the first cell in that row, though it doesn't really matter which one we get. + + nResultCol = cell.mCol; + + return row.mRow; // Return the row of the last item in the map. + } + + nResultCol = kRowColIndexNone; + return kRowColIndexNone; + } + + + template + bool sparse_matrix::GetMinMaxUsedColForRow(int nRow, int& nMinCol, int& nMaxCol) const + { + bool bReturnValue(false); + + EASTL_ASSERT((nRow < kSparseMatrixIntMax / 2) && (nRow > kSparseMatrixIntMin / 2)); + + nMinCol = kSparseMatrixIntMax; + nMaxCol = kSparseMatrixIntMin; + + typename RowMap::iterator it(mRowMap.find(nRow)); + + if(it != mRowMap.end()) + { + const row_type& row = (*it).second; + EASTL_ASSERT(!row.mCellRow.empty()); // All rows should have at least one col, or we would have removed it. + + const cell_type& matrixCellFront = (*row.mCellRow.begin()).second; + const cell_type& matrixCellBack = (*row.mCellRow.rbegin()).second; + + nMinCol = matrixCellFront.mCol; + nMaxCol = matrixCellBack.mCol; + + bReturnValue = true; + } + + return bReturnValue; + } + + + /////////////////////////////////////////////////////////////////////////////// + // GetMinMaxUsedRowForCol + // + template + bool sparse_matrix::GetMinMaxUsedRowForCol(int nCol, int& nMinRow, int& nMaxRow) const + { + // The implementation of this function is a little tougher than with the "col for row" version of + // this function, since the data is stored in row maps instead of column maps. + bool bReturnValue(false); + + EASTL_ASSERT((nCol < kSparseMatrixIntMax / 2) && (nCol > kSparseMatrixIntMin / 2)); + + nMinRow = kSparseMatrixIntMax; + nMaxRow = kSparseMatrixIntMin; + + //First search for the min row. + for(typename RowMap::iterator it(mRowMap.begin()); it != mRowMap.end(); ++it) + { + row_type& row = (*it).second; + EASTL_ASSERT(!row.mCellRow.empty()); // All rows should have at least one col, or we would have removed the row. + + // Find the given column in this row. If present work on it. + typename CellMap::iterator it1(row.mCellRow.find(nCol)); + + if(it1 != row.mCellRow.end()) + { + nMinRow = row.mRow; + nMaxRow = row.mRow; + bReturnValue = true; + break; + } + } + + // Now search for a max row. + if(bReturnValue) // There can only be a max row if there was also a min row. + { + for(typename RowMap::reverse_iterator it(mRowMap.rbegin()); it != mRowMap.rend(); ++it) + { + row_type& row = (*it).second; + EASTL_ASSERT(!row.mCellRow.empty()); // All rows should have at least one col, or we would have removed the row. + + // Find the given column in this row. If present work on it. + typename CellMap::iterator it1(row.mCellRow.find(nCol)); + + if(it1 != row.mCellRow.end()) + { + nMaxRow = row.mRow; + break; + } + } + } + + return bReturnValue; + } + + + /////////////////////////////////////////////////////////////////////////////// + // GetColCountForRow + // + template + typename sparse_matrix::size_type + sparse_matrix::GetColCountForRow(int nRow) const + { + EASTL_ASSERT((nRow < kSparseMatrixIntMax / 2) && (nRow > kSparseMatrixIntMin / 2)); + + row_type* pRow; + + if(GetMatrixRow(nRow, pRow)) + return (size_type)pRow->mCellRow.size(); + return 0; + } + + + /////////////////////////////////////////////////////////////////////////////// + // GetMinUsedCol + // + template + int sparse_matrix::GetMinUsedCol(int& nResultRow) const + { + int nMinCol = kRowColIndexNone; + nResultRow = kRowColIndexNone; + + for(typename RowMap::iterator it(mRowMap.begin()); it != mRowMap.end(); ++it) + { + row_type& row = (*it).second; + EASTL_ASSERT(!row.mCellRow.empty()); // All rows should have at least one col, or we would have removed it. + + const cell_type& cell = (*row.mCellRow.begin()).second; + + if((cell.mCol < nMinCol) || (nMinCol == kRowColIndexNone)) + { + nMinCol = cell.mCol; + nResultRow = row.mRow; + } + } + + return nMinCol; + } + + + /////////////////////////////////////////////////////////////////////////////// + // GetMaxUsedCol + // + template + int sparse_matrix::GetMaxUsedCol(int& nResultRow) const + { + int nMaxCol = kRowColIndexNone; + nResultRow = kRowColIndexNone; + + for(typename RowMap::iterator it(mRowMap.begin()); it != mRowMap.end(); ++it) + { + row_type& row = (*it).second; + EASTL_ASSERT(!row.mCellRow.empty()); // All rows should have at least one col, or we would have removed it. + + const cell_type& cell = (*row.mCellRow.rbegin()).second; + + if((cell.mCol > nMaxCol) || (nMaxCol == kRowColIndexNone)) + { + nMaxCol = cell.mCol; + nResultRow = row.mRow; + } + } + + return nMaxCol; + } + + + /////////////////////////////////////////////////////////////////////////////// + // GetRowCountForCol + // + template + typename sparse_matrix::size_type + sparse_matrix::GetRowCountForCol(int nCol) const + { + EASTL_ASSERT((nCol < kSparseMatrixIntMax / 2) && (nCol > kSparseMatrixIntMin / 2)); + + size_type nRowCount = 0; + + for(typename RowMap::iterator it(mRowMap.begin()); it != mRowMap.end(); ++it) + { + row_type& row = (*it).second; + EASTL_ASSERT(!row.mCellRow.empty()); + + //Faster set-based code: + typename CellMap::iterator it1(row.mCellRow.find(nCol)); + if(it1 != row.mCellRow.end()) + nRowCount++; + } + + return nRowCount; + } + + + /////////////////////////////////////////////////////////////////////////////// + // GetRowWithMaxColCount + // + template + int sparse_matrix::GetRowWithMaxColCount(size_type& nColCount) const + { + int nRow = 0; + nColCount = 0; + + for(typename RowMap::iterator it(mRowMap.begin()); it != mRowMap.end(); ++it) + { + const row_type& row = (*it).second; + const size_type nSize(row.mCellRow.size()); + EASTL_ASSERT(nSize != 0); + + if(nSize > (size_type)nColCount) + { + nRow = row.mRow; + nColCount = nSize; + } + } + return nRow; + } + + + /////////////////////////////////////////////////////////////////////////// + // GetCellCountForRange + // + template + typename sparse_matrix::size_type + sparse_matrix::GetCellCountForRange(int nRowStart, int nRowEnd, int nColStart, int nColEnd) const + { + size_type nCellCount(0); + + // Note by Paul P.: This could be made a little faster by doing a search + // for the first row and iterating the container from then on. + for(typename RowMap::iterator it(mRowMap.begin()); it != mRowMap.end(); ++it) + { + row_type& row = (*it).second; + + if(row.mRow < nRowStart) + continue; + + if(row.mRow > nRowEnd) + break; + + for(typename CellMap::iterator it1(row.mCellRow.begin()); it1 != row.mCellRow.end(); ++it1) + { + const cell_type& cell = (*it1).second; + + if(cell.mCol < nColStart) + continue; + + if(cell.mCol > nColEnd) + break; + + nCellCount++; + } + } + + return nCellCount; + } + + + /////////////////////////////////////////////////////////////////////////////// + // GetCellRange + // + template + int sparse_matrix::GetCellRange(int nRowStart, int nRowEnd, + int nColStart, int nColEnd, UserCell* pCellArray) const + { + int nCellCount(0); + + // Note by Paul P.: This could be made a little faster by doing a search + // for the first row and iterating the container from then on. + + for(typename RowMap::iterator it(mRowMap.begin()); it != mRowMap.end(); ++it) + { + row_type& row = (*it).second; + + if(row.mRow < nRowStart) + continue; + if(row.mRow > nRowEnd) + break; + + for(typename CellMap::iterator it1(row.mCellRow.begin()); it1 != row.mCellRow.end(); ++it1) + { + const cell_type& cell = (*it1).second; + + if(cell.mCol < nColStart) + continue; + + if(cell.mCol > nColEnd) + break; + + if(pCellArray) + { + pCellArray[nCellCount].mCol = cell.mCol; + pCellArray[nCellCount].mRow = row.mRow; + pCellArray[nCellCount].mValue = cell.mValue; + } + + nCellCount++; + } + } + + return nCellCount; + } + + + /////////////////////////////////////////////////////////////////////////////// + // remove + // + template + bool sparse_matrix::remove(int nRow, int nCol, T* pPreviousT) + { + EASTL_ASSERT((nCol < kSparseMatrixIntMax / 2) && (nCol > kSparseMatrixIntMin / 2)); + EASTL_ASSERT((nRow < kSparseMatrixIntMax / 2) && (nRow > kSparseMatrixIntMin / 2)); + + //Faster map-based technique: + typename RowMap::iterator it(mRowMap.find(nRow)); + + if(it != mRowMap.end()) + { + row_type& row = (*it).second; + + typename CellMap::iterator it1(row.mCellRow.find(nCol)); + + if(it1 != row.mCellRow.end()) + { + cell_type& cell = (*it1).second; + + if(pPreviousT) + *pPreviousT = cell.mValue; + row.mCellRow.erase(it1); + mnSize--; + + if(row.mCellRow.empty()) // If the row is now empty and thus has no more columns... + mRowMap.erase(it); // Remove the row from the row map. + return true; + } + } + + return false; + } + + + /////////////////////////////////////////////////////////////////////////////// + // remove_row + // + template + bool sparse_matrix::remove_row(int nRow, size_type nCount) + { + EASTL_ASSERT((nRow < kSparseMatrixIntMax / 2) && (nRow > kSparseMatrixIntMin / 2)); + + // Faster map-based technique: + for(int i(nRow), iEnd(nRow + (int)nCount); i < iEnd; i++) + { + typename RowMap::iterator it(mRowMap.find(i)); + + if(it != mRowMap.end()) // If the row is present... + { + row_type& row = (*it).second; + + mnSize -= row.mCellRow.size(); + mRowMap.erase(it); + } + } + + return true; + } + + + /////////////////////////////////////////////////////////////////////////////// + // remove_col + // + template + bool sparse_matrix::remove_col(int nCol, size_type nCount) + { + EASTL_ASSERT((nCol < kSparseMatrixIntMax / 2) && (nCol > kSparseMatrixIntMin / 2)); + + // Faster map-based version: + for(typename RowMap::iterator it(mRowMap.begin()); it != mRowMap.end(); ) // For each row... + { + row_type& row = (*it).second; + + for(int i(nCol), iEnd(nCol + (int)nCount); i < iEnd; i++) + { + typename CellMap::iterator it1(row.mCellRow.find(i)); + + if(it1 != row.mCellRow.end()) // If the col is present... + { + row.mCellRow.erase(it1); + mnSize--; + } + } + + if(row.mCellRow.empty()) + mRowMap.erase(it++); + else + ++it; + } + + return true; + } + + + template + inline bool sparse_matrix::clear() + { + mRowMap.clear(); // Clear out the map of maps. + mnSize = 0; + return true; + } + + + template + void sparse_matrix::insert(int nRow, int nCol, const T& t, T* pPreviousT) + { + EASTL_ASSERT((nCol < kSparseMatrixIntMax / 2) && (nCol > kSparseMatrixIntMin / 2)); + EASTL_ASSERT((nRow < kSparseMatrixIntMax / 2) && (nRow > kSparseMatrixIntMin / 2)); + + typename RowMap::iterator it(mRowMap.find(nRow)); + + if(it != mRowMap.end()) // If the row is already present... + { + row_type& row = (*it).second; + + typename CellMap::iterator it1(row.mCellRow.find(nCol)); + + if(it1 != row.mCellRow.end()) // If the col is already present... + { + cell_type& cell = (*it1).second; + + if(pPreviousT) + *pPreviousT = cell.mValue; + cell.mValue = t; + // Note that we leave 'mnSize' as is. + } + else + { + const typename CellMap::value_type insertionPair(nCol, cell_type(nCol, t)); + row.mCellRow.insert(insertionPair); + mnSize++; + } + } + else // Else the row doesn't exist (and the column in that row doesn't exist either). + { + const typename RowMap::value_type insertionPair(nRow, row_type(nRow)); + + eastl::pair insertionResult = mRowMap.insert(insertionPair); + row_type& row = (*insertionResult.first).second; + + EASTL_ASSERT(row.mRow == nRow); // Make sure we are now on the row we just inserted. + const typename CellMap::value_type insertionPair1(nCol, cell_type(nCol, t)); + row.mCellRow.insert(insertionPair1); // Now add the new cell to the new row. + mnSize++; + } + } + + + template + bool sparse_matrix::IsCellUsed(int nRow, int nCol) + { + EASTL_ASSERT((nCol < kSparseMatrixIntMax / 2) && (nCol > kSparseMatrixIntMin / 2)); + EASTL_ASSERT((nRow < kSparseMatrixIntMax / 2) && (nRow > kSparseMatrixIntMin / 2)); + + typename RowMap::iterator it(mRowMap.find(nRow)); + + if(it != mRowMap.end()) + { + row_type& row = (*it).second; + + typename CellMap::iterator it1(row.mCellRow.find(nCol)); + if(it1 != row.mCellRow.end()) + return true; + } + + return false; + } + + + template + bool sparse_matrix::GetCell(int nRow, int nCol, T* pT) + { + EASTL_ASSERT((nCol < kSparseMatrixIntMax / 2) && (nCol > kSparseMatrixIntMin / 2)); + + row_type* pRow; + cell_type* pCell; + + if(GetMatrixRow(nRow, pRow)) + { + if(pRow->GetMatrixCol(nCol, pCell)) + { + if(pT) + *pT = pCell->mValue; + return true; + } + } + + return false; + } + + + template + bool sparse_matrix::GetCellPtr(int nRow, int nCol, T** pT) + { + EASTL_ASSERT((nCol < kSparseMatrixIntMax / 2) && (nCol > kSparseMatrixIntMin / 2)); + + row_type* pRow; + cell_type* pCell; + + if(GetMatrixRow(nRow, pRow)) + { + if(pRow->GetMatrixCol(nCol, pCell)) + { + if(pT) + *pT = &pCell->mValue; + return true; + } + } + + return false; + } + + + template + bool sparse_matrix::GetMatrixRow(int nRow, row_type*& pRow) + { + EASTL_ASSERT((nRow < kSparseMatrixIntMax / 2) && (nRow > kSparseMatrixIntMin / 2)); + + typename RowMap::iterator it(mRowMap.find(nRow)); + + if(it != mRowMap.end()) + { + row_type& row = (*it).second; + pRow = &row; + return true; + } + + return false; + } + + + /////////////////////////////////////////////////////////////////////////////// + // FindCell + // + // Searches all cells for a match for input data 't'. Writes the cell data into + // the user celldata array. Call with a NULL pCellArray to get the count. + // + // This is a simple search function. Many real-world applications would need a + // slightly more flexible search function or mechanism. + // + template + int sparse_matrix::FindCell(const T& t, UserCell* pCellArray) + { + int nCount(0); + + for(typename RowMap::iterator it(mRowMap.begin()); it != mRowMap.end(); ++it) + { + row_type& row = (*it).second; + + for(typename CellMap::iterator it1(row.mCellRow.begin()); it1 != row.mCellRow.end(); ++it1) + { + cell_type& cell = (*it1).second; + + if(cell.mValue == t) + { + if(pCellArray) + { + UserCell& cell = pCellArray[nCount]; + + cell.mCol = cell.mCol; + cell.mRow = row.mRow; + cell.mValue = t; + } + nCount++; + } + } + } + + return nCount; + } + + + /////////////////////////////////////////////////////////////////////////////// + // validate + // + template + bool sparse_matrix::validate() + { + int nPreviousCol; + int nPreviousRow = kRowColIndexNone; + size_type nActualTotalCells = 0; + + for(typename RowMap::iterator it(mRowMap.begin()); it != mRowMap.end(); ++it) + { + row_type& row = (*it).second; + + if(row.mCellRow.empty()) + { + // EASTL_TRACE("sparse_matrix::validate(): Error: Empty Cell Row %d.\n", row.mRow); + return false; + } + + nPreviousCol = kRowColIndexNone; + + for(typename CellMap::iterator it1(row.mCellRow.begin()); it1 != row.mCellRow.end(); ++it1) + { + cell_type& cell = (*it1).second; + + if(cell.mCol <= nPreviousCol) + { + // EASTL_TRACE("sparse_matrix::validate(): Error: Columns out of order in row, col: %d, %d.\n", row.mRow, cell.mCol); + return false; + } + + nPreviousCol = cell.mCol; + nActualTotalCells++; + } + + if(row.mRow <= nPreviousRow) + { + // EASTL_TRACE("sparse_matrix::validate(): Error: Rows out of order at row: %d.\n", row.mRow); + return false; + } + + nPreviousRow = row.mRow; + } + + if(mnSize != nActualTotalCells) + { + // EASTL_TRACE("sparse_matrix::validate(): Error: 'mnSize' != counted cells %d != %d\n", mnSize, nActualTotalCells); + return false; + } + + return true; + } + + + template + int sparse_matrix::validate_iterator(const_iterator i) const + { + // To do: Complete this. The value below is a potential false positive. + return (isf_valid | isf_current | isf_can_dereference); + } + + + + + /////////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////////// + + template + bool operator==(sparse_matrix& a, sparse_matrix& b) + { + return (a.mRowMap == b.mRowMap); + } + + template + bool operator<(sparse_matrix& a, sparse_matrix& b) + { + return (a.mRowMap < b.mRowMap); + } + + template + bool operator!=(sparse_matrix& a, sparse_matrix& b) + { + return !(a.mRowMap == b.mRowMap); + } + + template + bool operator>(sparse_matrix& a, sparse_matrix& b) + { + return (b.mRowMap < a.mRowMap); + } + + template + bool operator<=(sparse_matrix& a, sparse_matrix& b) + { + return !(b.mRowMap < a.mRowMap); + } + + template + bool operator>=(sparse_matrix& a, sparse_matrix& b) + { + return !(a.mRowMap < b.mRowMap); + } + + template + void swap(sparse_matrix& a, sparse_matrix& b) + { + a.swap(b); + } + + + +} // namespace eastl + +#endif + +#endif // Header include guard + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/bonus/string_abstract.h b/libs/eastl/include/EASTL/bonus/string_abstract.h new file mode 100644 index 0000000..6a994dc --- /dev/null +++ b/libs/eastl/include/EASTL/bonus/string_abstract.h @@ -0,0 +1,3825 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Implements a basic_string class, much like the C++ std::basic_string. +// The primary distinctions between basic_string and std::basic_string are: +// - basic_string has a few extension functions that allow for increased performance. +// - basic_string has a few extension functions that make use easier, +// such as a member sprintf function and member tolower/toupper functions. +// - basic_string supports debug memory naming natively. +// - basic_string is easier to read, debug, and visualize. +// - basic_string internally manually expands basic functions such as begin(), +// size(), etc. in order to improve debug performance and optimizer success. +// - basic_string is savvy to an environment that doesn't have exception handling, +// as is sometimes the case with console or embedded environments. +// - basic_string has less deeply nested function calls and allows the user to +// enable forced inlining in debug builds in order to reduce bloat. +// - basic_string doesn't use char traits. As a result, EASTL assumes that +// strings will hold characters and not exotic things like widgets. At the +// very least, basic_string assumes that the value_type is a POD. +// - basic_string::size_type is defined as eastl_size_t instead of size_t in +// order to save memory and run faster on 64 bit systems. +// - basic_string data is guaranteed to be contiguous. +// - basic_string data is guaranteed to be 0-terminated, and the c_str() function +// is guaranteed to return the same pointer as the data() which is guaranteed +// to be the same value as &string[0]. +// - basic_string has a set_capacity() function which frees excess capacity. +// The only way to do this with std::basic_string is via the cryptic non-obvious +// trick of using: basic_string(x).swap(x); +// - basic_string has a force_size() function, which unilaterally moves the string +// end position (mpEnd) to the given location. Useful for when the user writes +// into the string via some extenal means such as C strcpy or sprintf. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Copy on Write (cow) +// +// This string implementation does not do copy on write (cow). This is by design, +// as cow penalizes 95% of string uses for the benefit of only 5% of the uses +// (these percentages are qualitative, not quantitative). The primary benefit of +// cow is that it allows for the sharing of string data between two string objects. +// Thus if you say this: +// string a("hello"); +// string b(a); +// the "hello" will be shared between a and b. If you then say this: +// a = "world"; +// then a will release its reference to "hello" and leave b with the only reference +// to it. Normally this functionality is accomplished via reference counting and +// with atomic operations or mutexes. +// +// The C++ standard does not say anything about basic_string and cow. However, +// for a basic_string implementation to be standards-conforming, a number of +// issues arise which dictate some things about how one would have to implement +// a cow string. The discussion of these issues will not be rehashed here, as you +// can read the references below for better detail than can be provided in the +// space we have here. However, we can say that the C++ standard is sensible and +// that anything we try to do here to allow for an efficient cow implementation +// would result in a generally unacceptable string interface. +// +// The disadvantages of cow strings are: +// - A reference count needs to exist with the string, which increases string memory usage. +// - With thread safety, atomic operations and mutex locks are expensive, especially +// on weaker memory systems such as console gaming platforms. +// - All non-const string accessor functions need to do a sharing check the the +// first such check needs to detach the string. Similarly, all string assignments +// need to do a sharing check as well. If you access the string before doing an +// assignment, the assignment doesn't result in a shared string, because the string +// has already been detached. +// - String sharing doesn't happen the large majority of the time. In some cases, +// the total sum of the reference count memory can exceed any memory savings +// gained by the strings that share representations. +// +// The addition of a string_cow class is under consideration for this library. +// There are conceivably some systems which have string usage patterns which would +// benefit from cow sharing. Such functionality is best saved for a separate string +// implementation so that the other string uses aren't penalized. +// +// References: +// This is a good starting HTML reference on the topic: +// http://www.gotw.ca/publications/optimizations.htm +// Here is a Usenet discussion on the topic: +// http://groups-beta.google.com/group/comp.lang.c++.moderated/browse_thread/thread/3dc6af5198d0bf7/886c8642cb06e03d +// +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_STRING_ABSTRACT_H +#define EASTL_STRING_ABSTRACT_H + + +#include +#include +#include +#include + +#ifdef _MSC_VER + #pragma warning(push, 0) +#endif +#include // size_t, ptrdiff_t, etc. +#include // vararg functionality. +#include // malloc, free. +#include // snprintf, etc. +#include // toupper, etc. +#include // toupper, etc. + #include // strlen, etc. +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#if EASTL_EXCEPTIONS_ENABLED + #ifdef _MSC_VER + #pragma warning(push, 0) + #endif + #include // std::out_of_range, std::length_error. + #ifdef _MSC_VER + #pragma warning(pop) + #endif +#endif + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4530) // C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc + #pragma warning(disable: 4267) // 'argument' : conversion from 'size_t' to 'const uint32_t', possible loss of data. This is a bogus warning resulting from a bug in VC++. + #pragma warning(disable: 4480) // nonstandard extension used: specifying underlying type for enum + #pragma warning(disable: 4571) // catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught. +#endif + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_ABSTRACT_STRING_ENABLED +// +// Defined as 0 or 1. Default is 0 until abstract string is fully tested. +// Used during development of abstract_string to detect its presence or absence. +// +#ifndef EASTL_ABSTRACT_STRING_ENABLED + #define EASTL_ABSTRACT_STRING_ENABLED 1 +#endif +/////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_STRING_EXPLICIT +// +// See EASTL_STRING_OPT_EXPLICIT_CTORS for documentation. +// +#if EASTL_STRING_OPT_EXPLICIT_CTORS + #define EASTL_STRING_EXPLICIT explicit +#else + #define EASTL_STRING_EXPLICIT +#endif +/////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_STRING_INITIAL_CAPACITY +// +// As of this writing, this must be > 0. Note that an initially empty string +// has a capacity of zero (it allocates no memory). +// +const eastl_size_t EASTL_STRING_INITIAL_CAPACITY = 8; +/////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////// +// Vsnprintf8 / Vsnprintf16 +// +// The user is expected to supply these functions. Note that these functions +// are expected to accept parameters as per the C99 standard. These functions +// can deal with C99 standard return values or Microsoft non-standard return +// values but act more efficiently if implemented via the C99 style. + +extern int Vsnprintf8 (char8_t* pDestination, size_t n, const char8_t* pFormat, va_list arguments); +extern int Vsnprintf16(char16_t* pDestination, size_t n, const char16_t* pFormat, va_list arguments); +extern int Vsnprintf32(char32_t* pDestination, size_t n, const char32_t* pFormat, va_list arguments); +#if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE + extern int VsnprintfW(wchar_t* pDestination, size_t n, const wchar_t* pFormat, va_list arguments); +#endif + +namespace eastl +{ + inline int Vsnprintf(char8_t* pDestination, size_t n, const char8_t* pFormat, va_list arguments) + { return Vsnprintf8(pDestination, n, pFormat, arguments); } + + inline int Vsnprintf(char16_t* pDestination, size_t n, const char16_t* pFormat, va_list arguments) + { return Vsnprintf16(pDestination, n, pFormat, arguments); } + + inline int Vsnprintf(char32_t* pDestination, size_t n, const char32_t* pFormat, va_list arguments) + { return Vsnprintf32(pDestination, n, pFormat, arguments); } + + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE + inline int Vsnprintf(wchar_t* pDestination, size_t n, const wchar_t* pFormat, va_list arguments) + { return VsnprintfW(pDestination, n, pFormat, arguments); } + #endif + +} +/////////////////////////////////////////////////////////////////////////////// + + + +namespace eastl +{ + + /// EASTL_BASIC_STRING_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_BASIC_STRING_DEFAULT_NAME + #define EASTL_BASIC_STRING_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " basic_string" // Unless the user overrides something, this is "EASTL basic_string". + #endif + + + /// EASTL_BASIC_STRING_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_BASIC_STRING_DEFAULT_ALLOCATOR + #define EASTL_BASIC_STRING_DEFAULT_ALLOCATOR allocator_type(EASTL_BASIC_STRING_DEFAULT_NAME) + #endif + + + + /// gEmptyString + /// + /// Declares a shared terminating 0 representation for scalar strings that are empty. + /// + union EmptyString + { + uint32_t mUint32; + char32_t mEmpty32[1]; + char16_t mEmpty16[1]; + char8_t mEmpty8[1]; + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE + wchar_t mEmptyWchar[1]; + #endif + }; + extern EASTL_API EmptyString gEmptyString; + + inline const char8_t* GetEmptyString(char8_t) { return gEmptyString.mEmpty8; } + inline const char16_t* GetEmptyString(char16_t){ return gEmptyString.mEmpty16; } + inline const char32_t* GetEmptyString(char32_t){ return gEmptyString.mEmpty32; } + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE + inline const wchar_t* GetEmptyString(wchar_t) { return gEmptyString.mEmptyWchar; } + #endif + + + /////////////////////////////////////////////////////////////////////////////// + /// abstract_string + /// + /// Implements a generic mutable string that can be passed around in a way that + /// is independent of the allocator used to manipulate it. Thus you can have + /// a function that takes an abstract_string& as an argument and the caller + /// can pass any kind of char-based string, including a fixed_string, and the + /// called function doesn't need to know about it. + /// + /// The primary implementation of this abstract_string was done by Olivier Nallet. + /// + template + class abstract_string + { + public: + typedef abstract_string this_type; + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + typedef T* iterator; // Maintainer note: We want to leave iterator defined as T* -- at least in release builds -- as this gives some algorithms an advantage that optimizers cannot get around. + typedef const T* const_iterator; + typedef eastl::reverse_iterator reverse_iterator; + typedef eastl::reverse_iterator const_reverse_iterator; + + #if defined(_MSC_VER) && (_MSC_VER >= 1400) && (_MSC_VER <= 1600) && !EASTL_STD_CPP_ONLY // _MSC_VER of 1400 means VS2005, 1600 means VS2010. VS2012 generates errors with usage of enum:size_type. + enum : size_type { // Use Microsoft enum language extension, allowing for smaller debug symbols than using a static const. Users have been affected by this. + npos = (size_type)-1, + kMaxSize = (size_type)-2 + }; + #else + static const size_type npos = (size_type)-1; /// 'npos' means non-valid position or simply non-position. + static const size_type kMaxSize = (size_type)-2; /// -1 is reserved for 'npos'. It also happens to be slightly beneficial that kMaxSize is a value less than -1, as it helps us deal with potential integer wraparound issues. + #endif + + // allocfreemethod is a function which allocates memory or frees memory, + // depending on whether pBuffer is NULL or non-NULL. The reason we have + // a single function like this instead of directly using EASTL allocator + // objects with two functions is that having a single function allows us + // to save a function pointer per string instance. The pContext parameter + // is always a pointer to the abstract_string. + typedef void* (*allocfreemethod)(size_t n, void* pBuffer, void* pContext); + + template friend class basic_string; + value_type* mpBegin; // Begin of string. + value_type* mpEnd; // End of string. *mpEnd is always '0', as we 0-terminate our string. mpEnd is always < mpCapacity. + value_type* mpCapacity; // End of allocated space, including the space needed to store the trailing '0' char. mpCapacity is always at least mpEnd + 1. + allocfreemethod mpAllocFreeMethod; + + public: + abstract_string(); + abstract_string(const this_type& x); + abstract_string(allocfreemethod pAllocFreeMethod); + + public: + // Raw access + const value_type* data() const; + const value_type* c_str() const; + + // Iterators. + iterator begin() EA_NOEXCEPT; // Expanded in source code as: mpBegin + const_iterator begin() const EA_NOEXCEPT; // Expanded in source code as: mpBegin + const_iterator cbegin() const EA_NOEXCEPT; + + iterator end() EA_NOEXCEPT; // Expanded in source code as: mpEnd + const_iterator end() const EA_NOEXCEPT; // Expanded in source code as: mpEnd + const_iterator cend() const EA_NOEXCEPT; + + reverse_iterator rbegin() EA_NOEXCEPT; + const_reverse_iterator rbegin() const EA_NOEXCEPT; + const_reverse_iterator crbegin() const EA_NOEXCEPT; + + reverse_iterator rend() EA_NOEXCEPT; + const_reverse_iterator rend() const EA_NOEXCEPT; + const_reverse_iterator crend() const EA_NOEXCEPT; + + // Size-related functionality + bool empty() const EA_NOEXCEPT; // Expanded in source code as: (mpBegin == mpEnd) or (mpBegin != mpEnd) + size_type size() const EA_NOEXCEPT; // Expanded in source code as: (size_type)(mpEnd - mpBegin) + size_type length() const EA_NOEXCEPT; // Expanded in source code as: (size_type)(mpEnd - mpBegin) + size_type max_size() const EA_NOEXCEPT; // Expanded in source code as: kMaxSize + size_type capacity() const EA_NOEXCEPT; // Expanded in source code as: (size_type)((mpCapacity - mpBegin) - 1) + void resize(size_type n, value_type c); + void resize(size_type n); + void reserve(size_type = 0); + void set_capacity(size_type n = npos); // Revises the capacity to the user-specified value. Resizes the container to match the capacity if the requested capacity n is less than the current size. If n == npos then the capacity is reallocated (if necessary) such that capacity == size. + void force_size(size_type n); // Unilaterally moves the string end position (mpEnd) to the given location. Useful for when the user writes into the string via some extenal means such as C strcpy or sprintf. This allows for more efficient use than using resize to achieve this. + void clear(); + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + + // Element access + const_reference operator[](size_type n) const; + reference operator[](size_type n); + const_reference at(size_type n) const; + reference at(size_type n); + reference front(); + const_reference front() const; + reference back(); + const_reference back() const; + + // Operator = + this_type& operator=(const this_type& x); + this_type& operator=(const value_type* p); + this_type& operator=(value_type c); + + // Append operations + this_type& operator+=(const this_type& x); + this_type& operator+=(const value_type* p); + this_type& operator+=(value_type c); + + this_type& append(const this_type& x); + this_type& append(const this_type& x, size_type position, size_type n); + this_type& append(const value_type* p, size_type n); + this_type& append(const value_type* p); + this_type& append(size_type n, value_type c); + this_type& append(const value_type* pBegin, const value_type* pEnd); + + this_type& append_sprintf_va_list(const value_type* pFormat, va_list arguments); + this_type& append_sprintf(const value_type* pFormat, ...); + + void push_back(value_type c); + void pop_back(); + + // Assignment operations + this_type& assign(const this_type& x); + this_type& assign(const this_type& x, size_type position, size_type n); + this_type& assign(const value_type* p, size_type n); + this_type& assign(const value_type* p); + this_type& assign(size_type n, value_type c); + this_type& assign(const value_type* pBegin, const value_type* pEnd); + + // Insertion operations + this_type& insert(size_type position, const this_type& x); + this_type& insert(size_type position, const this_type& x, size_type beg, size_type n); + this_type& insert(size_type position, const value_type* p, size_type n); + this_type& insert(size_type position, const value_type* p); + this_type& insert(size_type position, size_type n, value_type c); + iterator insert(iterator p, value_type c); + void insert(iterator p, size_type n, value_type c); + void insert(iterator p, const value_type* pBegin, const value_type* pEnd); + + // Erase operations + this_type& erase(size_type position = 0, size_type n = npos); + iterator erase(iterator p); + iterator erase(iterator pBegin, iterator pEnd); + + reverse_iterator erase(reverse_iterator position); + reverse_iterator erase(reverse_iterator first, reverse_iterator last); + + //Replacement operations + this_type& replace(size_type position, size_type n, const this_type& x); + this_type& replace(size_type pos1, size_type n1, const this_type& x, size_type pos2, size_type n2); + this_type& replace(size_type position, size_type n1, const value_type* p, size_type n2); + this_type& replace(size_type position, size_type n1, const value_type* p); + this_type& replace(size_type position, size_type n1, size_type n2, value_type c); + this_type& replace(iterator first, iterator last, const this_type& x); + this_type& replace(iterator first, iterator last, const value_type* p, size_type n); + this_type& replace(iterator first, iterator last, const value_type* p); + this_type& replace(iterator first, iterator last, size_type n, value_type c); + this_type& replace(iterator first, iterator last, const value_type* pBegin, const value_type* pEnd); + size_type copy(value_type* p, size_type n, size_type position = 0) const; + void swap(this_type& x); + + // Find operations + size_type find(const this_type& x, size_type position = 0) const; + size_type find(const value_type* p, size_type position = 0) const; + size_type find(const value_type* p, size_type position, size_type n) const; + size_type find(value_type c, size_type position = 0) const; + + // Reverse find operations + size_type rfind(const this_type& x, size_type position = npos) const; + size_type rfind(const value_type* p, size_type position = npos) const; + size_type rfind(const value_type* p, size_type position, size_type n) const; + size_type rfind(value_type c, size_type position = npos) const; + + // Find first-of operations + size_type find_first_of(const this_type& x, size_type position = 0) const; + size_type find_first_of(const value_type* p, size_type position = 0) const; + size_type find_first_of(const value_type* p, size_type position, size_type n) const; + size_type find_first_of(value_type c, size_type position = 0) const; + + // Find last-of operations + size_type find_last_of(const this_type& x, size_type position = npos) const; + size_type find_last_of(const value_type* p, size_type position = npos) const; + size_type find_last_of(const value_type* p, size_type position, size_type n) const; + size_type find_last_of(value_type c, size_type position = npos) const; + + // Find first not-of operations + size_type find_first_not_of(const this_type& x, size_type position = 0) const; + size_type find_first_not_of(const value_type* p, size_type position = 0) const; + size_type find_first_not_of(const value_type* p, size_type position, size_type n) const; + size_type find_first_not_of(value_type c, size_type position = 0) const; + + // Find last not-of operations + size_type find_last_not_of(const this_type& x, size_type position = npos) const; + size_type find_last_not_of(const value_type* p, size_type position = npos) const; + size_type find_last_not_of(const value_type* p, size_type position, size_type n) const; + size_type find_last_not_of(value_type c, size_type position = npos) const; + + // Substring functionality + this_type substr(size_type position = 0, size_type n = npos) const; + + // Comparison operations + int compare(const this_type& x) const; + int compare(size_type pos1, size_type n1, const this_type& x) const; + int compare(size_type pos1, size_type n1, const this_type& x, size_type pos2, size_type n2) const; + int compare(const value_type* p) const; + int compare(size_type pos1, size_type n1, const value_type* p) const; + int compare(size_type pos1, size_type n1, const value_type* p, size_type n2) const; + static int compare(const value_type* pBegin1, const value_type* pEnd1, const value_type* pBegin2, const value_type* pEnd2); + + // Case-insensitive comparison functions. Not part of C++ basic_string. Only ASCII-level locale functionality is supported. Thus this is not suitable for localization purposes. + int comparei(const this_type& x) const; + int comparei(const value_type* p) const; + static int comparei(const value_type* pBegin1, const value_type* pEnd1, const value_type* pBegin2, const value_type* pEnd2); + + // Misc functionality, not part of C++ basic_string. + void make_lower(); + void make_upper(); + void ltrim(); + void rtrim(); + void trim(); + this_type left(size_type n) const; + this_type right(size_type n) const; + this_type& sprintf_va_list(const value_type* pFormat, va_list arguments); + this_type& sprintf(const value_type* pFormat, ...); + + bool validate() const; + int validate_iterator(const_iterator i) const; + + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + + protected: + // Helper functions for initialization/insertion operations. + value_type* DoAllocate(size_type n); + void DoFree(value_type* p, size_type n); + size_type GetNewCapacity(size_type currentCapacity); + + void AllocateSelf(); + void AllocateSelf(size_type n); + void DeallocateSelf(); + iterator InsertInternal(iterator p, value_type c); + void RangeInitialize(const value_type* pBegin, const value_type* pEnd); + void RangeInitialize(const value_type* pBegin); + void SizeInitialize(size_type n, value_type c); + void ThrowLengthException() const; + void ThrowRangeException() const; + void ThrowInvalidArgumentException() const; + + // Replacements for STL template functions. + static const value_type* CharTypeStringFindEnd(const value_type* pBegin, const value_type* pEnd, value_type c); + static const value_type* CharTypeStringRFind(const value_type* pRBegin, const value_type* pREnd, const value_type c); + static const value_type* CharTypeStringSearch(const value_type* p1Begin, const value_type* p1End, const value_type* p2Begin, const value_type* p2End); + static const value_type* CharTypeStringRSearch(const value_type* p1Begin, const value_type* p1End, const value_type* p2Begin, const value_type* p2End); + static const value_type* CharTypeStringFindFirstOf(const value_type* p1Begin, const value_type* p1End, const value_type* p2Begin, const value_type* p2End); + static const value_type* CharTypeStringRFindFirstOf(const value_type* p1RBegin, const value_type* p1REnd, const value_type* p2Begin, const value_type* p2End); + static const value_type* CharTypeStringFindFirstNotOf(const value_type* p1Begin, const value_type* p1End, const value_type* p2Begin, const value_type* p2End); + static const value_type* CharTypeStringRFindFirstNotOf(const value_type* p1RBegin, const value_type* p1REnd, const value_type* p2Begin, const value_type* p2End); + }; + + + + /////////////////////////////////////////////////////////////////////////////// + /// basic_string + /// + /// Implements a templated string class, somewhat like C++ std::basic_string. + /// + /// Notes: + /// As of this writing, an insert of a string into itself necessarily + /// triggers a reallocation, even if there is enough capacity in self + /// to handle the increase in size. This is due to the slightly tricky + /// nature of the operation of modifying one's self with one's self, + /// and thus the source and destination are being modified during the + /// operation. It might be useful to rectify this to the extent possible. + /// + template + class basic_string : public abstract_string + { + public: + typedef abstract_string base_type; + typedef basic_string this_type; + typedef Allocator allocator_type; + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef eastl_size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* iterator; // Maintainer note: We want to leave iterator defined as T* -- at least in release builds -- as this gives some algorithms an advantage that optimizers cannot get around. + typedef const T* const_iterator; + typedef eastl::reverse_iterator reverse_iterator; + typedef eastl::reverse_iterator const_reverse_iterator; + + using base_type::mpBegin; + using base_type::mpEnd; + using base_type::mpCapacity; + using base_type::mpAllocFreeMethod; + using base_type::RangeInitialize; + using base_type::ThrowRangeException; + using base_type::AllocateSelf; + using base_type::DeallocateSelf; + using base_type::SizeInitialize; + using base_type::append_sprintf_va_list; + using base_type::assign; + using base_type::length; + using base_type::npos; + + // CtorDoNotInitialize exists so that we can create a constructor that allocates but doesn't + // initialize and also doesn't collide with any other constructor declaration. + struct CtorDoNotInitialize{}; + + // CtorSprintf exists so that we can create a constructor that accepts printf-style + // arguments but also doesn't collide with any other constructor declaration. + struct CtorSprintf{}; + + // Constructor, destructor + basic_string(); + explicit basic_string(const allocator_type& allocator); + basic_string(const base_type& x); + basic_string(const this_type& x); + basic_string(const this_type& x, size_type position, size_type n = npos); + basic_string(const value_type* p, size_type n, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); + EASTL_STRING_EXPLICIT basic_string(const value_type* p, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); + basic_string(size_type n, value_type c, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); + basic_string(const value_type* pBegin, const value_type* pEnd, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); + basic_string(CtorDoNotInitialize, size_type n, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR); + basic_string(CtorSprintf, const value_type* pFormat, ...); + + #if EASTL_MOVE_SEMANTICS_ENABLED + //basic_string(this_type&& x); + #endif + + ~basic_string(); + + // Allocator + const allocator_type& get_allocator() const EA_NOEXCEPT; + allocator_type& get_allocator() EA_NOEXCEPT; + void set_allocator(const allocator_type& allocator); + + // Operator = + this_type& operator=(const this_type& x); + this_type& operator=(const base_type& x); + this_type& operator=(const value_type* p); + this_type& operator=(value_type c); + + #if EASTL_MOVE_SEMANTICS_ENABLED + //this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + // Substring functionality + this_type substr(size_type position = 0, size_type n = npos) const; + this_type left(size_type n) const; + this_type right(size_type n) const; + + // Functions that merely call abstract_string but up-cast the return value (this_type&). + this_type& operator+=(const this_type& x) { return (this_type&)base_type::operator+=(x); } + this_type& operator+=(const base_type& x) { return (this_type&)base_type::operator+=(x); } + this_type& operator+=(const value_type* p) { return (this_type&)base_type::operator+=(p); } + this_type& operator+=(value_type c) { return (this_type&)base_type::operator+=(c); } + + this_type& append(const this_type& x) { return (this_type&)base_type::append(x); } + this_type& append(const this_type& x, size_type position, size_type n) { return (this_type&)base_type::append(x, position, n); } + this_type& append(const value_type* p, size_type n) { return (this_type&)base_type::append(p, n); } + this_type& append(const value_type* p) { return (this_type&)base_type::append(p); } + this_type& append(size_type n, value_type c) { return (this_type&)base_type::append(n, c); } + this_type& append(const value_type* pBegin, const value_type* pEnd) { return (this_type&)base_type::append(pBegin, pEnd); } + + this_type& append_sprintf_va_list(const value_type* pFormat, va_list arguments) { return (this_type&)base_type::append_sprintf_va_list(pFormat, arguments); } + this_type& append_sprintf(const value_type* pFormat, ...) { va_list arguments; va_start(arguments, pFormat); this_type& r = (this_type&)base_type::append_sprintf_va_list(pFormat, arguments); va_end(arguments); return r; } + + this_type& assign(const this_type& x) { return (this_type&)base_type::assign(x); } + this_type& assign(const this_type& x, size_type position, size_type n) { return (this_type&)base_type::assign(x, position, n); } + this_type& assign(const value_type* p, size_type n) { return (this_type&)base_type::assign(p, n); } + this_type& assign(const value_type* p) { return (this_type&)base_type::assign(p); } + this_type& assign(size_type n, value_type c) { return (this_type&)base_type::assign(n, c); } + this_type& assign(const value_type* pBegin, const value_type* pEnd) { return (this_type&)base_type::assign(pBegin, pEnd); } + + this_type& insert(size_type position, const this_type& x) { return (this_type&)base_type::insert(position, x); } + this_type& insert(size_type position, const this_type& x, size_type beg, size_type n) { return (this_type&)base_type::insert(position, x, beg, n); } + this_type& insert(size_type position, const value_type* p, size_type n) { return (this_type&)base_type::insert(position, p, n); } + this_type& insert(size_type position, const value_type* p) { return (this_type&)base_type::insert(position, p); } + this_type& insert(size_type position, size_type n, value_type c) { return (this_type&)base_type::insert(position, n, c); } + iterator insert(iterator p, value_type c) { return base_type::insert(p, c); } + void insert(iterator p, size_type n, value_type c) { base_type::insert(p, n, c); } + void insert(iterator p, const value_type* pBegin, const value_type* pEnd) { base_type::insert(p, pBegin, pEnd); } + + this_type& erase(size_type position = 0, size_type n = npos) { return (this_type&)base_type::erase(position, n); } + iterator erase(iterator p) { return base_type::erase(p); } + iterator erase(iterator pBegin, iterator pEnd) { return base_type::erase(pBegin, pEnd); } + + reverse_iterator erase(reverse_iterator position) { return base_type::erase(position); } + reverse_iterator erase(reverse_iterator first, reverse_iterator last) { return base_type::erase(first, last); } + + this_type& replace(size_type position, size_type n, const this_type& x) { return (this_type&)base_type::replace(position, n, x); } + this_type& replace(size_type pos1, size_type n1, const this_type& x, size_type pos2, size_type n2) { return (this_type&)base_type::replace(pos1, n1, x, pos2, n2); } + this_type& replace(size_type position, size_type n1, const value_type* p, size_type n2) { return (this_type&)base_type::replace(position, n1, p, n2); } + this_type& replace(size_type position, size_type n1, const value_type* p) { return (this_type&)base_type::replace(position, n1, p); } + this_type& replace(size_type position, size_type n1, size_type n2, value_type c) { return (this_type&)base_type::replace(position, n1, n2, c); } + this_type& replace(iterator first, iterator last, const this_type& x) { return (this_type&)base_type::replace(first, last, x); } + this_type& replace(iterator first, iterator last, const value_type* p, size_type n) { return (this_type&)base_type::replace(first, last, p, n); } + this_type& replace(iterator first, iterator last, const value_type* p) { return (this_type&)base_type::replace(first, last, p); } + this_type& replace(iterator first, iterator last, size_type n, value_type c) { return (this_type&)base_type::replace(first, last, n, c); } + this_type& replace(iterator first, iterator last, const value_type* pBegin, const value_type* pEnd) { return (this_type&)base_type::replace(first, last, pBegin, pEnd); } + + this_type& sprintf_va_list(const value_type* pFormat, va_list arguments) { return (this_type&)base_type::sprintf_va_list(pFormat, arguments); } + this_type& sprintf(const value_type* pFormat, ...) { va_list arguments; va_start(arguments, pFormat); this_type& r = (this_type&)base_type::sprintf_va_list(pFormat, arguments); va_end(arguments); return r; } + + protected: + static void* AllocFreeMethod(size_t n, void* pBuffer, void* pContext) + { + this_type* const pThis = static_cast(static_cast(pContext)); + + if(pBuffer) // If freeing... + { + EASTLFree(pThis->mAllocator, pBuffer, n); + return NULL; // The return value is meaningless for the free. + } + else // allocating + return EASTLAlloc(pThis->mAllocator, n); + } + + allocator_type mAllocator; // To consider: Use base class optimization to make this go away. However, this is not easy because doing so requires templating the base class on something in addition to T, and we'd like to avoid that in order to reduce code bloat. + }; // basic_string + + + + + /////////////////////////////////////////////////////////////////////////////// + // 'char traits' functionality + // + inline char8_t CharToLower(char8_t c) + { return (char8_t)tolower((uint8_t)c); } + + inline char16_t CharToLower(char16_t c) + { if((unsigned)c <= 0xff) return (char16_t)tolower((uint8_t)c); return c; } + + inline char32_t CharToLower(char32_t c) + { if((unsigned)c <= 0xff) return (char32_t)tolower((uint8_t)c); return c; } + + + + inline char8_t CharToUpper(char8_t c) + { return (char8_t)toupper((uint8_t)c); } + + inline char16_t CharToUpper(char16_t c) + { if((unsigned)c <= 0xff) return (char16_t)toupper((uint8_t)c); return c; } + + inline char32_t CharToUpper(char32_t c) + { if((unsigned)c <= 0xff) return (char32_t)toupper((uint8_t)c); return c; } + + + + template + int Compare(const T* p1, const T* p2, size_t n) + { + for(; n > 0; ++p1, ++p2, --n) + { + if(*p1 != *p2) + return (*p1 < *p2) ? -1 : 1; + } + return 0; + } + + inline int Compare(const char8_t* p1, const char8_t* p2, size_t n) + { + return memcmp(p1, p2, n); + } + + template + inline int CompareI(const T* p1, const T* p2, size_t n) + { + for(; n > 0; ++p1, ++p2, --n) + { + const T c1 = CharToLower(*p1); + const T c2 = CharToLower(*p2); + + if(c1 != c2) + return (c1 < c2) ? -1 : 1; + } + return 0; + } + + + inline const char8_t* Find(const char8_t* p, char8_t c, size_t n) + { + return (const char8_t*)memchr(p, c, n); + } + + inline const char16_t* Find(const char16_t* p, char16_t c, size_t n) + { + for(; n > 0; --n, ++p) + { + if(*p == c) + return p; + } + + return NULL; + } + + inline const char32_t* Find(const char32_t* p, char32_t c, size_t n) + { + for(; n > 0; --n, ++p) + { + if(*p == c) + return p; + } + + return NULL; + } + + + inline size_t CharStrlen(const char8_t* p) + { + #ifdef _MSC_VER // VC++ can implement an instrinsic here. + return strlen(p); + #else + const char8_t* pCurrent = p; + while(*pCurrent) + ++pCurrent; + return (size_t)(pCurrent - p); + #endif + } + + inline size_t CharStrlen(const char16_t* p) + { + const char16_t* pCurrent = p; + while(*pCurrent) + ++pCurrent; + return (size_t)(pCurrent - p); + } + + inline size_t CharStrlen(const char32_t* p) + { + const char32_t* pCurrent = p; + while(*pCurrent) + ++pCurrent; + return (size_t)(pCurrent - p); + } + + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE + inline size_t CharStrlen(const wchar_t *p) + { + const wchar_t* pCurrent = p; + while(*pCurrent) + ++pCurrent; + return (size_t)(pCurrent - p); + } + #endif + + + template + inline T* CharStringUninitializedCopy(const T* pSource, const T* pSourceEnd, T* pDestination) + { + memmove(pDestination, pSource, (size_t)(pSourceEnd - pSource) * sizeof(T)); + return pDestination + (pSourceEnd - pSource); + } + + + + + inline char8_t* CharStringUninitializedFillN(char8_t* pDestination, size_t n, const char8_t c) + { + if(n) // Some compilers (e.g. GCC 4.3+) generate a warning (which can't be disabled) if you call memset with a size of 0. + memset(pDestination, (uint8_t)c, (size_t)n); + return pDestination + n; + } + + inline char16_t* CharStringUninitializedFillN(char16_t* pDestination, size_t n, const char16_t c) + { + char16_t* pDest16 = pDestination; + const char16_t* const pEnd = pDestination + n; + while(pDest16 < pEnd) + *pDest16++ = c; + return pDestination + n; + } + + inline char32_t* CharStringUninitializedFillN(char32_t* pDestination, size_t n, const char32_t c) + { + char32_t* pDest32 = pDestination; + const char32_t* const pEnd = pDestination + n; + while(pDest32 < pEnd) + *pDest32++ = c; + return pDestination + n; + } + + + + inline char8_t* CharTypeAssignN(char8_t* pDestination, size_t n, char8_t c) + { + if(n) // Some compilers (e.g. GCC 4.3+) generate a warning (which can't be disabled) if you call memset with a size of 0. + memset(pDestination, c, (size_t)n); + return pDestination; + } + + inline char16_t* CharTypeAssignN(char16_t* pDestination, size_t n, char16_t c) + { + char16_t* pDest16 = pDestination; + const char16_t* const pEnd = pDestination + n; + while(pDest16 < pEnd) + *pDest16++ = c; + return pDestination; + } + + inline char32_t* CharTypeAssignN(char32_t* pDestination, size_t n, char32_t c) + { + char32_t* pDest32 = pDestination; + const char32_t* const pEnd = pDestination + n; + while(pDest32 < pEnd) + *pDest32++ = c; + return pDestination; + } + + + + /////////////////////////////////////////////////////////////////////////////// + // abstract_string / basic_string + // + // We mix the functions between these two classes here because we want to + // have the most common pathways close to each other. This can result in + // improved performance due to cache coherency effects. + /////////////////////////////////////////////////////////////////////////////// + + + template + inline abstract_string::abstract_string() + : mpBegin(const_cast(GetEmptyString(value_type()))), + mpEnd(mpBegin), + mpCapacity(mpBegin + 1), // When we are using gEmptyString, mpCapacity is always mpEnd + 1. This is an important distinguising characteristic. + mpAllocFreeMethod(default_allocfreemethod) + { + } + + + template + inline abstract_string::abstract_string(const this_type& x) + : mpBegin(NULL), + mpEnd(NULL), + mpCapacity(NULL), + mpAllocFreeMethod(x.mpAllocFreeMethod) + { + RangeInitialize(x.mpBegin, x.mpEnd); + } + + + template + inline abstract_string::abstract_string(allocfreemethod pAllocFreeMethod) + : mpBegin(const_cast(GetEmptyString(value_type()))), + mpEnd(mpBegin), + mpCapacity(mpBegin + 1), // When we are using gEmptyString, mpCapacity is always mpEnd + 1. This is an important distinguising characteristic. + mpAllocFreeMethod(pAllocFreeMethod) + { + // Do nothing. + } + + + template + inline basic_string::basic_string() + : base_type(&AllocFreeMethod), + mAllocator(EASTL_BASIC_STRING_DEFAULT_NAME) + { + // Do nothing. + } + + + template + inline basic_string::basic_string(const allocator_type& allocator) + : base_type(&AllocFreeMethod), + mAllocator(allocator) + { + // Do nothing. + } + + + template + inline basic_string::basic_string(const base_type& x) + : base_type(&AllocFreeMethod), + mAllocator(EASTL_BASIC_STRING_DEFAULT_NAME) + { + RangeInitialize(x.mpBegin, x.mpEnd); + } + + + template + inline basic_string::basic_string(const this_type& x) + : base_type(&AllocFreeMethod), + mAllocator(x.mAllocator) + { + RangeInitialize(x.mpBegin, x.mpEnd); + } + + + template + basic_string::basic_string(const this_type& x, size_type position, size_type n) + : base_type(&AllocFreeMethod), + mAllocator(x.mAllocator) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(x.mpEnd - x.mpBegin))) + { + ThrowRangeException(); + AllocateSelf(); + } + else + RangeInitialize(x.mpBegin + position, x.mpBegin + position + eastl::min_alt(n, (size_type)(x.mpEnd - x.mpBegin) - position)); + #else + RangeInitialize(x.mpBegin + position, x.mpBegin + position + eastl::min_alt(n, (size_type)(x.mpEnd - x.mpBegin) - position)); + #endif + } + + + template + inline basic_string::basic_string(const value_type* p, size_type n, const allocator_type& allocator) + : base_type(&AllocFreeMethod), + mAllocator(allocator) + { + RangeInitialize(p, p + n); + } + + + template + inline basic_string::basic_string(const value_type* p, const allocator_type& allocator) + : base_type(&AllocFreeMethod), + mAllocator(allocator) + { + RangeInitialize(p); + } + + + template + inline basic_string::basic_string(size_type n, value_type c, const allocator_type& allocator) + : base_type(&AllocFreeMethod), + mAllocator(allocator) + { + SizeInitialize(n, c); + } + + + template + inline basic_string::basic_string(const value_type* pBegin, const value_type* pEnd, const allocator_type& allocator) + : base_type(&AllocFreeMethod), + mAllocator(allocator) + { + RangeInitialize(pBegin, pEnd); + } + + + // CtorDoNotInitialize exists so that we can create a version that allocates but doesn't + // initialize but also doesn't collide with any other constructor declaration. + template + basic_string::basic_string(CtorDoNotInitialize /*unused*/, size_type n, const allocator_type& allocator) + : base_type(&AllocFreeMethod), + mAllocator(allocator) + { + // Note that we do not call SizeInitialize here. + AllocateSelf(n + 1); // '+1' so that we have room for the terminating 0. + *mpEnd = 0; + } + + + // CtorSprintf exists so that we can create a version that does a variable argument + // sprintf but also doesn't collide with any other constructor declaration. + template + basic_string::basic_string(CtorSprintf /*unused*/, const value_type* pFormat, ...) + : base_type(&AllocFreeMethod), + mAllocator() + { + const size_type n = (size_type)CharStrlen(pFormat) + 1; // We'll need at least this much. '+1' so that we have room for the terminating 0. + AllocateSelf(n); + + va_list arguments; + va_start(arguments, pFormat); + append_sprintf_va_list(pFormat, arguments); + va_end(arguments); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + /* To do. + template + inline basic_string::basic_string(this_type&& x) + : mpBegin(NULL), + mpEnd(NULL), + mpCapacity(NULL), + mAllocator() + { + if(mAllocator == x.mAllocator) // If we can borrow from x... + { + mpBegin = x.mpBegin; // It's OK if x.mpBegin is NULL. + mpEnd = x.mpEnd; + mpCapacity = x.mpCapacity; + x.mpBegin = NULL; + x.mpEnd = NULL; + x.mpCapacity = NULL; + } + else if(x.mpBegin) + { + RangeInitialize(x.mpBegin, x.mpEnd); + // Let x destruct its own items. + } + } + */ + #endif + + + template + inline basic_string::~basic_string() + { + DeallocateSelf(); + } + + + template + inline const typename basic_string::allocator_type& + basic_string::get_allocator() const EA_NOEXCEPT + { + return mAllocator; + } + + template + inline typename basic_string::allocator_type& + basic_string::get_allocator() EA_NOEXCEPT + { + return mAllocator; + } + + + template + inline void basic_string::set_allocator(const allocator_type& allocator) + { + mAllocator = allocator; + } + + + template + inline const typename abstract_string::value_type* + abstract_string::data() const + { + return mpBegin; + } + + + template + inline const typename abstract_string::value_type* + abstract_string::c_str() const + { + return mpBegin; + } + + + template + inline typename abstract_string::iterator + abstract_string::begin() EA_NOEXCEPT + { + return mpBegin; + } + + + template + inline typename abstract_string::const_iterator + abstract_string::begin() const EA_NOEXCEPT + { + return mpBegin; + } + + + template + inline typename abstract_string::const_iterator + abstract_string::cbegin() const EA_NOEXCEPT + { + return mpBegin; + } + + + template + inline typename abstract_string::iterator + abstract_string::end() EA_NOEXCEPT + { + return mpEnd; + } + + + template + inline typename abstract_string::const_iterator + abstract_string::end() const EA_NOEXCEPT + { + return mpEnd; + } + + + template + inline typename abstract_string::const_iterator + abstract_string::cend() const EA_NOEXCEPT + { + return mpEnd; + } + + + template + inline typename abstract_string::reverse_iterator + abstract_string::rbegin() EA_NOEXCEPT + { + return reverse_iterator(mpEnd); + } + + + template + inline typename abstract_string::const_reverse_iterator + abstract_string::rbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(mpEnd); + } + + + template + inline typename abstract_string::const_reverse_iterator + abstract_string::crbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(mpEnd); + } + + + template + inline typename abstract_string::reverse_iterator + abstract_string::rend() EA_NOEXCEPT + { + return reverse_iterator(mpBegin); + } + + + template + inline typename abstract_string::const_reverse_iterator + abstract_string::rend() const EA_NOEXCEPT + { + return const_reverse_iterator(mpBegin); + } + + + template + inline typename abstract_string::const_reverse_iterator + abstract_string::crend() const EA_NOEXCEPT + { + return const_reverse_iterator(mpBegin); + } + + + template + inline bool abstract_string::empty() const EA_NOEXCEPT + { + return (mpBegin == mpEnd); + } + + + template + inline typename abstract_string::size_type + abstract_string::size() const EA_NOEXCEPT + { + return (size_type)(mpEnd - mpBegin); + } + + + template + inline typename abstract_string::size_type + abstract_string::length() const EA_NOEXCEPT + { + return (size_type)(mpEnd - mpBegin); + } + + + template + inline typename abstract_string::size_type + abstract_string::max_size() const EA_NOEXCEPT + { + return kMaxSize; + } + + + template + inline typename abstract_string::size_type + abstract_string::capacity() const EA_NOEXCEPT + { + return (size_type)((mpCapacity - mpBegin) - 1); // '-1' because we pretend that we didn't allocate memory for the terminating 0. + } + + + template + inline typename abstract_string::const_reference + abstract_string::operator[](size_type n) const + { + #if EASTL_ASSERT_ENABLED // We allow the user to reference the trailing 0 char without asserting. Perhaps we shouldn't. + if(EASTL_UNLIKELY(n > (static_cast(mpEnd - mpBegin)))) + EASTL_FAIL_MSG("basic_string::operator[] -- out of range"); + #endif + + return mpBegin[n]; // Sometimes done as *(mpBegin + n) + } + + + template + inline typename abstract_string::reference + abstract_string::operator[](size_type n) + { + #if EASTL_ASSERT_ENABLED // We allow the user to reference the trailing 0 char without asserting. Perhaps we shouldn't. + if(EASTL_UNLIKELY(n > (static_cast(mpEnd - mpBegin)))) + EASTL_FAIL_MSG("basic_string::operator[] -- out of range"); + #endif + + return mpBegin[n]; // Sometimes done as *(mpBegin + n) + } + + + template + inline typename abstract_string::this_type& abstract_string::operator=(const this_type& x) + { + if(&x != this) + { + // This base class has no mAllocator. + //#if EASTL_ALLOCATOR_COPY_ENABLED + // mAllocator = x.mAllocator; + //#endif + + assign(x.mpBegin, x.mpEnd); + } + return *this; + } + + + template + inline abstract_string& abstract_string::operator=(const value_type* p) + { + return assign(p, p + CharStrlen(p)); + } + + + template + inline abstract_string& abstract_string::operator=(value_type c) + { + return assign((size_type)1, c); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + /* + template + inline typename basic_string::this_type& basic_string::operator=(this_type&& x) + { + if(mAllocator == x.mAllocator) + { + eastl::swap(mpBegin, x.mpBegin); + eastl::swap(mpEnd, x.mpEnd); + eastl::swap(mpCapacity, x.mpCapacity); + } + else + assign(x.mpBegin, x.mpEnd); + + return *this; + } + */ + #endif + + + template + void abstract_string::resize(size_type n, value_type c) + { + const size_type s = (size_type)(mpEnd - mpBegin); + + if(n < s) + erase(mpBegin + n, mpEnd); + else if(n > s) + append(n - s, c); + } + + + template + void abstract_string::resize(size_type n) + { + // C++ basic_string specifies that resize(n) is equivalent to resize(n, value_type()). + // For built-in types, value_type() is the same as zero (value_type(0)). + // We can improve the efficiency (especially for long strings) of this + // string class by resizing without assigning to anything. + + const size_type s = (size_type)(mpEnd - mpBegin); + + if(n < s) + erase(mpBegin + n, mpEnd); + else if(n > s) + { + #if EASTL_STRING_OPT_CHAR_INIT + append(n - s, value_type()); + #else + append(n - s); + #endif + } + } + + + template + void abstract_string::reserve(size_type n) + { + #if EASTL_STRING_OPT_LENGTH_ERRORS + if(EASTL_UNLIKELY(n > kMaxSize)) + ThrowLengthException(); + #endif + + // The C++ standard for basic_string doesn't specify if we should or shouldn't + // downsize the container. The standard is overly vague in its description of reserve: + // The member function reserve() is a directive that informs a + // basic_string object of a planned change in size, so that it + // can manage the storage allocation accordingly. + // We will act like the vector container and preserve the contents of + // the container and only reallocate if increasing the size. The user + // can use the set_capacity function to reduce the capacity. + + n = eastl::max_alt(n, (size_type)(mpEnd - mpBegin)); // Calculate the new capacity, which needs to be >= container size. + + if(n >= (size_type)(mpCapacity - mpBegin)) // If there is something to do... // We use >= because mpCapacity accounts for the trailing zero. + set_capacity(n); + } + + + template + inline void abstract_string::set_capacity(size_type n) + { + if(n == npos) // If the user wants to set the capacity to equal the current size... // '-1' because we pretend that we didn't allocate memory for the terminating 0. + n = (size_type)(mpEnd - mpBegin); + else if(n < (size_type)(mpEnd - mpBegin)) + mpEnd = mpBegin + n; + + if(n != (size_type)((mpCapacity - mpBegin) - 1)) // If there is any capacity change... + { + if(n) + { + pointer pNewBegin = DoAllocate(n + 1); // We need the + 1 to accomodate the trailing 0. + pointer pNewEnd = pNewBegin; + + pNewEnd = CharStringUninitializedCopy(mpBegin, mpEnd, pNewBegin); + *pNewEnd = 0; + + DeallocateSelf(); + mpBegin = pNewBegin; + mpEnd = pNewEnd; + mpCapacity = pNewBegin + (n + 1); + } + else + { + DeallocateSelf(); + AllocateSelf(); + } + } + } + + + template + inline void abstract_string::force_size(size_type n) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(n >= (size_type)(mpCapacity - mpBegin))) + ThrowRangeException(); + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(n >= (size_type)(mpCapacity - mpBegin))) + EASTL_FAIL_MSG("abstract_string::force_size -- out of range"); + #endif + + mpEnd = mpBegin + n; + } + + + template + inline void abstract_string::clear() + { + if(mpBegin != mpEnd) + { + *mpBegin = value_type(0); + mpEnd = mpBegin; + } + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void abstract_string::reset() + { + reset_lose_memory(); + } + #endif + + + template + inline void abstract_string::reset_lose_memory() + { + // The reset function is a special extension function which unilaterally + // resets the container to an empty state without freeing the memory of + // the contained objects. This is useful for very quickly tearing down a + // container built into scratch memory. + AllocateSelf(); + } + + + template + inline typename abstract_string::const_reference + abstract_string::at(size_type n) const + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(n >= (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #elif EASTL_ASSERT_ENABLED // We assert if the user references the trailing 0 char. + if(EASTL_UNLIKELY(n >= (size_type)(mpEnd - mpBegin))) + EASTL_FAIL_MSG("abstract_string::at -- out of range"); + #endif + + return mpBegin[n]; + } + + + template + inline typename abstract_string::reference + abstract_string::at(size_type n) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(n >= (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #elif EASTL_ASSERT_ENABLED // We assert if the user references the trailing 0 char. + if(EASTL_UNLIKELY(n >= (size_type)(mpEnd - mpBegin))) + EASTL_FAIL_MSG("abstract_string::at -- out of range"); + #endif + + return mpBegin[n]; + } + + + template + inline typename abstract_string::reference + abstract_string::front() + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference the trailing 0 char without asserting. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(mpEnd <= mpBegin)) // We assert if the user references the trailing 0 char. + EASTL_FAIL_MSG("abstract_string::front -- empty string"); + #endif + + return *mpBegin; + } + + + template + inline typename abstract_string::const_reference + abstract_string::front() const + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference the trailing 0 char without asserting. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(mpEnd <= mpBegin)) // We assert if the user references the trailing 0 char. + EASTL_FAIL_MSG("abstract_string::front -- empty string"); + #endif + + return *mpBegin; + } + + + template + inline typename abstract_string::reference + abstract_string::back() + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference the trailing 0 char without asserting. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(mpEnd <= mpBegin)) // We assert if the user references the trailing 0 char. + EASTL_FAIL_MSG("abstract_string::back -- empty string"); + #endif + + return *(mpEnd - 1); + } + + + template + inline typename abstract_string::const_reference + abstract_string::back() const + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference the trailing 0 char without asserting. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(mpEnd <= mpBegin)) // We assert if the user references the trailing 0 char. + EASTL_FAIL_MSG("abstract_string::back -- empty string"); + #endif + + return *(mpEnd - 1); + } + + + template + inline abstract_string& abstract_string::operator+=(const this_type& x) + { + return append(x); + } + + + template + inline abstract_string& abstract_string::operator+=(const value_type* p) + { + return append(p); + } + + + template + inline abstract_string& abstract_string::operator+=(value_type c) + { + push_back(c); + return *this; + } + + + template + inline abstract_string& abstract_string::append(const this_type& x) + { + return append(x.mpBegin, x.mpEnd); + } + + + template + inline abstract_string& abstract_string::append(const this_type& x, size_type position, size_type n) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(x.mpEnd - x.mpBegin))) + ThrowRangeException(); + #endif + + return append(x.mpBegin + position, x.mpBegin + position + eastl::min_alt(n, (size_type)(x.mpEnd - x.mpBegin) - position)); + } + + + template + inline abstract_string& abstract_string::append(const value_type* p, size_type n) + { + return append(p, p + n); + } + + + template + inline abstract_string& abstract_string::append(const value_type* p) + { + return append(p, p + CharStrlen(p)); + } + + + template + abstract_string& abstract_string::append(size_type n, value_type c) + { + const size_type s = (size_type)(mpEnd - mpBegin); + + #if EASTL_STRING_OPT_LENGTH_ERRORS + if(EASTL_UNLIKELY((n > kMaxSize) || (s > (kMaxSize - n)))) + ThrowLengthException(); + #endif + + const size_type nCapacity = (size_type)((mpCapacity - mpBegin) - 1); + + if((s + n) > nCapacity) + reserve(eastl::max_alt((size_type)GetNewCapacity(nCapacity), (size_type)(s + n))); + + if(n > 0) + { + CharStringUninitializedFillN(mpEnd + 1, n - 1, c); + *mpEnd = c; + mpEnd += n; + *mpEnd = 0; + } + + return *this; + } + + + template + abstract_string& abstract_string::append(const value_type* pBegin, const value_type* pEnd) + { + if(pBegin != pEnd) + { + const size_type nOldSize = (size_type)(mpEnd - mpBegin); + const size_type n = (size_type)(pEnd - pBegin); + + #if EASTL_STRING_OPT_LENGTH_ERRORS + if(EASTL_UNLIKELY(((size_t)n > kMaxSize) || (nOldSize > (kMaxSize - n)))) + ThrowLengthException(); + #endif + + const size_type nCapacity = (size_type)((mpCapacity - mpBegin) - 1); + + if((nOldSize + n) > nCapacity) + { + const size_type nLength = eastl::max_alt((size_type)GetNewCapacity(nCapacity), (size_type)(nOldSize + n)) + 1; // + 1 to accomodate the trailing 0. + + pointer pNewBegin = DoAllocate(nLength); + pointer pNewEnd = pNewBegin; + + pNewEnd = CharStringUninitializedCopy(mpBegin, mpEnd, pNewBegin); + pNewEnd = CharStringUninitializedCopy(pBegin, pEnd, pNewEnd); + *pNewEnd = 0; + + DeallocateSelf(); + mpBegin = pNewBegin; + mpEnd = pNewEnd; + mpCapacity = pNewBegin + nLength; + } + else + { + const value_type* pTemp = pBegin; + ++pTemp; + CharStringUninitializedCopy(pTemp, pEnd, mpEnd + 1); + mpEnd[n] = 0; + *mpEnd = *pBegin; + mpEnd += n; + } + } + + return *this; + } + + + template + abstract_string& abstract_string::append_sprintf_va_list(const value_type* pFormat, va_list arguments) + { + // From unofficial C89 extension documentation: + // The vsnprintf returns the number of characters written into the array, + // not counting the terminating null character, or a negative value + // if count or more characters are requested to be generated. + // An error can occur while converting a value for output. + + // From the C99 standard: + // The vsnprintf function returns the number of characters that would have + // been written had n been sufficiently large, not counting the terminating + // null character, or a negative value if an encoding error occurred. + // Thus, the null-terminated output has been completely written if and only + // if the returned value is nonnegative and less than n. + size_type nInitialSize = (size_type)(mpEnd - mpBegin); + int nReturnValue; + + #if EASTL_VA_COPY_ENABLED + va_list argumentsSaved; + va_copy(argumentsSaved, arguments); + #endif + + if(mpBegin == GetEmptyString(value_type())) // We need to do this because non-standard vsnprintf implementations will otherwise overwrite gEmptyString with a non-zero char. + nReturnValue = eastl::Vsnprintf(mpEnd, 0, pFormat, arguments); + else + nReturnValue = eastl::Vsnprintf(mpEnd, (size_t)(mpCapacity - mpEnd), pFormat, arguments); + + if(nReturnValue >= (int)(mpCapacity - mpEnd)) // If there wasn't enough capacity... + { + // In this case we definitely have C99 Vsnprintf behaviour. + #if EASTL_VA_COPY_ENABLED + va_end(arguments); + va_copy(arguments, argumentsSaved); + #endif + resize(nInitialSize + nReturnValue); + nReturnValue = eastl::Vsnprintf(mpBegin + nInitialSize, (size_t)(nReturnValue + 1), pFormat, arguments); // '+1' because vsnprintf wants to know the size of the buffer including the terminating zero. + } + else if(nReturnValue < 0) // If vsnprintf is non-C99-standard (e.g. it is VC++ _vsnprintf)... + { + // In this case we either have C89 extension behaviour or C99 behaviour. + size_type n = eastl::max_alt((size_type)(EASTL_STRING_INITIAL_CAPACITY - 1), (size_type)(size() * 2)); // '-1' because the resize call below will add one for NULL terminator and we want to keep allocations on fixed block sizes. + + for(; (nReturnValue < 0) && (n < 1000000); n *= 2) + { + #if EASTL_VA_COPY_ENABLED + va_end(arguments); + va_copy(arguments, argumentsSaved); + #endif + resize(n); + + const size_t nCapacity = (size_t)((n + 1) - nInitialSize); + nReturnValue = eastl::Vsnprintf(mpBegin + nInitialSize, nCapacity, pFormat, arguments); // '+1' because vsnprintf wants to know the size of the buffer including the terminating zero. + + if(nReturnValue == (int)(unsigned)nCapacity) + { + resize(++n); + nReturnValue = eastl::Vsnprintf(mpBegin + nInitialSize, nCapacity + 1, pFormat, arguments); + } + } + } + + if(nReturnValue >= 0) + mpEnd = mpBegin + nInitialSize + nReturnValue; // We are guaranteed from the above logic that mpEnd <= mpCapacity. + + #if EASTL_VA_COPY_ENABLED + // va_end for arguments will be called by the caller. + va_end(argumentsSaved); + #endif + + return *this; + } + + + template + abstract_string& abstract_string::append_sprintf(const value_type* pFormat, ...) + { + va_list arguments; + va_start(arguments, pFormat); + append_sprintf_va_list(pFormat, arguments); + va_end(arguments); + + return *this; + } + + + template + inline void abstract_string::push_back(value_type c) + { + if((mpEnd + 1) == mpCapacity) // If we are out of space... (note that we test for + 1 because we have a trailing 0) + reserve(eastl::max_alt(GetNewCapacity((size_type)((mpCapacity - mpBegin) - 1)), (size_type)(mpEnd - mpBegin) + 1)); + *mpEnd++ = c; + *mpEnd = 0; + } + + + template + inline void abstract_string::pop_back() + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(mpEnd <= mpBegin)) + EASTL_FAIL_MSG("abstract_string::pop_back -- empty string"); + #endif + + mpEnd[-1] = value_type(0); + --mpEnd; + } + + + template + inline abstract_string& abstract_string::assign(const this_type& x) + { + return assign(x.mpBegin, x.mpEnd); + } + + + template + inline abstract_string& abstract_string::assign(const this_type& x, size_type position, size_type n) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(x.mpEnd - x.mpBegin))) + ThrowRangeException(); + #endif + + return assign(x.mpBegin + position, x.mpBegin + position + eastl::min_alt(n, (size_type)(x.mpEnd - x.mpBegin) - position)); + } + + + template + inline abstract_string& abstract_string::assign(const value_type* p, size_type n) + { + return assign(p, p + n); + } + + + template + inline abstract_string& abstract_string::assign(const value_type* p) + { + return assign(p, p + CharStrlen(p)); + } + + template + abstract_string& abstract_string::assign(size_type n, value_type c) + { + if(n <= (size_type)(mpEnd - mpBegin)) + { + CharTypeAssignN(mpBegin, n, c); + erase(mpBegin + n, mpEnd); + } + else + { + CharTypeAssignN(mpBegin, (size_type)(mpEnd - mpBegin), c); + append(n - (size_type)(mpEnd - mpBegin), c); + } + return *this; + } + + + template + abstract_string& abstract_string::assign(const value_type* pBegin, const value_type* pEnd) + { + const ptrdiff_t n = pEnd - pBegin; + if(static_cast(n) <= (size_type)(mpEnd - mpBegin)) + { + memmove(mpBegin, pBegin, (size_t)n * sizeof(value_type)); + erase(mpBegin + n, mpEnd); + } + else + { + memmove(mpBegin, pBegin, (size_t)(mpEnd - mpBegin) * sizeof(value_type)); + append(pBegin + (size_type)(mpEnd - mpBegin), pEnd); + } + return *this; + } + + + template + abstract_string& abstract_string::insert(size_type position, const this_type& x) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #endif + + #if EASTL_STRING_OPT_LENGTH_ERRORS + if(EASTL_UNLIKELY((size_type)(mpEnd - mpBegin) > (kMaxSize - (size_type)(x.mpEnd - x.mpBegin)))) + ThrowLengthException(); + #endif + + insert(mpBegin + position, x.mpBegin, x.mpEnd); + return *this; + } + + + template + abstract_string& abstract_string::insert(size_type position, const this_type& x, size_type beg, size_type n) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY((position > (size_type)(mpEnd - mpBegin)) || (beg > (size_type)(x.mpEnd - x.mpBegin)))) + ThrowRangeException(); + #endif + + size_type nLength = eastl::min_alt(n, (size_type)(x.mpEnd - x.mpBegin) - beg); + + #if EASTL_STRING_OPT_LENGTH_ERRORS + if(EASTL_UNLIKELY((size_type)(mpEnd - mpBegin) > (kMaxSize - nLength))) + ThrowLengthException(); + #endif + + insert(mpBegin + position, x.mpBegin + beg, x.mpBegin + beg + nLength); + return *this; + } + + + template + abstract_string& abstract_string::insert(size_type position, const value_type* p, size_type n) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #endif + + #if EASTL_STRING_OPT_LENGTH_ERRORS + if(EASTL_UNLIKELY((size_type)(mpEnd - mpBegin) > (kMaxSize - n))) + ThrowLengthException(); + #endif + + insert(mpBegin + position, p, p + n); + return *this; + } + + + template + abstract_string& abstract_string::insert(size_type position, const value_type* p) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #endif + + size_type nLength = (size_type)CharStrlen(p); + + #if EASTL_STRING_OPT_LENGTH_ERRORS + if(EASTL_UNLIKELY((size_type)(mpEnd - mpBegin) > (kMaxSize - nLength))) + ThrowLengthException(); + #endif + + insert(mpBegin + position, p, p + nLength); + return *this; + } + + + template + abstract_string& abstract_string::insert(size_type position, size_type n, value_type c) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #endif + + #if EASTL_STRING_OPT_LENGTH_ERRORS + if(EASTL_UNLIKELY((size_type)(mpEnd - mpBegin) > (kMaxSize - n))) + ThrowLengthException(); + #endif + + insert(mpBegin + position, n, c); + return *this; + } + + + template + inline typename abstract_string::iterator + abstract_string::insert(iterator p, value_type c) + { + if(p == mpEnd) + { + push_back(c); + return mpEnd - 1; + } + return InsertInternal(p, c); + } + + + template + void abstract_string::insert(iterator p, size_type n, value_type c) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY((p < mpBegin) || (p > mpEnd))) + EASTL_FAIL_MSG("abstract_string::insert -- invalid position"); + #endif + + if(n) // If there is anything to insert... + { + if(size_type(mpCapacity - mpEnd) >= (n + 1)) // If we have enough capacity... + { + const size_type nElementsAfter = (size_type)(mpEnd - p); + iterator pOldEnd = mpEnd; + + if(nElementsAfter >= n) // If there's enough space for the new chars between the insert position and the end... + { + CharStringUninitializedCopy((mpEnd - n) + 1, mpEnd + 1, mpEnd + 1); + mpEnd += n; + memmove(p + n, p, (size_t)((nElementsAfter - n) + 1) * sizeof(value_type)); + CharTypeAssignN(p, n, c); + } + else + { + CharStringUninitializedFillN(mpEnd + 1, n - nElementsAfter - 1, c); + mpEnd += n - nElementsAfter; + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + CharStringUninitializedCopy(p, pOldEnd + 1, mpEnd); + mpEnd += nElementsAfter; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + mpEnd = pOldEnd; + throw; + } + #endif + + CharTypeAssignN(p, nElementsAfter + 1, c); + } + } + else + { + const size_type nOldSize = (size_type)(mpEnd - mpBegin); + const size_type nOldCap = (size_type)((mpCapacity - mpBegin) - 1); + const size_type nLength = eastl::max_alt((size_type)GetNewCapacity(nOldCap), (size_type)(nOldSize + n)) + 1; // + 1 to accomodate the trailing 0. + + iterator pNewBegin = DoAllocate(nLength); + iterator pNewEnd = pNewBegin; + + pNewEnd = CharStringUninitializedCopy(mpBegin, p, pNewBegin); + pNewEnd = CharStringUninitializedFillN(pNewEnd, n, c); + pNewEnd = CharStringUninitializedCopy(p, mpEnd, pNewEnd); + *pNewEnd = 0; + + DeallocateSelf(); + mpBegin = pNewBegin; + mpEnd = pNewEnd; + mpCapacity = pNewBegin + nLength; + } + } + } + + + template + void abstract_string::insert(iterator p, const value_type* pBegin, const value_type* pEnd) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY((p < mpBegin) || (p > mpEnd))) + EASTL_FAIL_MSG("abstract_string::insert -- invalid position"); + #endif + + const size_type n = (size_type)(pEnd - pBegin); + + if(n) + { + const bool bCapacityIsSufficient = ((mpCapacity - mpEnd) >= (difference_type)(n + 1)); + const bool bSourceIsFromSelf = ((pEnd >= mpBegin) && (pBegin <= mpEnd)); + + // If bSourceIsFromSelf is true, then we reallocate. This is because we are + // inserting ourself into ourself and thus both the source and destination + // be modified, making it rather tricky to attempt to do in place. The simplest + // resolution is to reallocate. To consider: there may be a way to implement this + // whereby we don't need to reallocate or can often avoid reallocating. + if(bCapacityIsSufficient && !bSourceIsFromSelf) + { + const ptrdiff_t nElementsAfter = (mpEnd - p); + iterator pOldEnd = mpEnd; + + if(nElementsAfter >= (ptrdiff_t)n) // If the newly inserted characters entirely fit within the size of the original string... + { + memmove(mpEnd + 1, mpEnd - n + 1, (size_t)n * sizeof(value_type)); + mpEnd += n; + memmove(p + n, p, (size_t)((nElementsAfter - n) + 1) * sizeof(value_type)); + memmove(p, pBegin, (size_t)(pEnd - pBegin) * sizeof(value_type)); + } + else + { + const value_type* const pMid = pBegin + (nElementsAfter + 1); + + memmove(mpEnd + 1, pMid, (size_t)(pEnd - pMid) * sizeof(value_type)); + mpEnd += n - nElementsAfter; + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + memmove(mpEnd, p, (size_t)(pOldEnd - p + 1) * sizeof(value_type)); + mpEnd += nElementsAfter; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + mpEnd = pOldEnd; + throw; + } + #endif + + memmove(p, pBegin, (size_t)(pMid - pBegin) * sizeof(value_type)); + } + } + else // Else we need to reallocate to implement this. + { + const size_type nOldSize = (size_type)(mpEnd - mpBegin); + const size_type nOldCap = (size_type)((mpCapacity - mpBegin) - 1); + size_type nLength; + + if(bCapacityIsSufficient) // If bCapacityIsSufficient is true, then bSourceIsFromSelf must be false. + nLength = nOldSize + n + 1; // + 1 to accomodate the trailing 0. + else + nLength = eastl::max_alt((size_type)GetNewCapacity(nOldCap), (size_type)(nOldSize + n)) + 1; // + 1 to accomodate the trailing 0. + + pointer pNewBegin = DoAllocate(nLength); + pointer pNewEnd = pNewBegin; + + pNewEnd = CharStringUninitializedCopy(mpBegin, p, pNewBegin); + pNewEnd = CharStringUninitializedCopy(pBegin, pEnd, pNewEnd); + pNewEnd = CharStringUninitializedCopy(p, mpEnd, pNewEnd); + *pNewEnd = 0; + + DeallocateSelf(); + mpBegin = pNewBegin; + mpEnd = pNewEnd; + mpCapacity = pNewBegin + nLength; + } + } + } + + + template + inline abstract_string& abstract_string::erase(size_type position, size_type n) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #endif + + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + EASTL_FAIL_MSG("abstract_string::erase -- invalid position"); + #endif + + erase(mpBegin + position, mpBegin + position + eastl::min_alt(n, (size_type)(mpEnd - mpBegin) - position)); + return *this; + } + + + template + inline typename abstract_string::iterator + abstract_string::erase(iterator p) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY((p < mpBegin) || (p >= mpEnd))) + EASTL_FAIL_MSG("abstract_string::erase -- invalid position"); + #endif + + memmove(p, p + 1, (size_t)(mpEnd - p) * sizeof(value_type)); + --mpEnd; + return p; + } + + + template + typename abstract_string::iterator + abstract_string::erase(iterator pBegin, iterator pEnd) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY((pBegin < mpBegin) || (pBegin > mpEnd) || (pEnd < mpBegin) || (pEnd > mpEnd) || (pEnd < pBegin))) + EASTL_FAIL_MSG("abstract_string::erase -- invalid position"); + #endif + + if(pBegin != pEnd) + { + memmove(pBegin, pEnd, (size_t)((mpEnd - pEnd) + 1) * sizeof(value_type)); + const iterator pNewEnd = (mpEnd - (pEnd - pBegin)); + mpEnd = pNewEnd; + } + return pBegin; + } + + + template + inline typename abstract_string::reverse_iterator + abstract_string::erase(reverse_iterator position) + { + return reverse_iterator(erase((++position).base())); + } + + + template + typename abstract_string::reverse_iterator + abstract_string::erase(reverse_iterator first, reverse_iterator last) + { + return reverse_iterator(erase((++last).base(), (++first).base())); + } + + + template + abstract_string& abstract_string::replace(size_type position, size_type n, const this_type& x) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #endif + + const size_type nLength = eastl::min_alt(n, (size_type)(mpEnd - mpBegin) - position); + + #if EASTL_STRING_OPT_LENGTH_ERRORS + if(EASTL_UNLIKELY(((size_type)(mpEnd - mpBegin) - nLength) >= (kMaxSize - (size_type)(x.mpEnd - x.mpBegin)))) + ThrowLengthException(); + #endif + + return replace(mpBegin + position, mpBegin + position + nLength, x.mpBegin, x.mpEnd); + } + + + template + abstract_string& abstract_string::replace(size_type pos1, size_type n1, const this_type& x, size_type pos2, size_type n2) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY((pos1 > (size_type)(mpEnd - mpBegin)) || (pos2 > (size_type)(x.mpEnd - x.mpBegin)))) + ThrowRangeException(); + #endif + + const size_type nLength1 = eastl::min_alt(n1, (size_type)( mpEnd - mpBegin) - pos1); + const size_type nLength2 = eastl::min_alt(n2, (size_type)(x.mpEnd - x.mpBegin) - pos2); + + #if EASTL_STRING_OPT_LENGTH_ERRORS + if(EASTL_UNLIKELY(((size_type)(mpEnd - mpBegin) - nLength1) >= (kMaxSize - nLength2))) + ThrowLengthException(); + #endif + + return replace(mpBegin + pos1, mpBegin + pos1 + nLength1, x.mpBegin + pos2, x.mpBegin + pos2 + nLength2); + } + + + template + abstract_string& abstract_string::replace(size_type position, size_type n1, const value_type* p, size_type n2) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #endif + + const size_type nLength = eastl::min_alt(n1, (size_type)(mpEnd - mpBegin) - position); + + #if EASTL_STRING_OPT_LENGTH_ERRORS + if(EASTL_UNLIKELY((n2 > kMaxSize) || (((size_type)(mpEnd - mpBegin) - nLength) >= (kMaxSize - n2)))) + ThrowLengthException(); + #endif + + return replace(mpBegin + position, mpBegin + position + nLength, p, p + n2); + } + + + template + abstract_string& abstract_string::replace(size_type position, size_type n1, const value_type* p) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #endif + + const size_type nLength = eastl::min_alt(n1, (size_type)(mpEnd - mpBegin) - position); + + #if EASTL_STRING_OPT_LENGTH_ERRORS + const size_type n2 = (size_type)CharStrlen(p); + if(EASTL_UNLIKELY((n2 > kMaxSize) || (((size_type)(mpEnd - mpBegin) - nLength) >= (kMaxSize - n2)))) + ThrowLengthException(); + #endif + + return replace(mpBegin + position, mpBegin + position + nLength, p, p + CharStrlen(p)); + } + + + template + abstract_string& abstract_string::replace(size_type position, size_type n1, size_type n2, value_type c) + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #endif + + const size_type nLength = eastl::min_alt(n1, (size_type)(mpEnd - mpBegin) - position); + + #if EASTL_STRING_OPT_LENGTH_ERRORS + if(EASTL_UNLIKELY((n2 > kMaxSize) || ((size_type)(mpEnd - mpBegin) - nLength) >= (kMaxSize - n2))) + ThrowLengthException(); + #endif + + return replace(mpBegin + position, mpBegin + position + nLength, n2, c); + } + + + template + inline abstract_string& abstract_string::replace(iterator pBegin, iterator pEnd, const this_type& x) + { + return replace(pBegin, pEnd, x.mpBegin, x.mpEnd); + } + + + template + inline abstract_string& abstract_string::replace(iterator pBegin, iterator pEnd, const value_type* p, size_type n) + { + return replace(pBegin, pEnd, p, p + n); + } + + + template + inline abstract_string& abstract_string::replace(iterator pBegin, iterator pEnd, const value_type* p) + { + return replace(pBegin, pEnd, p, p + CharStrlen(p)); + } + + + template + abstract_string& abstract_string::replace(iterator pBegin, iterator pEnd, size_type n, value_type c) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY((pBegin < mpBegin) || (pBegin > mpEnd) || (pEnd < mpBegin) || (pEnd > mpEnd) || (pEnd < pBegin))) + EASTL_FAIL_MSG("abstract_string::replace -- invalid position"); + #endif + + const size_type nLength = static_cast(pEnd - pBegin); + + if(nLength >= n) + { + CharTypeAssignN(pBegin, n, c); + erase(pBegin + n, pEnd); + } + else + { + CharTypeAssignN(pBegin, nLength, c); + insert(pEnd, n - nLength, c); + } + return *this; + } + + + template + abstract_string& abstract_string::replace(iterator pBegin1, iterator pEnd1, const value_type* pBegin2, const value_type* pEnd2) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY((pBegin1 < mpBegin) || (pBegin1 > mpEnd) || (pEnd1 < mpBegin) || (pEnd1 > mpEnd) || (pEnd1 < pBegin1))) + EASTL_FAIL_MSG("abstract_string::replace -- invalid position"); + #endif + + const size_type nLength1 = (size_type)(pEnd1 - pBegin1); + const size_type nLength2 = (size_type)(pEnd2 - pBegin2); + + if(nLength1 >= nLength2) // If we have a non-expanding operation... + { + if((pBegin2 > pEnd1) || (pEnd2 <= pBegin1)) // If we have a non-overlapping operation... + memcpy(pBegin1, pBegin2, (size_t)(pEnd2 - pBegin2) * sizeof(value_type)); + else + memmove(pBegin1, pBegin2, (size_t)(pEnd2 - pBegin2) * sizeof(value_type)); + erase(pBegin1 + nLength2, pEnd1); + } + else // Else we are expanding. + { + if((pBegin2 > pEnd1) || (pEnd2 <= pBegin1)) // If we have a non-overlapping operation... + { + const value_type* const pMid2 = pBegin2 + nLength1; + + if((pEnd2 <= pBegin1) || (pBegin2 > pEnd1)) + memcpy(pBegin1, pBegin2, (size_t)(pMid2 - pBegin2) * sizeof(value_type)); + else + memmove(pBegin1, pBegin2, (size_t)(pMid2 - pBegin2) * sizeof(value_type)); + insert(pEnd1, pMid2, pEnd2); + } + else // else we have an overlapping operation. + { + // I can't think of any easy way of doing this without allocating temporary memory. + const size_type nOldSize = (size_type)(mpEnd - mpBegin); + const size_type nOldCap = (size_type)((mpCapacity - mpBegin) - 1); + const size_type nNewCapacity = eastl::max_alt((size_type)GetNewCapacity(nOldCap), (size_type)(nOldSize + (nLength2 - nLength1))) + 1; // + 1 to accomodate the trailing 0. + + pointer pNewBegin = DoAllocate(nNewCapacity); + pointer pNewEnd = pNewBegin; + + pNewEnd = CharStringUninitializedCopy(mpBegin, pBegin1, pNewBegin); + pNewEnd = CharStringUninitializedCopy(pBegin2, pEnd2, pNewEnd); + pNewEnd = CharStringUninitializedCopy(pEnd1, mpEnd, pNewEnd); + *pNewEnd = 0; + + DeallocateSelf(); + mpBegin = pNewBegin; + mpEnd = pNewEnd; + mpCapacity = pNewBegin + nNewCapacity; + } + } + return *this; + } + + + template + typename abstract_string::size_type + abstract_string::copy(value_type* p, size_type n, size_type position) const + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #endif + + // It is not clear from the C++ standard if 'p' destination pointer is allowed to + // refer to memory from within the string itself. We assume so and use memmove + // instead of memcpy until we find otherwise. + const size_type nLength = eastl::min_alt(n, (size_type)(mpEnd - mpBegin) - position); + memmove(p, mpBegin + position, (size_t)nLength * sizeof(value_type)); + return nLength; + } + + + template + void abstract_string::swap(this_type& x) + { + if(mpAllocFreeMethod == x.mpAllocFreeMethod) // If allocators are equivalent... + { + // We leave mpAllocFreeMethod as-is. + eastl::swap(mpBegin, x.mpBegin); + eastl::swap(mpEnd, x.mpEnd); + eastl::swap(mpCapacity, x.mpCapacity); + } + else // else swap the contents. + { + const this_type temp(*this); // Can't call eastl::swap(*this, x) because that + *this = x; // would itself call this member swap function. + x = temp; + } + } + + + template + inline typename abstract_string::size_type + abstract_string::find(const this_type& x, size_type position) const + { + return find(x.mpBegin, position, (size_type)(x.mpEnd - x.mpBegin)); + } + + + template + inline typename abstract_string::size_type + abstract_string::find(const value_type* p, size_type position) const + { + return find(p, position, (size_type)CharStrlen(p)); + } + + template + typename abstract_string::size_type + abstract_string::find(const value_type* p, size_type position, size_type n) const + { + // It is not clear what the requirements are for position, but since the C++ standard + // appears to be silent it is assumed for now that position can be any value. + //#if EASTL_ASSERT_ENABLED + // if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + // EASTL_FAIL_MSG("abstract_string::find -- invalid position"); + //#endif + + if(EASTL_LIKELY((position + n) <= (size_type)(mpEnd - mpBegin))) // If the range is valid... + { + const value_type* const pTemp = eastl::search(mpBegin + position, mpEnd, p, p + n); + + if((pTemp != mpEnd) || (n == 0)) + return (size_type)(pTemp - mpBegin); + } + return npos; + } + + template + typename abstract_string::size_type + abstract_string::find(value_type c, size_type position) const + { + // It is not clear what the requirements are for position, but since the C++ standard + // appears to be silent it is assumed for now that position can be any value. + //#if EASTL_ASSERT_ENABLED + // if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + // EASTL_FAIL_MSG("abstract_string::find -- invalid position"); + //#endif + + if(EASTL_LIKELY(position < (size_type)(mpEnd - mpBegin))) // If the position is valid... + { + const const_iterator pResult = eastl::find(mpBegin + position, mpEnd, c); + + if(pResult != mpEnd) + return (size_type)(pResult - mpBegin); + } + return npos; + } + + + template + inline typename abstract_string::size_type + abstract_string::rfind(const this_type& x, size_type position) const + { + return rfind(x.mpBegin, position, (size_type)(x.mpEnd - x.mpBegin)); + } + + + template + inline typename abstract_string::size_type + abstract_string::rfind(const value_type* p, size_type position) const + { + return rfind(p, position, (size_type)CharStrlen(p)); + } + + + template + typename abstract_string::size_type + abstract_string::rfind(const value_type* p, size_type position, size_type n) const + { + // Disabled because it's not clear what values are valid for position. + // It is documented that npos is a valid value, though. We return npos and + // don't crash if postion is any invalid value. + //#if EASTL_ASSERT_ENABLED + // if(EASTL_UNLIKELY((position != npos) && (position > (size_type)(mpEnd - mpBegin)))) + // EASTL_FAIL_MSG("abstract_string::rfind -- invalid position"); + //#endif + + // Note that a search for a zero length string starting at position = end() returns end() and not npos. + // Note by Paul Pedriana: I am not sure how this should behave in the case of n == 0 and position > size. + // The standard seems to suggest that rfind doesn't act exactly the same as find in that input position + // can be > size and the return value can still be other than npos. Thus, if n == 0 then you can + // never return npos, unlike the case with find. + const size_type nLength = (size_type)(mpEnd - mpBegin); + + if(EASTL_LIKELY(n <= nLength)) + { + if(EASTL_LIKELY(n)) + { + const const_iterator pEnd = mpBegin + eastl::min_alt(nLength - n, position) + n; + const const_iterator pResult = CharTypeStringRSearch(mpBegin, pEnd, p, p + n); + + if(pResult != pEnd) + return (size_type)(pResult - mpBegin); + } + else + return eastl::min_alt(nLength, position); + } + return npos; + } + + + template + typename abstract_string::size_type + abstract_string::rfind(value_type c, size_type position) const + { + // If n is zero or position is >= size, we return npos. + const size_type nLength = (size_type)(mpEnd - mpBegin); + + if(EASTL_LIKELY(nLength)) + { + const value_type* const pEnd = mpBegin + eastl::min_alt(nLength - 1, position) + 1; + const value_type* const pResult = CharTypeStringRFind(pEnd, mpBegin, c); + + if(pResult != mpBegin) + return (size_type)((pResult - 1) - mpBegin); + } + return npos; + } + + + template + inline typename abstract_string::size_type + abstract_string::find_first_of(const this_type& x, size_type position) const + { + return find_first_of(x.mpBegin, position, (size_type)(x.mpEnd - x.mpBegin)); + } + + + template + inline typename abstract_string::size_type + abstract_string::find_first_of(const value_type* p, size_type position) const + { + return find_first_of(p, position, (size_type)CharStrlen(p)); + } + + + template + typename abstract_string::size_type + abstract_string::find_first_of(const value_type* p, size_type position, size_type n) const + { + // If position is >= size, we return npos. + if(EASTL_LIKELY((position < (size_type)(mpEnd - mpBegin)))) + { + const value_type* const pBegin = mpBegin + position; + const const_iterator pResult = CharTypeStringFindFirstOf(pBegin, mpEnd, p, p + n); + + if(pResult != mpEnd) + return (size_type)(pResult - mpBegin); + } + return npos; + } + + + template + inline typename abstract_string::size_type + abstract_string::find_first_of(value_type c, size_type position) const + { + return find(c, position); + } + + + template + inline typename abstract_string::size_type + abstract_string::find_last_of(const this_type& x, size_type position) const + { + return find_last_of(x.mpBegin, position, (size_type)(x.mpEnd - x.mpBegin)); + } + + + template + inline typename abstract_string::size_type + abstract_string::find_last_of(const value_type* p, size_type position) const + { + return find_last_of(p, position, (size_type)CharStrlen(p)); + } + + + template + typename abstract_string::size_type + abstract_string::find_last_of(const value_type* p, size_type position, size_type n) const + { + // If n is zero or position is >= size, we return npos. + const size_type nLength = (size_type)(mpEnd - mpBegin); + + if(EASTL_LIKELY(nLength)) + { + const value_type* const pEnd = mpBegin + eastl::min_alt(nLength - 1, position) + 1; + const value_type* const pResult = CharTypeStringRFindFirstOf(pEnd, mpBegin, p, p + n); + + if(pResult != mpBegin) + return (size_type)((pResult - 1) - mpBegin); + } + return npos; + } + + + template + inline typename abstract_string::size_type + abstract_string::find_last_of(value_type c, size_type position) const + { + return rfind(c, position); + } + + + template + inline typename abstract_string::size_type + abstract_string::find_first_not_of(const this_type& x, size_type position) const + { + return find_first_not_of(x.mpBegin, position, (size_type)(x.mpEnd - x.mpBegin)); + } + + + template + inline typename abstract_string::size_type + abstract_string::find_first_not_of(const value_type* p, size_type position) const + { + return find_first_not_of(p, position, (size_type)CharStrlen(p)); + } + + + template + typename abstract_string::size_type + abstract_string::find_first_not_of(const value_type* p, size_type position, size_type n) const + { + if(EASTL_LIKELY(position <= (size_type)(mpEnd - mpBegin))) + { + const const_iterator pResult = CharTypeStringFindFirstNotOf(mpBegin + position, mpEnd, p, p + n); + + if(pResult != mpEnd) + return (size_type)(pResult - mpBegin); + } + return npos; + } + + + template + typename abstract_string::size_type + abstract_string::find_first_not_of(value_type c, size_type position) const + { + if(EASTL_LIKELY(position <= (size_type)(mpEnd - mpBegin))) + { + // Todo: Possibly make a specialized version of CharTypeStringFindFirstNotOf(pBegin, pEnd, c). + const const_iterator pResult = CharTypeStringFindFirstNotOf(mpBegin + position, mpEnd, &c, &c + 1); + + if(pResult != mpEnd) + return (size_type)(pResult - mpBegin); + } + return npos; + } + + + template + inline typename abstract_string::size_type + abstract_string::find_last_not_of(const this_type& x, size_type position) const + { + return find_last_not_of(x.mpBegin, position, (size_type)(x.mpEnd - x.mpBegin)); + } + + + template + inline typename abstract_string::size_type + abstract_string::find_last_not_of(const value_type* p, size_type position) const + { + return find_last_not_of(p, position, (size_type)CharStrlen(p)); + } + + + template + typename abstract_string::size_type + abstract_string::find_last_not_of(const value_type* p, size_type position, size_type n) const + { + const size_type nLength = (size_type)(mpEnd - mpBegin); + + if(EASTL_LIKELY(nLength)) + { + const value_type* const pEnd = mpBegin + eastl::min_alt(nLength - 1, position) + 1; + const value_type* const pResult = CharTypeStringRFindFirstNotOf(pEnd, mpBegin, p, p + n); + + if(pResult != mpBegin) + return (size_type)((pResult - 1) - mpBegin); + } + return npos; + } + + + template + typename abstract_string::size_type + abstract_string::find_last_not_of(value_type c, size_type position) const + { + const size_type nLength = (size_type)(mpEnd - mpBegin); + + if(EASTL_LIKELY(nLength)) + { + // Todo: Possibly make a specialized version of CharTypeStringRFindFirstNotOf(pBegin, pEnd, c). + const value_type* const pEnd = mpBegin + eastl::min_alt(nLength - 1, position) + 1; + const value_type* const pResult = CharTypeStringRFindFirstNotOf(pEnd, mpBegin, &c, &c + 1); + + if(pResult != mpBegin) + return (size_type)((pResult - 1) - mpBegin); + } + return npos; + } + + + template + inline abstract_string abstract_string::substr(size_type position, size_type n) const + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + EASTL_FAIL_MSG("abstract_string::substr -- invalid position"); + #endif + + // We have no alternative but to create a this_type with the default global allocator. + // We cannot create a copy of ourselves with mpAllocFreeMethod because the mpAllocFreeMethod + // is intrinsically tied to an unknown subclass of this_type. We would likely get a crash + // if we tried to use mpAllocFreeMethod. + this_type x(default_allocfreemethod); + x.assign(mpBegin + position, mpBegin + position + eastl::min_alt(n, (size_type)(mpEnd - mpBegin) - position)); + return x; + } + + + template + inline int abstract_string::compare(const this_type& x) const + { + return compare(mpBegin, mpEnd, x.mpBegin, x.mpEnd); + } + + + template + inline int abstract_string::compare(size_type pos1, size_type n1, const this_type& x) const + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(pos1 > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #endif + + return compare(mpBegin + pos1, + mpBegin + pos1 + eastl::min_alt(n1, (size_type)(mpEnd - mpBegin) - pos1), + x.mpBegin, + x.mpEnd); + } + + + template + inline int abstract_string::compare(size_type pos1, size_type n1, const this_type& x, size_type pos2, size_type n2) const + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY((pos1 > (size_type)(mpEnd - mpBegin)) || (pos2 > (size_type)(x.mpEnd - x.mpBegin)))) + ThrowRangeException(); + #endif + + return compare(mpBegin + pos1, + mpBegin + pos1 + eastl::min_alt(n1, (size_type)(mpEnd - mpBegin) - pos1), + x.mpBegin + pos2, + x.mpBegin + pos2 + eastl::min_alt(n2, (size_type)(x.mpEnd - x.mpBegin) - pos2)); + } + + + template + inline int abstract_string::compare(const value_type* p) const + { + return compare(mpBegin, mpEnd, p, p + CharStrlen(p)); + } + + + template + inline int abstract_string::compare(size_type pos1, size_type n1, const value_type* p) const + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(pos1 > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #endif + + return compare(mpBegin + pos1, + mpBegin + pos1 + eastl::min_alt(n1, (size_type)(mpEnd - mpBegin) - pos1), + p, + p + CharStrlen(p)); + } + + + template + inline int abstract_string::compare(size_type pos1, size_type n1, const value_type* p, size_type n2) const + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(pos1 > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #endif + + return compare(mpBegin + pos1, + mpBegin + pos1 + eastl::min_alt(n1, (size_type)(mpEnd - mpBegin) - pos1), + p, + p + n2); + } + + + // make_lower + // This is a very simple ASCII-only case conversion function + // Anything more complicated should use a more powerful separate library. + template + inline void abstract_string::make_lower() + { + for(pointer p = mpBegin; p < mpEnd; ++p) + *p = (value_type)CharToLower(*p); + } + + + // make_upper + // This is a very simple ASCII-only case conversion function + // Anything more complicated should use a more powerful separate library. + template + inline void abstract_string::make_upper() + { + for(pointer p = mpBegin; p < mpEnd; ++p) + *p = (value_type)CharToUpper(*p); + } + + + template + inline void abstract_string::ltrim() + { + const value_type array[] = { ' ', '\t', 0 }; // This is a pretty simplistic view of whitespace. + erase(0, find_first_not_of(array)); + } + + + template + inline void abstract_string::rtrim() + { + const value_type array[] = { ' ', '\t', 0 }; // This is a pretty simplistic view of whitespace. + erase(find_last_not_of(array) + 1); + } + + + template + inline void abstract_string::trim() + { + ltrim(); + rtrim(); + } + + + template + inline abstract_string abstract_string::left(size_type n) const + { + const size_type nLength = length(); + if(n < nLength) + return substr(0, n); + return *this; + } + + + template + inline abstract_string abstract_string::right(size_type n) const + { + const size_type nLength = length(); + if(n < nLength) + return substr(nLength - n, n); + return *this; + } + + + template + inline abstract_string& abstract_string::sprintf(const value_type* pFormat, ...) + { + va_list arguments; + va_start(arguments, pFormat); + mpEnd = mpBegin; // Fast truncate to zero length. + append_sprintf_va_list(pFormat, arguments); + va_end(arguments); + + return *this; + } + + + template + abstract_string& abstract_string::sprintf_va_list(const value_type* pFormat, va_list arguments) + { + mpEnd = mpBegin; // Fast truncate to zero length. + + return append_sprintf_va_list(pFormat, arguments); + } + + + template + int abstract_string::compare(const value_type* pBegin1, const value_type* pEnd1, + const value_type* pBegin2, const value_type* pEnd2) + { + const ptrdiff_t n1 = pEnd1 - pBegin1; + const ptrdiff_t n2 = pEnd2 - pBegin2; + const ptrdiff_t nMin = eastl::min_alt(n1, n2); + const int cmp = Compare(pBegin1, pBegin2, (size_t)nMin); + + return (cmp != 0 ? cmp : (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0))); + } + + + template + int abstract_string::comparei(const value_type* pBegin1, const value_type* pEnd1, + const value_type* pBegin2, const value_type* pEnd2) + { + const ptrdiff_t n1 = pEnd1 - pBegin1; + const ptrdiff_t n2 = pEnd2 - pBegin2; + const ptrdiff_t nMin = eastl::min_alt(n1, n2); + const int cmp = CompareI(pBegin1, pBegin2, (size_t)nMin); + + return (cmp != 0 ? cmp : (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0))); + } + + + template + inline int abstract_string::comparei(const this_type& x) const + { + return comparei(mpBegin, mpEnd, x.mpBegin, x.mpEnd); + } + + + template + inline int abstract_string::comparei(const value_type* p) const + { + return comparei(mpBegin, mpEnd, p, p + CharStrlen(p)); + } + + + template + typename abstract_string::iterator + abstract_string::InsertInternal(iterator p, value_type c) + { + iterator pNewPosition = p; + + if((mpEnd + 1) < mpCapacity) + { + *(mpEnd + 1) = 0; + memmove(p + 1, p, (size_t)(mpEnd - p) * sizeof(value_type)); + *p = c; + ++mpEnd; + } + else + { + const size_type nOldSize = (size_type)(mpEnd - mpBegin); + const size_type nOldCap = (size_type)((mpCapacity - mpBegin) - 1); + const size_type nLength = eastl::max_alt((size_type)GetNewCapacity(nOldCap), (size_type)(nOldSize + 1)) + 1; // The second + 1 is to accomodate the trailing 0. + + iterator pNewBegin = DoAllocate(nLength); + iterator pNewEnd = pNewBegin; + + pNewPosition = CharStringUninitializedCopy(mpBegin, p, pNewBegin); + *pNewPosition = c; + + pNewEnd = pNewPosition + 1; + pNewEnd = CharStringUninitializedCopy(p, mpEnd, pNewEnd); + *pNewEnd = 0; + + DeallocateSelf(); + mpBegin = pNewBegin; + mpEnd = pNewEnd; + mpCapacity = pNewBegin + nLength; + } + return pNewPosition; + } + + + template + void abstract_string::SizeInitialize(size_type n, value_type c) + { + AllocateSelf((size_type)(n + 1)); // '+1' so that we have room for the terminating 0. + + mpEnd = CharStringUninitializedFillN(mpBegin, n, c); + *mpEnd = 0; + } + + + template + void abstract_string::RangeInitialize(const value_type* pBegin, const value_type* pEnd) + { + const size_type n = (size_type)(pEnd - pBegin); + + #if EASTL_STRING_OPT_ARGUMENT_ERRORS + if(EASTL_UNLIKELY(!pBegin && (n != 0))) + ThrowInvalidArgumentException(); + #endif + + AllocateSelf((size_type)(n + 1)); // '+1' so that we have room for the terminating 0. + + mpEnd = CharStringUninitializedCopy(pBegin, pEnd, mpBegin); + *mpEnd = 0; + } + + + template + inline void abstract_string::RangeInitialize(const value_type* pBegin) + { + #if EASTL_STRING_OPT_ARGUMENT_ERRORS + if(EASTL_UNLIKELY(!pBegin)) + ThrowInvalidArgumentException(); + #endif + + RangeInitialize(pBegin, pBegin + CharStrlen(pBegin)); + } + + + template + inline typename abstract_string::value_type* + abstract_string::DoAllocate(size_type n) + { + EASTL_ASSERT(n > 1); // We want n > 1 because n == 1 is reserved for empty capacity and usage of gEmptyString. + return (value_type*)(*mpAllocFreeMethod)(n * sizeof(value_type), NULL, this); + } + + + template + inline void abstract_string::DoFree(value_type* p, size_type n) + { + if(p) + (*mpAllocFreeMethod)(n * sizeof(value_type), p, this); + } + + + template + inline typename abstract_string::size_type + abstract_string::GetNewCapacity(size_type currentCapacity) // This needs to return a value of at least currentCapacity and at least 1. + { + return (currentCapacity > EASTL_STRING_INITIAL_CAPACITY) ? (2 * currentCapacity) : EASTL_STRING_INITIAL_CAPACITY; + } + + + template + inline void abstract_string::AllocateSelf() + { + EASTL_ASSERT(gEmptyString.mUint32 == 0); + mpBegin = const_cast(GetEmptyString(value_type())); + mpEnd = mpBegin; + mpCapacity = mpBegin + 1; // When we are using gEmptyString, mpCapacity is always mpEnd + 1. This is an important distinguising characteristic. + } + + + template + void abstract_string::AllocateSelf(size_type n) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(n >= 0x40000000)) + EASTL_FAIL_MSG("abstract_string::AllocateSelf -- improbably large request."); + #endif + + #if EASTL_STRING_OPT_LENGTH_ERRORS + if(EASTL_UNLIKELY(n > kMaxSize)) + ThrowLengthException(); + #endif + + if(n > 1) + { + mpBegin = DoAllocate(n); + mpEnd = mpBegin; + mpCapacity = mpBegin + n; + } + else + AllocateSelf(); + } + + + template + inline void abstract_string::DeallocateSelf() + { + // Note that we compare mpCapacity to mpEnd instead of comparing + // mpBegin to &gEmptyString. This is important because we may have + // a case whereby one library passes a string to another library to + // deallocate and the two libraries have idependent versions of gEmptyString. + if((mpCapacity - mpBegin) > 1) // If we are not using gEmptyString as our memory... + DoFree(mpBegin, (size_type)(mpCapacity - mpBegin)); + } + + + template + inline void abstract_string::ThrowLengthException() const + { + #if EASTL_EXCEPTIONS_ENABLED + throw std::length_error("abstract_string -- length_error"); + #elif EASTL_ASSERT_ENABLED + EASTL_FAIL_MSG("abstract_string -- length_error"); + #endif + } + + + template + inline void abstract_string::ThrowRangeException() const + { + #if EASTL_EXCEPTIONS_ENABLED + throw std::out_of_range("abstract_string -- out of range"); + #elif EASTL_ASSERT_ENABLED + EASTL_FAIL_MSG("abstract_string -- out of range"); + #endif + } + + + template + inline void abstract_string::ThrowInvalidArgumentException() const + { + #if EASTL_EXCEPTIONS_ENABLED + throw std::invalid_argument("abstract_string -- invalid argument"); + #elif EASTL_ASSERT_ENABLED + EASTL_FAIL_MSG("abstract_string -- invalid argument"); + #endif + } + + + // CharTypeStringFindEnd + // Specialized char version of STL find() from back function. + // Not the same as RFind because search range is specified as forward iterators. + template + const typename abstract_string::value_type* + abstract_string::CharTypeStringFindEnd(const value_type* pBegin, const value_type* pEnd, value_type c) + { + const value_type* pTemp = pEnd; + while(--pTemp >= pBegin) + { + if(*pTemp == c) + return pTemp; + } + + return pEnd; + } + + + // CharTypeStringRFind + // Specialized value_type version of STL find() function in reverse. + template + const typename abstract_string::value_type* + abstract_string::CharTypeStringRFind(const value_type* pRBegin, const value_type* pREnd, const value_type c) + { + while(pRBegin > pREnd) + { + if(*(pRBegin - 1) == c) + return pRBegin; + --pRBegin; + } + return pREnd; + } + + + // CharTypeStringSearch + // Specialized value_type version of STL search() function. + // Purpose: find p2 within p1. Return p1End if not found or if either string is zero length. + template + const typename abstract_string::value_type* + abstract_string::CharTypeStringSearch(const value_type* p1Begin, const value_type* p1End, + const value_type* p2Begin, const value_type* p2End) + { + // Test for zero length strings, in which case we have a match or a failure, + // but the return value is the same either way. + if((p1Begin == p1End) || (p2Begin == p2End)) + return p1Begin; + + // Test for a pattern of length 1. + if((p2Begin + 1) == p2End) + return eastl::find(p1Begin, p1End, *p2Begin); + + // General case. + const value_type* pTemp; + const value_type* pTemp1 = (p2Begin + 1); + const value_type* pCurrent = p1Begin; + + while(p1Begin != p1End) + { + p1Begin = eastl::find(p1Begin, p1End, *p2Begin); + if(p1Begin == p1End) + return p1End; + + pTemp = pTemp1; + pCurrent = p1Begin; + if(++pCurrent == p1End) + return p1End; + + while(*pCurrent == *pTemp) + { + if(++pTemp == p2End) + return p1Begin; + if(++pCurrent == p1End) + return p1End; + } + + ++p1Begin; + } + + return p1Begin; + } + + + // CharTypeStringRSearch + // Specialized value_type version of STL find_end() function (which really is a reverse search function). + // Purpose: find last instance of p2 within p1. Return p1End if not found or if either string is zero length. + template + const typename abstract_string::value_type* + abstract_string::CharTypeStringRSearch(const value_type* p1Begin, const value_type* p1End, + const value_type* p2Begin, const value_type* p2End) + { + // Test for zero length strings, in which case we have a match or a failure, + // but the return value is the same either way. + if((p1Begin == p1End) || (p2Begin == p2End)) + return p1Begin; + + // Test for a pattern of length 1. + if((p2Begin + 1) == p2End) + return CharTypeStringFindEnd(p1Begin, p1End, *p2Begin); + + // Test for search string length being longer than string length. + if((p2End - p2Begin) > (p1End - p1Begin)) + return p1End; + + // General case. + const value_type* pSearchEnd = (p1End - (p2End - p2Begin) + 1); + const value_type* pCurrent1; + const value_type* pCurrent2; + + while(pSearchEnd != p1Begin) + { + // Search for the last occurrence of *p2Begin. + pCurrent1 = CharTypeStringFindEnd(p1Begin, pSearchEnd, *p2Begin); + if(pCurrent1 == pSearchEnd) // If the first char of p2 wasn't found, + return p1End; // then we immediately have failure. + + // In this case, *pTemp == *p2Begin. So compare the rest. + pCurrent2 = p2Begin; + while(*pCurrent1++ == *pCurrent2++) + { + if(pCurrent2 == p2End) + return (pCurrent1 - (p2End - p2Begin)); + } + + // A smarter algorithm might know to subtract more than just one, + // but in most cases it won't make much difference anyway. + --pSearchEnd; + } + + return p1End; + } + + + // CharTypeStringFindFirstOf + // Specialized value_type version of STL find_first_of() function. + // This function is much like the C runtime strtok function, except the strings aren't null-terminated. + template + const typename abstract_string::value_type* + abstract_string::CharTypeStringFindFirstOf(const value_type* p1Begin, const value_type* p1End, + const value_type* p2Begin, const value_type* p2End) + { + for( ; p1Begin != p1End; ++p1Begin) + { + for(const value_type* pTemp = p2Begin; pTemp != p2End; ++pTemp) + { + if(*p1Begin == *pTemp) + return p1Begin; + } + } + return p1End; + } + + + // CharTypeStringRFindFirstOf + // Specialized value_type version of STL find_first_of() function in reverse. + // This function is much like the C runtime strtok function, except the strings aren't null-terminated. + template + const typename abstract_string::value_type* + abstract_string::CharTypeStringRFindFirstOf(const value_type* p1RBegin, const value_type* p1REnd, + const value_type* p2Begin, const value_type* p2End) + { + for( ; p1RBegin != p1REnd; --p1RBegin) + { + for(const value_type* pTemp = p2Begin; pTemp != p2End; ++pTemp) + { + if(*(p1RBegin - 1) == *pTemp) + return p1RBegin; + } + } + return p1REnd; + } + + + + // CharTypeStringFindFirstNotOf + // Specialized value_type version of STL find_first_not_of() function. + template + const typename abstract_string::value_type* + abstract_string::CharTypeStringFindFirstNotOf(const value_type* p1Begin, const value_type* p1End, + const value_type* p2Begin, const value_type* p2End) + { + for( ; p1Begin != p1End; ++p1Begin) + { + const value_type* pTemp; + for(pTemp = p2Begin; pTemp != p2End; ++pTemp) + { + if(*p1Begin == *pTemp) + break; + } + if(pTemp == p2End) + return p1Begin; + } + return p1End; + } + + + // CharTypeStringRFindFirstNotOf + // Specialized value_type version of STL find_first_not_of() function in reverse. + template + const typename abstract_string::value_type* + abstract_string::CharTypeStringRFindFirstNotOf(const value_type* p1RBegin, const value_type* p1REnd, + const value_type* p2Begin, const value_type* p2End) + { + for( ; p1RBegin != p1REnd; --p1RBegin) + { + const value_type* pTemp; + for(pTemp = p2Begin; pTemp != p2End; ++pTemp) + { + if(*(p1RBegin-1) == *pTemp) + break; + } + if(pTemp == p2End) + return p1RBegin; + } + return p1REnd; + } + + + template + inline bool abstract_string::validate() const + { + if((mpBegin == NULL) || (mpEnd == NULL)) + return false; + if(mpEnd < mpBegin) + return false; + if(mpCapacity < mpEnd) + return false; + return true; + } + + + template + inline int abstract_string::validate_iterator(const_iterator i) const + { + if(i >= mpBegin) + { + if(i < mpEnd) + return (isf_valid | isf_current | isf_can_dereference); + + if(i <= mpEnd) + return (isf_valid | isf_current); + } + + return isf_none; + } + + + + + // iterator operators + template + inline bool operator==(const typename abstract_string::reverse_iterator& r1, + const typename abstract_string::reverse_iterator& r2) + { + return r1.mpCurrent == r2.mpCurrent; + } + + + template + inline bool operator!=(const typename abstract_string::reverse_iterator& r1, + const typename abstract_string::reverse_iterator& r2) + { + return r1.mpCurrent != r2.mpCurrent; + } + + + // Operator + + template + basic_string operator+(const basic_string& a, const abstract_string& b) + { + typedef typename basic_string::CtorDoNotInitialize CtorDoNotInitialize; + CtorDoNotInitialize cDNI; // GCC 2.x forces us to declare a named temporary like this. + basic_string result(cDNI, a.size() + b.size(), const_cast&>(a).get_allocator()); // Note that we choose to assign a's allocator. + result.append(a); + result.append(b); + return result; + } + + + template + basic_string operator+(const typename basic_string::value_type* p, const basic_string& b) + { + typedef typename basic_string::CtorDoNotInitialize CtorDoNotInitialize; + CtorDoNotInitialize cDNI; // GCC 2.x forces us to declare a named temporary like this. + const typename basic_string::size_type n = (typename basic_string::size_type)CharStrlen(p); + basic_string result(cDNI, n + b.size(), const_cast&>(b).get_allocator()); + result.append(p, p + n); + result.append(b); + return result; + } + + + template + basic_string operator+(typename basic_string::value_type c, const basic_string& b) + { + typedef typename basic_string::CtorDoNotInitialize CtorDoNotInitialize; + CtorDoNotInitialize cDNI; // GCC 2.x forces us to declare a named temporary like this. + basic_string result(cDNI, 1 + b.size(), const_cast&>(b).get_allocator()); + result.push_back(c); + result.append(b); + return result; + } + + + template + basic_string operator+(const basic_string& a, const typename basic_string::value_type* p) + { + typedef typename basic_string::CtorDoNotInitialize CtorDoNotInitialize; + CtorDoNotInitialize cDNI; // GCC 2.x forces us to declare a named temporary like this. + const typename basic_string::size_type n = (typename basic_string::size_type)CharStrlen(p); + basic_string result(cDNI, a.size() + n, const_cast&>(a).get_allocator()); + result.append(a); + result.append(p, p + n); + return result; + } + + + template + basic_string operator+(const basic_string& a, const typename basic_string::value_type c) + { + typedef typename basic_string::CtorDoNotInitialize CtorDoNotInitialize; + CtorDoNotInitialize cDNI; // GCC 2.x forces us to declare a named temporary like this. + basic_string result(cDNI, a.size() + 1, const_cast&>(a).get_allocator()); + result.append(a); + result.push_back(c); + return result; + } + + + template + inline typename basic_string::this_type& basic_string::operator=(const this_type& x) + { + if(&x != this) + { + #if EASTL_ALLOCATOR_COPY_ENABLED + mAllocator = x.mAllocator; + #endif + + assign(x.mpBegin, x.mpEnd); + } + return *this; + } + + + template + inline basic_string& basic_string::operator=(const base_type& x) + { + if(&x != this) + { + // We are copying from our base_type, which is an interface class that doesn't define an allocator. + // and may not have one or may not have one like ours. So a copy from the base type does not attempt + // to copy the allocator. Note that we also have an operator=(const this_type&) which will in fact + // copy the allocator if the copy source is the same type as us. It would be nice if we had a mechanism + // to somehow detect that the base_type had a compatible allocator, but that can bet complicated. + //#if EASTL_ALLOCATOR_COPY_ENABLED + // mAllocator = x.mAllocator; + //#endif + + assign(x.mpBegin, x.mpEnd); + } + return *this; + } + + + template + inline basic_string& basic_string::operator=(const value_type* p) + { + return static_cast(assign(p, p + CharStrlen(p))); + } + + + template + inline basic_string& basic_string::operator=(value_type c) + { + return static_cast(assign((size_type)1, c)); + } + + + template + void basic_string::swap(this_type& x) + { + if(mAllocator == x.mAllocator) // If allocators are equivalent... + { + // We leave mAllocator as-is. + eastl::swap(mpBegin, x.mpBegin); + eastl::swap(mpEnd, x.mpEnd); + eastl::swap(mpCapacity, x.mpCapacity); + } + else // else swap the contents. + { + const this_type temp(*this); // Can't call eastl::swap because that would + *this = x; // itself call this member swap function. + x = temp; + } + } + + + template + inline basic_string basic_string::substr(size_type position, size_type n) const + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + ThrowRangeException(); + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(position > (size_type)(mpEnd - mpBegin))) + EASTL_FAIL_MSG("basic_string::substr -- invalid position"); + #endif + + this_type x(mpAllocFreeMethod); + x.assign(mpBegin + position, mpBegin + position + eastl::min_alt(n, (size_type)(mpEnd - mpBegin) - position)); + return x; + } + + + template + inline basic_string basic_string::left(size_type n) const + { + const size_type nLength = length(); + if(n < nLength) + return substr(0, n); + return *this; + } + + + template + inline basic_string basic_string::right(size_type n) const + { + const size_type nLength = length(); + if(n < nLength) + return substr(nLength - n, n); + return *this; + } + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + // Operator== and operator!= + template + inline bool operator==(const abstract_string& a, const abstract_string& b) + { + return ((a.size() == b.size()) && (memcmp(a.data(), b.data(), (size_t)a.size() * sizeof(typename abstract_string::value_type)) == 0)); + } + + + template + inline bool operator==(const typename abstract_string::value_type* p, const abstract_string& b) + { + typedef typename abstract_string::size_type size_type; + const size_type n = (size_type)CharStrlen(p); + return ((n == b.size()) && (memcmp(p, b.data(), (size_t)n * sizeof(*p)) == 0)); + } + + + template + inline bool operator==(const abstract_string& a, const typename abstract_string::value_type* p) + { + typedef typename abstract_string::size_type size_type; + const size_type n = (size_type)CharStrlen(p); + return ((a.size() == n) && (memcmp(a.data(), p, (size_t)n * sizeof(*p)) == 0)); + } + + + template + inline bool operator!=(const abstract_string& a, const abstract_string& b) + { + return !(a == b); + } + + + template + inline bool operator!=(const typename abstract_string::value_type* p, const abstract_string& b) + { + return !(p == b); + } + + + template + inline bool operator!=(const abstract_string& a, const typename abstract_string::value_type* p) + { + return !(a == p); + } + + + // Operator< (and also >, <=, and >=). + template + inline bool operator<(const abstract_string& a, const abstract_string& b) + { + return abstract_string::compare(a.begin(), a.end(), b.begin(), b.end()) < 0; + } + + + template + inline bool operator<(const typename abstract_string::value_type* p, const abstract_string& b) + { + typedef typename abstract_string::size_type size_type; + const size_type n = (size_type)CharStrlen(p); + return basic_string::compare(p, p + n, b.begin(), b.end()) < 0; + } + + + template + inline bool operator<(const abstract_string& a, const typename abstract_string::value_type* p) + { + typedef typename abstract_string::size_type size_type; + const size_type n = (size_type)CharStrlen(p); + return abstract_string::compare(a.begin(), a.end(), p, p + n) < 0; + } + + + template + inline bool operator>(const abstract_string& a, const abstract_string& b) + { + return b < a; + } + + + template + inline bool operator>(const typename abstract_string::value_type* p, const abstract_string& b) + { + return b < p; + } + + + template + inline bool operator>(const abstract_string& a, const typename abstract_string::value_type* p) + { + return p < a; + } + + + template + inline bool operator<=(const abstract_string& a, const abstract_string& b) + { + return !(b < a); + } + + + template + inline bool operator<=(const typename abstract_string::value_type* p, const abstract_string& b) + { + return !(b < p); + } + + + template + inline bool operator<=(const abstract_string& a, const typename abstract_string::value_type* p) + { + return !(p < a); + } + + + template + inline bool operator>=(const abstract_string& a, const abstract_string& b) + { + return !(a < b); + } + + + template + inline bool operator>=(const typename abstract_string::value_type* p, const abstract_string& b) + { + return !(p < b); + } + + + template + inline bool operator>=(const abstract_string& a, const typename abstract_string::value_type* p) + { + return !(a < p); + } + + + template + inline void swap(abstract_string& a, abstract_string& b) + { + a.swap(b); + } + + + + /// string / wstring + typedef basic_string string; + typedef basic_string wstring; + + /// string8 / string16 / string32 + typedef basic_string string8; + typedef basic_string string16; + typedef basic_string string32; + + + + /// hash + /// + /// We provide EASTL hash function objects for use in hash table containers. + /// + /// Example usage: + /// #include + /// hash_set stringHashSet; + /// + template struct hash; + + template <> + struct hash + { + size_t operator()(const string& x) const + { + const unsigned char* p = (const unsigned char*)x.c_str(); // To consider: limit p to at most 256 chars. + unsigned int c, result = 2166136261U; // We implement an FNV-like string hash. + while((c = *p++) != 0) // Using '!=' disables compiler warnings. + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + + template <> + struct hash + { + size_t operator()(const string16& x) const + { + const char16_t* p = x.c_str(); + unsigned int c, result = 2166136261U; + while((c = *p++) != 0) + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + + template <> + struct hash + { + size_t operator()(const string32& x) const + { + const char32_t* p = x.c_str(); + unsigned int c, result = 2166136261U; + while((c = (unsigned int)*p++) != 0) + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + + #if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE + template <> + struct hash + { + size_t operator()(const wstring& x) const + { + const wchar_t* p = x.c_str(); + unsigned int c, result = 2166136261U; + while((c = (unsigned int)*p++) != 0) + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + #endif + + +} // namespace eastl + + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + + +#endif // Header include guard + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/chrono.h b/libs/eastl/include/EASTL/chrono.h new file mode 100644 index 0000000..8f9be94 --- /dev/null +++ b/libs/eastl/include/EASTL/chrono.h @@ -0,0 +1,712 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// This file implements the eastl::chrono specification which is part of the +// standard STL date and time library. eastl::chrono implements all the +// mechanisms required to capture and manipulate times retrieved from the +// provided clocks. It implements the all of the features to allow type safe +// durations to be used in code. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_CHRONO_H +#define EASTL_CHRONO_H + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include +#include +#include +#include + + +// TODO: move to platform specific cpp or header file +#if defined EA_PLATFORM_MICROSOFT + #pragma warning(push, 0) + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + EA_DISABLE_ALL_VC_WARNINGS() + #undef NOMINMAX + #define NOMINMAX + #include + EA_RESTORE_ALL_VC_WARNINGS() + #pragma warning(pop) +#endif + +#if defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_MINGW) + #include +#elif defined(EA_PLATFORM_APPLE) + #include +#elif defined(EA_PLATFORM_POSIX) || defined(EA_PLATFORM_MINGW) || defined(EA_PLATFORM_ANDROID) + // Posix means Linux, Unix, and Macintosh OSX, among others (including Linux-based mobile platforms). + #if defined(EA_PLATFORM_MINGW) + #include + #endif + #include + #if (defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC)) + #include + #else + #include + #include + #endif +#endif + + +namespace eastl +{ +namespace chrono +{ + /////////////////////////////////////////////////////////////////////////////// + // treat_as_floating_point + /////////////////////////////////////////////////////////////////////////////// + template + struct treat_as_floating_point : is_floating_point {}; + + + /////////////////////////////////////////////////////////////////////////////// + // 20.12.4, duration_values + /////////////////////////////////////////////////////////////////////////////// + template + struct duration_values + { + public: + EASTL_FORCE_INLINE static EA_CONSTEXPR Rep zero() { return Rep(0); } + EASTL_FORCE_INLINE static EA_CONSTEXPR Rep max() { return eastl::numeric_limits::max(); } + EASTL_FORCE_INLINE static EA_CONSTEXPR Rep min() { return eastl::numeric_limits::lowest(); } + }; + + + /////////////////////////////////////////////////////////////////////////////// + // duration fwd_decl + /////////////////////////////////////////////////////////////////////////////// + template > + class duration; + + + namespace Internal + { + /////////////////////////////////////////////////////////////////////////////// + // IsRatio + /////////////////////////////////////////////////////////////////////////////// + template struct IsRatio : eastl::false_type {}; + template struct IsRatio> : eastl::true_type {}; + template struct IsRatio> : eastl::true_type {}; + template struct IsRatio> : eastl::true_type {}; + template struct IsRatio> : eastl::true_type {}; + + + /////////////////////////////////////////////////////////////////////////////// + // IsDuration + /////////////////////////////////////////////////////////////////////////////// + template struct IsDuration : eastl::false_type{}; + template struct IsDuration> : eastl::true_type{}; + template struct IsDuration> : eastl::true_type{}; + template struct IsDuration> : eastl::true_type{}; + template struct IsDuration> : eastl::true_type{}; + + + /////////////////////////////////////////////////////////////////////////////// + // RatioGCD + /////////////////////////////////////////////////////////////////////////////// + template + struct RatioGCD + { + static_assert(IsRatio::value, "Period1 is not a eastl::ratio type"); + static_assert(IsRatio::value, "Period2 is not a eastl::ratio type"); + + typedef ratio::value, + eastl::Internal::lcm::value> type; + }; + }; + + + /////////////////////////////////////////////////////////////////////////////// + // 20.12.5.7, duration_cast + /////////////////////////////////////////////////////////////////////////////// + namespace Internal + { + template ::type, + typename CommonRep = typename eastl::decay::type>::type, + bool = CommonPeriod::num == 1, + bool = CommonPeriod::den == 1> + struct DurationCastImpl; + + template + struct DurationCastImpl + { + inline static ToDuration DoCast(const FromDuration& fd) + { + return ToDuration(static_cast(fd.count())); + } + }; + + template + struct DurationCastImpl + { + inline static ToDuration DoCast(const FromDuration& d) + { + return ToDuration(static_cast(static_cast(d.count()) * + static_cast(CommonPeriod::num))); + } + }; + + template + struct DurationCastImpl + { + inline static ToDuration DoCast(const FromDuration& d) + { + return ToDuration(static_cast(static_cast(d.count()) / + static_cast(CommonPeriod::den))); + } + }; + + template + struct DurationCastImpl + { + inline static ToDuration DoCast(const FromDuration& d) + { + return ToDuration(static_cast(static_cast(d.count()) * + static_cast(CommonPeriod::num) / + static_cast(CommonPeriod::den))); + } + }; + }; // namespace Internal + + + /////////////////////////////////////////////////////////////////////////////// + // duration_cast + /////////////////////////////////////////////////////////////////////////////// + template + inline typename eastl::enable_if::value, ToDuration>::type + duration_cast(const duration& d) + { + typedef typename duration::this_type FromDuration; + return Internal::DurationCastImpl::DoCast(d); + } + + + /////////////////////////////////////////////////////////////////////////////// + // duration + /////////////////////////////////////////////////////////////////////////////// + template + class duration + { + Rep mRep; + + public: + typedef Rep rep; + typedef Period period; + typedef duration this_type; + + #if defined(EA_COMPILER_NO_DEFAULTED_FUNCTIONS) || defined(CS_UNDEFINED_STRING) + EA_CONSTEXPR duration() + : mRep() {} + + duration(const duration& other) + : mRep(Rep(other.mRep)) {} + + duration& operator=(const duration& other) + { mRep = other.mRep; } + #else + EA_CONSTEXPR duration() = default; + duration(const duration&) = default; + duration& operator=(const duration&) = default; + #endif + + + /////////////////////////////////////////////////////////////////////////////// + // conversion constructors + /////////////////////////////////////////////////////////////////////////////// + template + inline EA_CONSTEXPR explicit duration( + const Rep2& rep2, + typename eastl::enable_if::value && + (treat_as_floating_point::value || + !treat_as_floating_point::value)>::type** = 0) + : mRep(static_cast(rep2)) {} + + + template + EA_CONSTEXPR duration(const duration& d2, + typename eastl::enable_if::value || + (eastl::ratio_divide::type::den == 1 && + !treat_as_floating_point::value), + void>::type** = 0) + : mRep(duration_cast(d2).count()) {} + + /////////////////////////////////////////////////////////////////////////////// + // returns the count of ticks + /////////////////////////////////////////////////////////////////////////////// + EA_CONSTEXPR Rep count() const { return mRep; } + + /////////////////////////////////////////////////////////////////////////////// + // static accessors of special duration values + /////////////////////////////////////////////////////////////////////////////// + EA_CONSTEXPR inline static duration zero() { return duration(duration_values::zero()); } + EA_CONSTEXPR inline static duration min() { return duration(duration_values::min()); } + EA_CONSTEXPR inline static duration max() { return duration(duration_values::max()); } + + /////////////////////////////////////////////////////////////////////////////// + // const arithmetic operations + /////////////////////////////////////////////////////////////////////////////// + EA_CONSTEXPR inline duration operator+() const { return *this; } + EA_CONSTEXPR inline duration operator-() const { return duration(0-mRep); } + + /////////////////////////////////////////////////////////////////////////////// + // arithmetic operations + /////////////////////////////////////////////////////////////////////////////// + inline duration operator++(int) { return duration(mRep++); } + inline duration operator--(int) { return duration(mRep--); } + inline duration& operator++() { ++mRep; return *this; } + inline duration& operator--() { --mRep; return *this; } + inline duration& operator+=(const duration& d) { mRep += d.count(); return *this; } + inline duration& operator-=(const duration& d) { mRep -= d.count(); return *this; } + inline duration& operator*=(const Rep& rhs) { mRep *= rhs; return *this; } + inline duration& operator/=(const Rep& rhs) { mRep /= rhs; return *this; } + inline duration& operator%=(const Rep& rhs) { mRep %= rhs; return *this; } + inline duration& operator%=(const duration& d) { mRep %= d.count(); return *this; } + }; + + + /////////////////////////////////////////////////////////////////////////////// + // 20.12.5.5, arithmetic operations with durations as arguments + /////////////////////////////////////////////////////////////////////////////// + template + typename eastl::common_type, duration>::type EASTL_FORCE_INLINE + operator+(const duration& lhs, const duration& rhs) + { + typedef typename eastl::common_type, duration>::type common_duration_t; + return common_duration_t(common_duration_t(lhs).count() + common_duration_t(rhs).count()); + } + + template + typename eastl::common_type, duration>::type EASTL_FORCE_INLINE + operator-(const duration& lhs, const duration& rhs) + { + typedef typename eastl::common_type, duration>::type common_duration_t; + return common_duration_t(common_duration_t(lhs).count() - common_duration_t(rhs).count()); + } + + template + duration::type, Period1> EASTL_FORCE_INLINE + operator*(const duration& lhs, const Rep2& rhs) + { + typedef typename duration, Period1>::type common_duration_t; + return common_duration_t(common_duration_t(lhs).count() * rhs); + } + + template + duration::type, Period2> EASTL_FORCE_INLINE + operator*(const Rep1& lhs, const duration& rhs) + { + typedef duration::type, Period2> common_duration_t; + return common_duration_t(lhs * common_duration_t(rhs).count()); + } + + template + duration::type, Period1> EASTL_FORCE_INLINE + operator/(const duration& lhs, const Rep2& rhs) + { + typedef duration::type, Period1> common_duration_t; + return common_duration_t(common_duration_t(lhs).count() / rhs); + } + + template + typename eastl::common_type, duration>::type EASTL_FORCE_INLINE + operator/(const duration& lhs, const duration& rhs) + { + typedef typename eastl::common_type, duration>::type common_duration_t; + return common_duration_t(common_duration_t(lhs).count() / common_duration_t(rhs).count()); + } + + template + duration::type, Period1> EASTL_FORCE_INLINE + operator%(const duration& lhs, const Rep2& rhs) + { + typedef duration::type, Period1> common_duration_t; + return common_duration_t(common_duration_t(lhs).count() % rhs); + } + + template + typename eastl::common_type, duration>::type EASTL_FORCE_INLINE + operator%(const duration& lhs, const duration& rhs) + { + typedef typename eastl::common_type, duration>::type common_duration_t; + return common_duration_t(common_duration_t(lhs).count() % common_duration_t(rhs).count()); + } + + + /////////////////////////////////////////////////////////////////////////////// + // 20.12.5.6, compares two durations + /////////////////////////////////////////////////////////////////////////////// + template + EASTL_FORCE_INLINE bool operator==(const duration& lhs, + const duration& rhs) + { + typedef typename eastl::common_type, duration>::type common_duration_t; + return common_duration_t(lhs).count() == common_duration_t(rhs).count(); + } + + template + EASTL_FORCE_INLINE bool operator<(const duration& lhs, + const duration& rhs) + { + typedef typename eastl::common_type, duration>::type common_duration_t; + return common_duration_t(lhs).count() < common_duration_t(rhs).count(); + } + + template + EASTL_FORCE_INLINE bool operator!=(const duration& lhs, + const duration& rhs) + { + return !(lhs == rhs); + } + + template + EASTL_FORCE_INLINE bool operator<=(const duration& lhs, + const duration& rhs) + { + return !(rhs < lhs); + } + + template + EASTL_FORCE_INLINE bool operator>(const duration& lhs, + const duration& rhs) + { + return rhs < lhs; + } + + template + EASTL_FORCE_INLINE bool operator>=(const duration& lhs, + const duration& rhs) + { + return !(lhs < rhs); + } + + + /////////////////////////////////////////////////////////////////////////////// + // standard duration units + /////////////////////////////////////////////////////////////////////////////// + typedef duration nanoseconds; + typedef duration microseconds; + typedef duration milliseconds; + typedef duration seconds; + typedef duration> minutes; + typedef duration> hours; + + + /////////////////////////////////////////////////////////////////////////////// + // 20.12.6, time_point + /////////////////////////////////////////////////////////////////////////////// + template + class time_point + { + Duration mDuration; + + public: + typedef Clock clock; + typedef Duration duration; + typedef typename Duration::rep rep; + typedef typename Duration::period period; + + inline EA_CONSTEXPR time_point() : mDuration(Duration::zero()) {} + EA_CONSTEXPR explicit time_point(const Duration& other) : mDuration(other) {} + + template + inline EA_CONSTEXPR time_point( + const time_point& t, + typename eastl::enable_if::value>::type** = 0) + : mDuration(t.time_since_epoch()) {} + + EA_CONSTEXPR Duration time_since_epoch() const { return mDuration; } + + time_point& operator+=(const Duration& d) { mDuration += d; return *this; } + time_point& operator-=(const Duration& d) { mDuration -= d; return *this; } + + static EA_CONSTEXPR time_point min() { return time_point(Duration::min()); } + static EA_CONSTEXPR time_point max() { return time_point(Duration::max()); } + }; + + + /////////////////////////////////////////////////////////////////////////////// + // 20.12.6.5, time_point arithmetic + /////////////////////////////////////////////////////////////////////////////// + template + inline EA_CONSTEXPR time_point>::type> + operator+(const time_point& lhs, const duration& rhs) + { + typedef time_point>::type> common_timepoint_t; + return common_timepoint_t(lhs.time_since_epoch() + rhs); + } + + template + inline EA_CONSTEXPR time_point>::type> + operator+(const duration& lhs, const time_point& rhs) + { + typedef time_point>::type> common_timepoint_t; + return common_timepoint_t(lhs + rhs.time_since_epoch()); + } + + template + inline EA_CONSTEXPR time_point>::type> + operator-(const time_point& lhs, const duration& rhs) + { + typedef time_point>::type> common_timepoint_t; + return common_timepoint_t(lhs.time_since_epoch() - rhs); + } + + template + inline EA_CONSTEXPR typename eastl::common_type::type operator-( + const time_point& lhs, + const time_point& rhs) + { + return lhs.time_since_epoch() - rhs.time_since_epoch(); + } + + template + inline EA_CONSTEXPR bool operator==(const time_point& lhs, + const time_point& rhs) + { + return lhs.time_since_epoch() == rhs.time_since_epoch(); + } + + template + inline EA_CONSTEXPR bool operator!=(const time_point& lhs, + const time_point& rhs) + { + return !(lhs == rhs); + } + + template + inline EA_CONSTEXPR bool operator<(const time_point& lhs, const time_point& rhs) + { + return lhs.time_since_epoch() < rhs.time_since_epoch(); + } + + template + inline EA_CONSTEXPR bool operator<=(const time_point& lhs, + const time_point& rhs) + { + return !(rhs < lhs); + } + + template + inline EA_CONSTEXPR bool operator>(const time_point& lhs, const time_point& rhs) + { + return rhs < lhs; + } + + template + inline EA_CONSTEXPR bool operator>=(const time_point& lhs, + const time_point& rhs) + { + return !(lhs < rhs); + } + + + /////////////////////////////////////////////////////////////////////////////// + // 20.12.6.7, time_point_cast + /////////////////////////////////////////////////////////////////////////////// + template + EA_CONSTEXPR time_point time_point_cast( + const time_point& t, + typename eastl::enable_if::value>::type** = 0) + { + return time_point(duration_cast(t.time_since_epoch())); + } + + + /////////////////////////////////////////////////////////////////////////////// + // 20.12.7, clocks + /////////////////////////////////////////////////////////////////////////////// + + namespace Internal + { + #if defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_MINGW) + #define EASTL_NS_PER_TICK _XTIME_NSECS_PER_TICK + #elif defined EA_PLATFORM_POSIX + #define EASTL_NS_PER_TICK _XTIME_NSECS_PER_TICK + #else + #define EASTL_NS_PER_TICK 100 + #endif + + #if defined(EA_PLATFORM_POSIX) + typedef chrono::nanoseconds::period SystemClock_Period; + typedef chrono::nanoseconds::period SteadyClock_Period; + #else + typedef eastl::ratio_multiply, nano>::type SystemClock_Period; + typedef eastl::ratio_multiply, nano>::type SteadyClock_Period; + #endif + + + /////////////////////////////////////////////////////////////////////////////// + // Internal::GetTicks + /////////////////////////////////////////////////////////////////////////////// + uint64_t GetTicks() + { + #if defined EA_PLATFORM_MICROSOFT + uint64_t t; + QueryPerformanceCounter(reinterpret_cast(&t)); // TODO: migrate to rdtsc? + return t; + #elif defined(EA_PLATFORM_APPLE) + return mach_absolute_time(); + #elif defined(EA_PLATFORM_POSIX) // Posix means Linux, Unix, and Macintosh OSX, among others (including Linux-based mobile platforms). + #if (defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC)) + timespec ts; + int result = clock_gettime(CLOCK_MONOTONIC, &ts); + + if (result == EINVAL) + result = clock_gettime(CLOCK_REALTIME, &ts); + + const uint64_t nNanoseconds = (uint64_t)ts.tv_nsec + ((uint64_t)ts.tv_sec * UINT64_C(1000000000)); + return nNanoseconds; + #else + struct timeval tv; + gettimeofday(&tv, NULL); + const uint64_t nMicroseconds = (uint64_t)tv.tv_usec + ((uint64_t)tv.tv_sec * 1000000); + return nMicroseconds; + #endif + #else + #error "chrono not implemented for platform" + #endif + } + } // namespace Internal + + + /////////////////////////////////////////////////////////////////////////////// + // system_clock + /////////////////////////////////////////////////////////////////////////////// + class system_clock + { + public: + typedef long long rep; // signed arithmetic type representing the number of ticks in the clock's duration + typedef Internal::SystemClock_Period period; + typedef chrono::duration duration; // duration, capable of representing negative durations + typedef chrono::time_point time_point; + + // true if the time between ticks is always increases monotonically + EA_CONSTEXPR_OR_CONST static bool is_steady = false; + + // returns a time point representing the current point in time. + static time_point now() EA_NOEXCEPT + { + return time_point(duration(Internal::GetTicks())); + } + }; + + + /////////////////////////////////////////////////////////////////////////////// + // steady_clock + /////////////////////////////////////////////////////////////////////////////// + class steady_clock + { + public: + typedef long long rep; // signed arithmetic type representing the number of ticks in the clock's duration + typedef Internal::SteadyClock_Period period; + typedef chrono::duration duration; // duration, capable of representing negative durations + typedef chrono::time_point time_point; + + // true if the time between ticks is always increases monotonically + EA_CONSTEXPR_OR_CONST static bool is_steady = true; + + // returns a time point representing the current point in time. + static time_point now() EA_NOEXCEPT + { + return time_point(duration(Internal::GetTicks())); + } + }; + + + /////////////////////////////////////////////////////////////////////////////// + // high_resolution_clock + /////////////////////////////////////////////////////////////////////////////// + typedef system_clock high_resolution_clock; + + +} // namespace chrono + + + /////////////////////////////////////////////////////////////////////////////// + // duration common_type specialization + /////////////////////////////////////////////////////////////////////////////// + template + struct common_type, chrono::duration> + { + typedef chrono::duration::type>::type, + typename chrono::Internal::RatioGCD::type> type; + }; + + + /////////////////////////////////////////////////////////////////////////////// + // time_point common_type specialization + /////////////////////////////////////////////////////////////////////////////// + template + struct common_type, chrono::time_point> + { + typedef chrono::time_point::type> type; + }; + + + /////////////////////////////////////////////////////////////////////////////// + // chrono_literals + /////////////////////////////////////////////////////////////////////////////// +#if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED + EA_DISABLE_VC_WARNING(4455) // disable warning C4455: literal suffix identifiers that do not start with an underscore are reserved + inline namespace literals + { + inline namespace chrono_literals + { + /////////////////////////////////////////////////////////////////////////////// + // integer chrono literals + /////////////////////////////////////////////////////////////////////////////// + EA_CONSTEXPR chrono::hours operator"" h(unsigned long long h) { return chrono::hours(h); } + EA_CONSTEXPR chrono::minutes operator"" min(unsigned long long m) { return chrono::minutes(m); } + EA_CONSTEXPR chrono::seconds operator"" s(unsigned long long s) { return chrono::seconds(s); } + EA_CONSTEXPR chrono::milliseconds operator"" ms(unsigned long long ms) { return chrono::milliseconds(ms); } + EA_CONSTEXPR chrono::microseconds operator"" us(unsigned long long us) { return chrono::microseconds(us); } + EA_CONSTEXPR chrono::nanoseconds operator"" ns(unsigned long long ns) { return chrono::nanoseconds(ns); } + + /////////////////////////////////////////////////////////////////////////////// + // float chrono literals + /////////////////////////////////////////////////////////////////////////////// + EA_CONSTEXPR chrono::duration> operator"" h(long double h) + { return chrono::duration>(h); } + EA_CONSTEXPR chrono::duration> operator"" min(long double m) + { return chrono::duration>(m); } + EA_CONSTEXPR chrono::duration operator"" s(long double s) + { return chrono::duration(s); } + EA_CONSTEXPR chrono::duration operator"" ms(long double ms) + { return chrono::duration(ms); } + EA_CONSTEXPR chrono::duration operator"" us(long double us) + { return chrono::duration(us); } + EA_CONSTEXPR chrono::duration operator"" ns(long double ns) + { return chrono::duration(ns); } + + } // namespace chrono_literals + }// namespace literals + EA_RESTORE_VC_WARNING() // warning: 4455 +#endif + +} // namespace eastl + + +#if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED +namespace chrono +{ + using namespace literals::chrono_literals; +} // namespace chrono +#endif + + +#endif diff --git a/libs/eastl/include/EASTL/core_allocator.h b/libs/eastl/include/EASTL/core_allocator.h new file mode 100644 index 0000000..0a28d23 --- /dev/null +++ b/libs/eastl/include/EASTL/core_allocator.h @@ -0,0 +1,75 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_CORE_ALLOCATOR_H +#define EASTL_CORE_ALLOCATOR_H + +#if EASTL_CORE_ALLOCATOR_ENABLED + +#include + +namespace EA +{ + namespace Allocator + { + /// EASTLCoreAllocatorImpl + /// + /// EASTL provides an out of the box implementation of the + /// ICoreAllocator interface. This is provided as a convenience for + /// users who wish to provide ICoreAllocator implementations for EASTL to use. + /// + /// EASTL has a dependency on coreallocator so to provide an out of + /// the box implementation for EASTLCoreAlloctor and EASTLCoreDeleter + /// that can be used and tested. Historically we could not test + /// ICoreAllocator interface because we relied on the code being linked + /// in user code. + /// + + class EASTLCoreAllocatorImpl : public ICoreAllocator + { + public: + virtual void* Alloc(size_t size, const char* name, unsigned int flags) + { + return ::operator new[](size, name, flags, 0, __FILE__, __LINE__); + } + + virtual void* Alloc(size_t size, const char* name, unsigned int flags, unsigned int alignment, unsigned int alignOffset = 0) + { + return ::operator new[](size, alignment, alignOffset, name, flags, 0, __FILE__, __LINE__); + } + + virtual void Free(void* ptr, size_t size = 0) + { + ::operator delete(static_cast(ptr)); + } + + virtual void* AllocDebug(size_t size, const DebugParams debugParams, unsigned int flags) + { + return Alloc(size, debugParams.mName, flags); + } + + virtual void* AllocDebug(size_t size, const DebugParams debugParams, unsigned int flags, unsigned int align, unsigned int alignOffset = 0) + { + return Alloc(size, debugParams.mName, flags, align, alignOffset); + } + + static EASTLCoreAllocatorImpl* GetDefaultAllocator(); + }; + + EASTLCoreAllocatorImpl* EASTLCoreAllocatorImpl::GetDefaultAllocator() + { + EA_DISABLE_VC_WARNING(4640) // disable warning : "warning C4640: 'allocator' : construction of local static object is not thread-safe" + // Given that EASTLCoreAllocatorImpl doesn't contain any member data, and doesn't need to execute any code during construction, construcion + // of this static variable should be thread-safe despite the warning MSVC normally generates. + static EASTLCoreAllocatorImpl allocator; + EA_RESTORE_VC_WARNING() + + return &allocator; + } + } +} + +#endif // EASTL_CORE_ALLOCATOR_ENABLED +#endif // EASTL_CORE_ALLOCATOR_H + diff --git a/libs/eastl/include/EASTL/core_allocator_adapter.h b/libs/eastl/include/EASTL/core_allocator_adapter.h new file mode 100644 index 0000000..3fa66b7 --- /dev/null +++ b/libs/eastl/include/EASTL/core_allocator_adapter.h @@ -0,0 +1,364 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Implements an EASTL allocator that uses an ICoreAllocator. +// However, this header file is not dependent on ICoreAllocator or its package. +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_CORE_ALLOCATOR_ADAPTER_H +#define EASTL_CORE_ALLOCATOR_ADAPTER_H + +#if EASTL_CORE_ALLOCATOR_ENABLED + + +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + +/// EASTL_CORE_ALLOCATOR_ADAPTER_GET_DEFAULT_CORE_ALLOCATOR +/// +/// This allows the application to override the default name for the default global core allocator. +/// However, you must be careful in your usage of this, as if this file is shared between uses then +/// you will need to be careful that your override of this doesn't conflict with others. +/// +#ifndef EASTL_CORE_ALLOCATOR_ADAPTER_GET_DEFAULT_CORE_ALLOCATOR + #define EASTL_CORE_ALLOCATOR_ADAPTER_GET_DEFAULT_CORE_ALLOCATOR AllocatorType::GetDefaultAllocator +#endif + + + +namespace EA +{ + namespace Allocator + { + /// CoreAllocatorAdapter + /// + /// Implements the EASTL allocator interface. + /// Allocates memory from an instance of ICoreAllocator or another class with an equivalent interface. + /// ICoreAllocator is a pure-virtual memory allocation interface used by a number of EA games and + /// shared libraries. It's completely unrelated to EASTL, but it's prevalent enough that it's useful + /// for EASTL to have a built-in adapter for this interface. ICoreAllocator is declared in the + /// CoreAllocator package icoreallocator_interface.h header, but CoreAllocatorAdapter can work with + /// any equivalent interface, as defined below. + /// + /// Expected interface: + /// enum AllocFlags { + /// kFlagTempMemory = 0, + /// kFlagPermMemory = 1 + /// }; + /// + /// struct CoreAllocator { + /// void* Alloc(size_t size, const char* name, unsigned int allocFlags); + /// void* Alloc(size_t size, const char* name, unsigned int allocFlags, // Not required unless you are working with types that require custom alignment. + /// unsigned int align, unsigned int alignOffset = 0); + /// void Free(void* block, size_t size = 0); + /// static CoreAllocator* GetDefaultAllocator(); + /// }; + /// + /// Example usage: + /// #include + /// typedef EA::Allocator::CoreAllocatorAdapter Adapter; + /// eastl::list widgetList(Adapter("UI/WidgetList", pSomeCoreAllocator)); + /// widgetList.push_back(Widget()); + /// + /// Example usage: + /// #include + /// eastl::list > widgetList; + /// widgetList.push_back(Widget()); + /// + /// Example usage: + /// #include + /// typedef EA::Allocator::CoreAllocatorAdapter Adapter; + /// typedef eastl::list WidgetList; + /// CoreAllocatorFixed widgetCoreAllocator(pFixedAllocatorForWidgetListValueType); // CoreAllocatorFixed is a hypothetical implementation of the ICoreAllocator interface. + /// WidgetList widgetList(Adapter("UI/WidgetList", &widgetCoreAllocator)); // Note that the widgetCoreAllocator is declared before and thus destroyed after the widget list. + /// + template + class CoreAllocatorAdapter + { + public: + typedef CoreAllocatorAdapter this_type; + + public: + // To do: Make this constructor explicit, when there is no known code dependent on it being otherwise. + CoreAllocatorAdapter(const char* pName = EASTL_NAME_VAL(EASTL_ALLOCATOR_DEFAULT_NAME), AllocatorType* pAllocator = EASTL_CORE_ALLOCATOR_ADAPTER_GET_DEFAULT_CORE_ALLOCATOR()); + CoreAllocatorAdapter(const char* pName, AllocatorType* pAllocator, int flags); + CoreAllocatorAdapter(const CoreAllocatorAdapter& x); + CoreAllocatorAdapter(const CoreAllocatorAdapter& x, const char* pName); + + CoreAllocatorAdapter& operator=(const CoreAllocatorAdapter& x); + + void* allocate(size_t n, int flags = 0); + void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0); + void deallocate(void* p, size_t n); + + AllocatorType* get_allocator() const; + void set_allocator(AllocatorType* pAllocator); + + int get_flags() const; + void set_flags(int flags); + + const char* get_name() const; + void set_name(const char* pName); + + public: // Public because otherwise VC++ generates (possibly invalid) warnings about inline friend template specializations. + AllocatorType* mpCoreAllocator; + int mnFlags; // Allocation flags. See ICoreAllocator/AllocFlags. + + #if EASTL_NAME_ENABLED + const char* mpName; // Debug name, used to track memory. + #endif + }; + + template + bool operator==(const CoreAllocatorAdapter& a, const CoreAllocatorAdapter& b); + + template + bool operator!=(const CoreAllocatorAdapter& a, const CoreAllocatorAdapter& b); + + + + /// EASTLICoreAllocator + /// + /// Provides a standardized typedef for ICoreAllocator; + /// + /// Example usage: + /// eastl::list widgetList("UI/WidgetList", pSomeCoreAllocator); + /// widgetList.push_back(Widget()); + /// + class ICoreAllocator; + class EASTLCoreAllocatorImpl; + + typedef CoreAllocatorAdapter EASTLICoreAllocatorAdapter; + typedef CoreAllocatorAdapter EASTLCoreAllocatorAdapter; + typedef EASTLICoreAllocatorAdapter EASTLICoreAllocator; // for backwards compatibility + + + + /// EASTLICoreDeleter + /// + /// Implements a functor which can free memory from the specified + /// ICoreAllocator interface. This is a convenience object provided for + /// users who wish to have EASTL containers deallocate memory obtained from + /// ICoreAllocator interfaces. + /// + template + class CoreDeleterAdapter + { + public: + typedef CoreDeleterAdapter this_type; + AllocatorType* mpCoreAllocator; + + public: + CoreDeleterAdapter(AllocatorType* pAllocator = EASTL_CORE_ALLOCATOR_ADAPTER_GET_DEFAULT_CORE_ALLOCATOR()) EA_NOEXCEPT + : mpCoreAllocator(pAllocator) {} + + ~CoreDeleterAdapter() EA_NOEXCEPT {} + + template + void operator()(T* p) { mpCoreAllocator->Free(p); } + + CoreDeleterAdapter(const CoreDeleterAdapter& in) { mpCoreAllocator = in.mpCoreAllocator; } + + #if EASTL_MOVE_SEMANTICS_ENABLED + CoreDeleterAdapter(CoreDeleterAdapter&& in) + { + mpCoreAllocator = in.mpCoreAllocator; + in.mpCoreAllocator = nullptr; + } + + CoreDeleterAdapter& operator=(const CoreDeleterAdapter& in) + { + mpCoreAllocator = in.mpCoreAllocator; + return *this; + } + + CoreDeleterAdapter& operator=(CoreDeleterAdapter&& in) + { + mpCoreAllocator = in.mpCoreAllocator; + in.mpCoreAllocator = nullptr; + return *this; + } + #endif + + }; + + + + /// EASTLICoreDeleter + /// + /// Provides a standardized typedef for ICoreAllocator implementations. + /// + /// Example usage: + /// eastl::shared_ptr foo(pA, EASTLCoreDeleter()); + /// + typedef CoreDeleterAdapter EASTLICoreDeleterAdapter; + typedef CoreDeleterAdapter EASTLCoreDeleterAdapter; + + } // namespace Allocator + +} // namespace EA + + + + + +/////////////////////////////////////////////////////////////////////////////// +// Inlines +/////////////////////////////////////////////////////////////////////////////// + +namespace EA +{ + namespace Allocator + { + template + inline CoreAllocatorAdapter::CoreAllocatorAdapter(const char* EASTL_NAME(pName), AllocatorType* pCoreAllocator) + : mpCoreAllocator(pCoreAllocator), mnFlags(0) + { + #if EASTL_NAME_ENABLED + mpName = pName ? pName : EASTL_ALLOCATOR_DEFAULT_NAME; + #endif + } + + template + inline CoreAllocatorAdapter::CoreAllocatorAdapter(const char* EASTL_NAME(pName), AllocatorType* pCoreAllocator, int flags) + : mpCoreAllocator(pCoreAllocator), mnFlags(flags) + { + #if EASTL_NAME_ENABLED + mpName = pName ? pName : EASTL_ALLOCATOR_DEFAULT_NAME; + #endif + } + + template + inline CoreAllocatorAdapter::CoreAllocatorAdapter(const CoreAllocatorAdapter& x) + : mpCoreAllocator(x.mpCoreAllocator), mnFlags(x.mnFlags) + { + #if EASTL_NAME_ENABLED + mpName = x.mpName; + #endif + } + + template + inline CoreAllocatorAdapter::CoreAllocatorAdapter(const CoreAllocatorAdapter& x, const char* EASTL_NAME(pName)) + : mpCoreAllocator(x.mpCoreAllocator), mnFlags(x.mnFlags) + { + #if EASTL_NAME_ENABLED + mpName = pName ? pName : EASTL_ALLOCATOR_DEFAULT_NAME; + #endif + } + + template + inline CoreAllocatorAdapter& CoreAllocatorAdapter::operator=(const CoreAllocatorAdapter& x) + { + // In order to be consistent with EASTL's allocator implementation, + // we don't copy the name from the source object. + mpCoreAllocator = x.mpCoreAllocator; + mnFlags = x.mnFlags; + return *this; + } + + template + inline void* CoreAllocatorAdapter::allocate(size_t n, int /*flags*/) + { + // It turns out that EASTL itself doesn't use the flags parameter, + // whereas the user here might well want to specify a flags + // parameter. So we use ours instead of the one passed in. + return mpCoreAllocator->Alloc(n, EASTL_NAME_VAL(mpName), (unsigned)mnFlags); + } + + template + inline void* CoreAllocatorAdapter::allocate(size_t n, size_t alignment, size_t offset, int /*flags*/) + { + // It turns out that EASTL itself doesn't use the flags parameter, + // whereas the user here might well want to specify a flags + // parameter. So we use ours instead of the one passed in. + return mpCoreAllocator->Alloc(n, EASTL_NAME_VAL(mpName), (unsigned)mnFlags, (unsigned)alignment, (unsigned)offset); + } + + template + inline void CoreAllocatorAdapter::deallocate(void* p, size_t n) + { + return mpCoreAllocator->Free(p, n); + } + + template + inline AllocatorType* CoreAllocatorAdapter::get_allocator() const + { + return mpCoreAllocator; + } + + template + inline void CoreAllocatorAdapter::set_allocator(AllocatorType* pAllocator) + { + mpCoreAllocator = pAllocator; + } + + template + inline int CoreAllocatorAdapter::get_flags() const + { + return mnFlags; + } + + template + inline void CoreAllocatorAdapter::set_flags(int flags) + { + mnFlags = flags; + } + + template + inline const char* CoreAllocatorAdapter::get_name() const + { + #if EASTL_NAME_ENABLED + return mpName; + #else + return EASTL_ALLOCATOR_DEFAULT_NAME; + #endif + } + + template + inline void CoreAllocatorAdapter::set_name(const char* pName) + { + #if EASTL_NAME_ENABLED + mpName = pName; + #else + (void)pName; + #endif + } + + + + template + inline bool operator==(const CoreAllocatorAdapter& a, const CoreAllocatorAdapter& b) + { + return (a.mpCoreAllocator == b.mpCoreAllocator) && + (a.mnFlags == b.mnFlags); + } + + template + inline bool operator!=(const CoreAllocatorAdapter& a, const CoreAllocatorAdapter& b) + { + return (a.mpCoreAllocator != b.mpCoreAllocator) || + (a.mnFlags != b.mnFlags); + } + + + } // namespace Allocator + +} // namespace EA + + +#endif // EASTL_CORE_ALLOCATOR_ENABLED +#endif // Header include guard + + + + + + + + diff --git a/libs/eastl/include/EASTL/deque.h b/libs/eastl/include/EASTL/deque.h new file mode 100644 index 0000000..d5c7cd7 --- /dev/null +++ b/libs/eastl/include/EASTL/deque.h @@ -0,0 +1,2978 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// deque design +// +// A deque (pronounced "deck") is a double-ended queue, though this is partially +// of a misnomer. A deque does indeed let you add and remove values from both ends +// of the container, but it's not usually used for such a thing and instead is used +// as a more flexible version of a vector. It provides operator[] (random access) +// and can insert items anywhere and not just at the front and back. +// +// While you can implement a double-ended queue via a doubly-linked list, deque is +// instead implemented as a list of arrays. The benefit of this is that memory usage +// is lower and that random access can be had with decent efficiency. +// +// Our implementation of deque is just like every other implementation of deque, +// as the C++ standard all but dictates that you make it work this way. Below +// we have a depiction of an array (or vector) of 48 items, with each node being +// a '+' character and extra capacity being a '-' character. What we have is one +// contiguous block of memory: +// +// ++++++++++++++++++++++++++++++++++++++++++++++++----------------- +// 0 47 +// +// With a deque, the same array of 48 items would be implemented as multiple smaller +// arrays of contiguous memory, each of fixed size. We will call these "sub-arrays." +// In the case here, we have six arrays of 8 nodes: +// +// ++++++++ ++++++++ ++++++++ ++++++++ ++++++++ ++++++++ +// +// With an vector, item [0] is the first item and item [47] is the last item. With a +// deque, item [0] is usually not the first item and neither is item [47]. There is +// extra capacity on both the front side and the back side of the deque. So a deque +// (of 24 items) actually looks like this: +// +// -------- -----+++ ++++++++ ++++++++ +++++--- -------- +// 0 23 +// +// To insert items at the front, you move into the capacity on the left, and to insert +// items at the back, you append items on the right. As you can see, inserting an item +// at the front doesn't require allocating new memory nor does it require moving any +// items in the container. It merely involves moving the pointer to the [0] item to +// the left by one node. +// +// We keep track of these sub-arrays by having an array of pointers, with each array +// entry pointing to each of the sub-arrays. We could alternatively use a linked +// list of pointers, but it turns out we can implement our deque::operator[] more +// efficiently if we use an array of pointers instead of a list of pointers. +// +// To implement deque::iterator, we could keep a struct which is essentially this: +// struct iterator { +// int subArrayIndex; +// int subArrayOffset; +// } +// +// In practice, we implement iterators a little differently, but in reality our +// implementation isn't much different from the above. It turns out that it's most +// simple if we also manage the location of item [0] and item [end] by using these +// same iterators. +// +// To consider: Implement the deque as a circular deque instead of a linear one. +// This would use a similar subarray layout but iterators would +// wrap around when they reached the end of the subarray pointer list. +// +////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_DEQUE_H +#define EASTL_DEQUE_H + + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + #pragma warning(push, 0) + #include + #include + #pragma warning(pop) +#else + #include + #include +#endif + +#if EASTL_EXCEPTIONS_ENABLED + #ifdef _MSC_VER + #pragma warning(push, 0) + #endif + #include // std::out_of_range, std::length_error. + #ifdef _MSC_VER + #pragma warning(pop) + #endif +#endif + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4267) // 'argument' : conversion from 'size_t' to 'const uint32_t', possible loss of data. This is a bogus warning resulting from a bug in VC++. + #pragma warning(disable: 4345) // Behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized + #pragma warning(disable: 4480) // nonstandard extension used: specifying underlying type for enum + #pragma warning(disable: 4530) // C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc + #pragma warning(disable: 4571) // catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught. + #if EASTL_EXCEPTIONS_ENABLED + #pragma warning(disable: 4703) // potentially uninitialized local pointer variable used. VC++ is mistakenly analyzing the possibility of uninitialized variables, though it's not easy for it to do so. + #pragma warning(disable: 4701) // potentially uninitialized local variable used. + #endif +#endif + + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + +namespace eastl +{ + + /// EASTL_DEQUE_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_DEQUE_DEFAULT_NAME + #define EASTL_DEQUE_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " deque" // Unless the user overrides something, this is "EASTL deque". + #endif + + + /// EASTL_DEQUE_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_DEQUE_DEFAULT_ALLOCATOR + #define EASTL_DEQUE_DEFAULT_ALLOCATOR allocator_type(EASTL_DEQUE_DEFAULT_NAME) + #endif + + + /// DEQUE_DEFAULT_SUBARRAY_SIZE + /// + /// Defines the default number of items in a subarray. + /// Note that the user has the option of specifying the subarray size + /// in the deque template declaration. + /// + #if !defined(__GNUC__) || (__GNUC__ >= 3) // GCC 2.x can't handle the declaration below. + #define DEQUE_DEFAULT_SUBARRAY_SIZE(T) ((sizeof(T) <= 4) ? 64 : ((sizeof(T) <= 8) ? 32 : ((sizeof(T) <= 16) ? 16 : ((sizeof(T) <= 32) ? 8 : 4)))) + #else + #define DEQUE_DEFAULT_SUBARRAY_SIZE(T) 16 + #endif + + + + /// DequeIterator + /// + /// The DequeIterator provides both const and non-const iterators for deque. + /// It also is used for the tracking of the begin and end for the deque. + /// + template + struct DequeIterator + { + typedef DequeIterator this_type; + typedef DequeIterator iterator; + typedef DequeIterator const_iterator; + typedef ptrdiff_t difference_type; + typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + + public: + DequeIterator(); + DequeIterator(const iterator& x); + + pointer operator->() const; + reference operator*() const; + + this_type& operator++(); + this_type operator++(int); + + this_type& operator--(); + this_type operator--(int); + + this_type& operator+=(difference_type n); + this_type& operator-=(difference_type n); + + this_type operator+(difference_type n) const; + this_type operator-(difference_type n) const; + + protected: + template + friend struct DequeIterator; + + template + friend struct DequeBase; + + template + friend class deque; + + template + friend bool operator==(const DequeIterator&, + const DequeIterator&); + + template + friend bool operator!=(const DequeIterator&, + const DequeIterator&); + + template + friend bool operator!=(const DequeIterator& a, + const DequeIterator& b); + + template + friend bool operator< (const DequeIterator&, + const DequeIterator&); + + template + friend bool operator> (const DequeIterator&, + const DequeIterator&); + + template + friend bool operator<=(const DequeIterator&, + const DequeIterator&); + + template + friend bool operator>=(const DequeIterator&, + const DequeIterator&); + + template + friend typename DequeIterator::difference_type + operator-(const DequeIterator& a, + const DequeIterator& b); + + protected: + T* mpCurrent; // Where we currently point. Declared first because it's used most often. + T* mpBegin; // The beginning of the current subarray. + T* mpEnd; // The end of the current subarray. To consider: remove this member, as it is always equal to 'mpBegin + kDequeSubarraySize'. Given that deque subarrays usually consist of hundreds of bytes, this isn't a massive win. Also, now that we are implementing a zero-allocation new deque policy, mpEnd may in fact not be equal to 'mpBegin + kDequeSubarraySize'. + T** mpCurrentArrayPtr; // Pointer to current subarray. We could alternatively implement this as a list node iterator if the deque used a linked list. + + struct Increment{ }; + struct Decrement{ }; + struct FromConst{}; + + DequeIterator(T** pCurrentArrayPtr, T* pCurrent); + DequeIterator(const const_iterator& x, FromConst) : mpCurrent(x.mpCurrent), mpBegin(x.mpBegin), mpEnd(x.mpEnd), mpCurrentArrayPtr(x.mpCurrentArrayPtr){} + DequeIterator(const iterator& x, Increment); + DequeIterator(const iterator& x, Decrement); + + this_type copy(const iterator& first, const iterator& last, true_type); // true means that value_type has the type_trait has_trivial_relocate, + this_type copy(const iterator& first, const iterator& last, false_type); // false means it does not. + + void copy_backward(const iterator& first, const iterator& last, true_type); // true means that value_type has the type_trait has_trivial_relocate, + void copy_backward(const iterator& first, const iterator& last, false_type); // false means it does not. + + void SetSubarray(T** pCurrentArrayPtr); + }; + + + + + /// DequeBase + /// + /// The DequeBase implements memory allocation for deque. + /// See VectorBase (class vector) for an explanation of why we + /// create this separate base class. + /// + template + struct DequeBase + { + typedef T value_type; + typedef Allocator allocator_type; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + typedef DequeIterator iterator; + typedef DequeIterator const_iterator; + + #if defined(_MSC_VER) && (_MSC_VER >= 1400) && (_MSC_VER <= 1600) && !EASTL_STD_CPP_ONLY // _MSC_VER of 1400 means VS2005, 1600 means VS2010. VS2012 generates errors with usage of enum:size_type. + enum : size_type { // Use Microsoft enum language extension, allowing for smaller debug symbols than using a static const. Users have been affected by this. + npos = (size_type)-1, + kMaxSize = (size_type)-2 + }; + #else + static const size_type npos = (size_type)-1; /// 'npos' means non-valid position or simply non-position. + static const size_type kMaxSize = (size_type)-2; /// -1 is reserved for 'npos'. It also happens to be slightly beneficial that kMaxSize is a value less than -1, as it helps us deal with potential integer wraparound issues. + #endif + + enum + { + kMinPtrArraySize = 8, /// A new empty deque has a ptrArraySize of 0, but any allocated ptrArrays use this min size. + kSubarraySize = kDequeSubarraySize /// + //kNodeSize = kDequeSubarraySize * sizeof(T) /// Disabled because it prevents the ability to do this: struct X{ eastl::deque mDequeOfSelf; }; + }; + + enum Side /// Defines the side of the deque: front or back. + { + kSideFront, /// Identifies the front side of the deque. + kSideBack /// Identifies the back side of the deque. + }; + + protected: + T** mpPtrArray; // Array of pointers to subarrays. + size_type mnPtrArraySize; // Possibly we should store this as T** mpArrayEnd. + iterator mItBegin; // Where within the subarrays is our beginning. + iterator mItEnd; // Where within the subarrays is our end. + allocator_type mAllocator; // To do: Use base class optimization to make this go away. + + public: + DequeBase(const allocator_type& allocator); + DequeBase(size_type n); + DequeBase(size_type n, const allocator_type& allocator); + ~DequeBase(); + + const allocator_type& get_allocator() const EA_NOEXCEPT; + allocator_type& get_allocator() EA_NOEXCEPT; + void set_allocator(const allocator_type& allocator); + + protected: + T* DoAllocateSubarray(); + void DoFreeSubarray(T* p); + void DoFreeSubarrays(T** pBegin, T** pEnd); + + T** DoAllocatePtrArray(size_type n); + void DoFreePtrArray(T** p, size_t n); + + iterator DoReallocSubarray(size_type nAdditionalCapacity, Side allocationSide); + void DoReallocPtrArray(size_type nAdditionalCapacity, Side allocationSide); + + void DoInit(size_type n); + + }; // DequeBase + + + + + /// deque + /// + /// Implements a conventional C++ double-ended queue. The implementation used here + /// is very much like any other deque implementations you may have seen, as it + /// follows the standard algorithm for deque design. + /// + /// Note: + /// As of this writing, deque does not support zero-allocation initial emptiness. + /// A newly created deque with zero elements will still allocate a subarray + /// pointer set. We are looking for efficient and clean ways to get around this, + /// but current efforts have resulted in less efficient and more fragile code. + /// The logic of this class doesn't lend itself to a clean implementation. + /// It turns out that deques are one of the least likely classes you'd want this + /// behaviour in, so until this functionality becomes very imporantant to somebody, + /// we will leave it as-is. It can probably be solved by adding some extra code to + /// the Do* functions and adding good comments explaining the situation. + /// + template + class deque : public DequeBase + { + public: + + typedef DequeBase base_type; + typedef deque this_type; + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef DequeIterator iterator; + typedef DequeIterator const_iterator; + typedef eastl::reverse_iterator reverse_iterator; + typedef eastl::reverse_iterator const_reverse_iterator; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::allocator_type allocator_type; + + using base_type::kSideFront; + using base_type::kSideBack; + using base_type::mpPtrArray; + using base_type::mnPtrArraySize; + using base_type::mItBegin; + using base_type::mItEnd; + using base_type::mAllocator; + using base_type::npos; + using base_type::DoAllocateSubarray; + using base_type::DoFreeSubarray; + using base_type::DoFreeSubarrays; + using base_type::DoAllocatePtrArray; + using base_type::DoFreePtrArray; + using base_type::DoReallocSubarray; + using base_type::DoReallocPtrArray; + + public: + deque(); + explicit deque(const allocator_type& allocator); + explicit deque(size_type n, const allocator_type& allocator = EASTL_DEQUE_DEFAULT_ALLOCATOR); + deque(size_type n, const value_type& value, const allocator_type& allocator = EASTL_DEQUE_DEFAULT_ALLOCATOR); + deque(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + deque(this_type&& x); + deque(this_type&& x, const allocator_type& allocator); + #endif + deque(std::initializer_list ilist, const allocator_type& allocator = EASTL_DEQUE_DEFAULT_ALLOCATOR); + + template + deque(InputIterator first, InputIterator last); // allocator arg removed because VC7.1 fails on the default arg. To do: Make a second version of this function without a default arg. + + ~deque(); + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + void assign(size_type n, const value_type& value); + + template // It turns out that the C++ std::deque specifies a two argument + void assign(InputIterator first, InputIterator last); // version of assign that takes (int size, int value). These are not + // iterators, so we need to do a template compiler trick to do the right thing. + void assign(std::initializer_list ilist); + + iterator begin() EA_NOEXCEPT; + const_iterator begin() const EA_NOEXCEPT; + const_iterator cbegin() const EA_NOEXCEPT; + + iterator end() EA_NOEXCEPT; + const_iterator end() const EA_NOEXCEPT; + const_iterator cend() const EA_NOEXCEPT; + + reverse_iterator rbegin() EA_NOEXCEPT; + const_reverse_iterator rbegin() const EA_NOEXCEPT; + const_reverse_iterator crbegin() const EA_NOEXCEPT; + + reverse_iterator rend() EA_NOEXCEPT; + const_reverse_iterator rend() const EA_NOEXCEPT; + const_reverse_iterator crend() const EA_NOEXCEPT; + + bool empty() const EA_NOEXCEPT; + size_type size() const EA_NOEXCEPT; + + void resize(size_type n, const value_type& value); + void resize(size_type n); + + void shrink_to_fit(); + void set_capacity(size_type n = base_type::npos); + + reference operator[](size_type n); + const_reference operator[](size_type n) const; + + reference at(size_type n); + const_reference at(size_type n) const; + + reference front(); + const_reference front() const; + + reference back(); + const_reference back() const; + + void push_front(const value_type& value); + reference push_front(); + #if EASTL_MOVE_SEMANTICS_ENABLED + void push_front(value_type&& value); + #endif + + void push_back(const value_type& value); + reference push_back(); + #if EASTL_MOVE_SEMANTICS_ENABLED + void push_back(value_type&& value); + #endif + + void pop_front(); + void pop_back(); + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + iterator emplace(const_iterator position, Args&&... args); + + template + void emplace_front(Args&&... args); + + template + void emplace_back(Args&&... args); + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + iterator emplace(const_iterator position, value_type&& value); + void emplace_front(value_type&& value); + void emplace_back(value_type&& value); + #endif + + iterator emplace(const_iterator position, const value_type& value); + void emplace_front(const value_type& value); + void emplace_back(const value_type& value); + #endif + + iterator insert(const_iterator position, const value_type& value); + #if EASTL_MOVE_SEMANTICS_ENABLED + iterator insert(const_iterator position, value_type&& value); + #endif + void insert(const_iterator position, size_type n, const value_type& value); + + template + void insert(const_iterator position, InputIterator first, InputIterator last); + + iterator insert(const_iterator position, std::initializer_list ilist); + + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + + reverse_iterator erase(reverse_iterator position); + reverse_iterator erase(reverse_iterator first, reverse_iterator last); + + void clear(); + //void reset_lose_memory(); // Disabled until it can be implemented efficiently and cleanly. // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + + bool validate() const; + int validate_iterator(const_iterator i) const; + + protected: + template + void DoInit(Integer n, Integer value, true_type); + + template + void DoInit(InputIterator first, InputIterator last, false_type); + + template + void DoInitFromIterator(InputIterator first, InputIterator last, EASTL_ITC_NS::input_iterator_tag); + + template + void DoInitFromIterator(ForwardIterator first, ForwardIterator last, EASTL_ITC_NS::forward_iterator_tag); + + void DoFillInit(const value_type& value); + + template + void DoAssign(Integer n, Integer value, true_type); + + template + void DoAssign(InputIterator first, InputIterator last, false_type); + + void DoAssignValues(size_type n, const value_type& value); + + template + void DoInsert(const const_iterator& position, Integer n, Integer value, true_type); + + template + void DoInsert(const const_iterator& position, const InputIterator& first, const InputIterator& last, false_type); + + template + void DoInsertFromIterator(const_iterator position, const InputIterator& first, const InputIterator& last, EASTL_ITC_NS::forward_iterator_tag); + + void DoInsertValues(const_iterator position, size_type n, const value_type& value); + + void DoSwap(this_type& x); + }; // class deque + + + + + /////////////////////////////////////////////////////////////////////// + // DequeBase + /////////////////////////////////////////////////////////////////////// + + template + DequeBase::DequeBase(const allocator_type& allocator) + : mpPtrArray(NULL), + mnPtrArraySize(0), + mItBegin(), + mItEnd(), + mAllocator(allocator) + { + // It is assumed here that the deque subclass will init us when/as needed. + } + + + template + DequeBase::DequeBase(size_type n) + : mpPtrArray(NULL), + mnPtrArraySize(0), + mItBegin(), + mItEnd(), + mAllocator(EASTL_DEQUE_DEFAULT_NAME) + { + // It's important to note that DoInit creates space for elements and assigns + // mItBegin/mItEnd to point to them, but these elements are not constructed. + // You need to immediately follow this constructor with code that constructs the values. + DoInit(n); + } + + + template + DequeBase::DequeBase(size_type n, const allocator_type& allocator) + : mpPtrArray(NULL), + mnPtrArraySize(0), + mItBegin(), + mItEnd(), + mAllocator(allocator) + { + // It's important to note that DoInit creates space for elements and assigns + // mItBegin/mItEnd to point to them, but these elements are not constructed. + // You need to immediately follow this constructor with code that constructs the values. + DoInit(n); + } + + + template + DequeBase::~DequeBase() + { + if(mpPtrArray) + { + DoFreeSubarrays(mItBegin.mpCurrentArrayPtr, mItEnd.mpCurrentArrayPtr + 1); + DoFreePtrArray(mpPtrArray, mnPtrArraySize); + } + } + + + template + const typename DequeBase::allocator_type& + DequeBase::get_allocator() const EA_NOEXCEPT + { + return mAllocator; + } + + + template + typename DequeBase::allocator_type& + DequeBase::get_allocator() EA_NOEXCEPT + { + return mAllocator; + } + + + template + void DequeBase::set_allocator(const allocator_type& allocator) + { + // The only time you can set an allocator is with an empty unused container, such as right after construction. + if(EASTL_LIKELY(mAllocator != allocator)) + { + if(EASTL_LIKELY(mpPtrArray && (mItBegin.mpCurrentArrayPtr == mItEnd.mpCurrentArrayPtr))) // If we are empty and so can safely deallocate the existing memory... We could also test for empty(), but that's a more expensive calculation and more involved clearing, though it would be more flexible. + { + DoFreeSubarrays(mItBegin.mpCurrentArrayPtr, mItEnd.mpCurrentArrayPtr + 1); + DoFreePtrArray(mpPtrArray, mnPtrArraySize); + + mAllocator = allocator; + DoInit(0); + } + else + { + EASTL_FAIL_MSG("DequeBase::set_allocator -- atempt to change allocator after allocating elements."); + } + } + } + + + template + T* DequeBase::DoAllocateSubarray() + { + T* p = (T*)allocate_memory(mAllocator, kDequeSubarraySize * sizeof(T), EASTL_ALIGN_OF(T), 0); + EASTL_ASSERT_MSG(p != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_DEBUG + memset((void*)p, 0, kDequeSubarraySize * sizeof(T)); + #endif + + return (T*)p; + } + + + template + void DequeBase::DoFreeSubarray(T* p) + { + if(p) + EASTLFree(mAllocator, p, kDequeSubarraySize * sizeof(T)); + } + + template + void DequeBase::DoFreeSubarrays(T** pBegin, T** pEnd) + { + while(pBegin < pEnd) + DoFreeSubarray(*pBegin++); + } + + template + T** DequeBase::DoAllocatePtrArray(size_type n) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(n >= 0x80000000)) + EASTL_FAIL_MSG("deque::DoAllocatePtrArray -- improbably large request."); + #endif + + T** pp = (T**)allocate_memory(mAllocator, n * sizeof(T*), EASTL_ALIGN_OF(T), 0); + EASTL_ASSERT_MSG(pp != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_DEBUG + memset((void*)pp, 0, n * sizeof(T*)); + #endif + + return pp; + } + + + template + void DequeBase::DoFreePtrArray(T** pp, size_t n) + { + if(pp) + EASTLFree(mAllocator, pp, n * sizeof(T*)); + } + + + template + typename DequeBase::iterator + DequeBase::DoReallocSubarray(size_type nAdditionalCapacity, Side allocationSide) + { + // nAdditionalCapacity refers to the amount of additional space we need to be + // able to store in this deque. Typically this function is called as part of + // an insert or append operation. This is the function that makes sure there + // is enough capacity for the new elements to be copied into the deque. + // The new capacity here is always at the front or back of the deque. + // This function returns an iterator to that points to the new begin or + // the new end of the deque space, depending on allocationSide. + + if(allocationSide == kSideFront) + { + // There might be some free space (nCurrentAdditionalCapacity) at the front of the existing subarray. + const size_type nCurrentAdditionalCapacity = (size_type)(mItBegin.mpCurrent - mItBegin.mpBegin); + + if(EASTL_UNLIKELY(nCurrentAdditionalCapacity < nAdditionalCapacity)) // If we need to grow downward into a new subarray... + { + const difference_type nSubarrayIncrease = (difference_type)(((nAdditionalCapacity - nCurrentAdditionalCapacity) + kDequeSubarraySize - 1) / kDequeSubarraySize); + difference_type i; + + if(nSubarrayIncrease > (mItBegin.mpCurrentArrayPtr - mpPtrArray)) // If there are not enough pointers in front of the current (first) one... + DoReallocPtrArray((size_type)(nSubarrayIncrease - (mItBegin.mpCurrentArrayPtr - mpPtrArray)), kSideFront); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + for(i = 1; i <= nSubarrayIncrease; ++i) + mItBegin.mpCurrentArrayPtr[-i] = DoAllocateSubarray(); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + for(difference_type j = 1; j < i; ++j) + DoFreeSubarray(mItBegin.mpCurrentArrayPtr[-j]); + throw; + } + #endif + } + + return mItBegin - (difference_type)nAdditionalCapacity; + } + else // else kSideBack + { + const size_type nCurrentAdditionalCapacity = (size_type)((mItEnd.mpEnd - 1) - mItEnd.mpCurrent); + + if(EASTL_UNLIKELY(nCurrentAdditionalCapacity < nAdditionalCapacity)) // If we need to grow forward into a new subarray... + { + const difference_type nSubarrayIncrease = (difference_type)(((nAdditionalCapacity - nCurrentAdditionalCapacity) + kDequeSubarraySize - 1) / kDequeSubarraySize); + difference_type i; + + if(nSubarrayIncrease > ((mpPtrArray + mnPtrArraySize) - mItEnd.mpCurrentArrayPtr) - 1) // If there are not enough pointers after the current (last) one... + DoReallocPtrArray((size_type)(nSubarrayIncrease - (((mpPtrArray + mnPtrArraySize) - mItEnd.mpCurrentArrayPtr) - 1)), kSideBack); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + for(i = 1; i <= nSubarrayIncrease; ++i) + mItEnd.mpCurrentArrayPtr[i] = DoAllocateSubarray(); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + for(difference_type j = 1; j < i; ++j) + DoFreeSubarray(mItEnd.mpCurrentArrayPtr[j]); + throw; + } + #endif + } + + return mItEnd + (difference_type)nAdditionalCapacity; + } + } + + + template + void DequeBase::DoReallocPtrArray(size_type nAdditionalCapacity, Side allocationSide) + { + // This function is not called unless the capacity is known to require a resize. + // + // We have an array of pointers (mpPtrArray), of which a segment of them are in use and + // at either end of the array are zero or more unused pointers. This function is being + // called because we need to extend the capacity on either side of this array by + // nAdditionalCapacity pointers. However, it's possible that if the user is continually + // using push_back and pop_front then the pointer array will continue to be extended + // on the back side and unused on the front side. So while we are doing this resizing + // here we also take the opportunity to recenter the pointers and thus be balanced. + // It man turn out that we don't even need to reallocate the pointer array in order + // to increase capacity on one side, as simply moving the pointers to the center may + // be enough to open up the requires space. + // + // Balanced pointer array Unbalanced pointer array (unused space at front, no free space at back) + // ----++++++++++++---- ---------+++++++++++ + + const size_type nUnusedPtrCountAtFront = (size_type)(mItBegin.mpCurrentArrayPtr - mpPtrArray); + const size_type nUsedPtrCount = (size_type)(mItEnd.mpCurrentArrayPtr - mItBegin.mpCurrentArrayPtr) + 1; + const size_type nUsedPtrSpace = nUsedPtrCount * sizeof(void*); + const size_type nUnusedPtrCountAtBack = (mnPtrArraySize - nUnusedPtrCountAtFront) - nUsedPtrCount; + value_type** pPtrArrayBegin; + + if((allocationSide == kSideBack) && (nAdditionalCapacity <= nUnusedPtrCountAtFront)) // If we can take advantage of unused pointers at the front without doing any reallocation... + { + if(nAdditionalCapacity < (nUnusedPtrCountAtFront / 2)) // Possibly use more space than required, if there's a lot of extra space. + nAdditionalCapacity = (nUnusedPtrCountAtFront / 2); + + pPtrArrayBegin = mpPtrArray + (nUnusedPtrCountAtFront - nAdditionalCapacity); + memmove(pPtrArrayBegin, mItBegin.mpCurrentArrayPtr, nUsedPtrSpace); + + #if EASTL_DEBUG + memset(pPtrArrayBegin + nUsedPtrCount, 0, (size_t)(mpPtrArray + mnPtrArraySize) - (size_t)(pPtrArrayBegin + nUsedPtrCount)); + #endif + } + else if((allocationSide == kSideFront) && (nAdditionalCapacity <= nUnusedPtrCountAtBack)) // If we can take advantage of unused pointers at the back without doing any reallocation... + { + if(nAdditionalCapacity < (nUnusedPtrCountAtBack / 2)) // Possibly use more space than required, if there's a lot of extra space. + nAdditionalCapacity = (nUnusedPtrCountAtBack / 2); + + pPtrArrayBegin = mItBegin.mpCurrentArrayPtr + nAdditionalCapacity; + memmove(pPtrArrayBegin, mItBegin.mpCurrentArrayPtr, nUsedPtrSpace); + + #if EASTL_DEBUG + memset(mpPtrArray, 0, (size_t)((uintptr_t)pPtrArrayBegin - (uintptr_t)mpPtrArray)); + #endif + } + else + { + // In this case we will have to do a reallocation. + const size_type nNewPtrArraySize = mnPtrArraySize + eastl::max_alt(mnPtrArraySize, nAdditionalCapacity) + 2; // Allocate extra capacity. + value_type** const pNewPtrArray = DoAllocatePtrArray(nNewPtrArraySize); + + pPtrArrayBegin = pNewPtrArray + (mItBegin.mpCurrentArrayPtr - mpPtrArray) + ((allocationSide == kSideFront) ? nAdditionalCapacity : 0); + + // The following is equivalent to: eastl::copy(mItBegin.mpCurrentArrayPtr, mItEnd.mpCurrentArrayPtr + 1, pPtrArrayBegin); + // It's OK to use memcpy instead of memmove because the destination is guaranteed to non-overlap the source. + if(mpPtrArray) // Could also say: 'if(mItBegin.mpCurrentArrayPtr)' + memcpy(pPtrArrayBegin, mItBegin.mpCurrentArrayPtr, nUsedPtrSpace); + + DoFreePtrArray(mpPtrArray, mnPtrArraySize); + + mpPtrArray = pNewPtrArray; + mnPtrArraySize = nNewPtrArraySize; + } + + // We need to reset the begin and end iterators, as code that calls this expects them to *not* be invalidated. + mItBegin.SetSubarray(pPtrArrayBegin); + mItEnd.SetSubarray((pPtrArrayBegin + nUsedPtrCount) - 1); + } + + + template + void DequeBase::DoInit(size_type n) + { + // This code is disabled because it doesn't currently work properly. + // We are trying to make it so that a deque can have a zero allocation + // initial empty state, but we (OK, I) am having a hard time making + // this elegant and efficient. + //if(n) + //{ + const size_type nNewPtrArraySize = (size_type)((n / kDequeSubarraySize) + 1); // Always have at least one, even if n is zero. + const size_type kMinPtrArraySize_ = kMinPtrArraySize; // GCC 4.0 blows up unless we define this constant. + + mnPtrArraySize = eastl::max_alt(kMinPtrArraySize_, (nNewPtrArraySize + 2)); // GCC 4.0 blows up on this. + mpPtrArray = DoAllocatePtrArray(mnPtrArraySize); + + value_type** const pPtrArrayBegin = (mpPtrArray + ((mnPtrArraySize - nNewPtrArraySize) / 2)); // Try to place it in the middle. + value_type** const pPtrArrayEnd = pPtrArrayBegin + nNewPtrArraySize; + value_type** pPtrArrayCurrent = pPtrArrayBegin; + + // I am sorry for the mess of #ifs and indentations below. + #if EASTL_EXCEPTIONS_ENABLED + try + { + try + { + #endif + while(pPtrArrayCurrent < pPtrArrayEnd) + *pPtrArrayCurrent++ = DoAllocateSubarray(); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeSubarrays(pPtrArrayBegin, pPtrArrayCurrent); + throw; + } + } + catch(...) + { + DoFreePtrArray(mpPtrArray, mnPtrArraySize); + mpPtrArray = NULL; + mnPtrArraySize = 0; + throw; + } + #endif + + mItBegin.SetSubarray(pPtrArrayBegin); + mItBegin.mpCurrent = mItBegin.mpBegin; + + mItEnd.SetSubarray(pPtrArrayEnd - 1); + mItEnd.mpCurrent = mItEnd.mpBegin + (difference_type)(n % kDequeSubarraySize); + //} + //else // Else we do a zero-allocation initialization. + //{ + // mpPtrArray = NULL; + // mnPtrArraySize = 0; + // + // mItBegin.mpCurrentArrayPtr = NULL; + // mItBegin.mpBegin = NULL; + // mItBegin.mpEnd = NULL; // We intentionally create a situation whereby the subarray that has no capacity. + // mItBegin.mpCurrent = NULL; + // + // mItEnd = mItBegin; + //} + } + + + + /////////////////////////////////////////////////////////////////////// + // DequeIterator + /////////////////////////////////////////////////////////////////////// + + template + DequeIterator::DequeIterator() + : mpCurrent(NULL), mpBegin(NULL), mpEnd(NULL), mpCurrentArrayPtr(NULL) + { + // Empty + } + + + template + DequeIterator::DequeIterator(T** pCurrentArrayPtr, T* pCurrent) + : mpCurrent(pCurrent), mpBegin(*pCurrentArrayPtr), mpEnd(pCurrent + kDequeSubarraySize), mpCurrentArrayPtr(pCurrentArrayPtr) + { + // Empty + } + + + template + DequeIterator::DequeIterator(const iterator& x) + : mpCurrent(x.mpCurrent), mpBegin(x.mpBegin), mpEnd(x.mpEnd), mpCurrentArrayPtr(x.mpCurrentArrayPtr) + { + // Empty + } + + + template + DequeIterator::DequeIterator(const iterator& x, Increment) + : mpCurrent(x.mpCurrent), mpBegin(x.mpBegin), mpEnd(x.mpEnd), mpCurrentArrayPtr(x.mpCurrentArrayPtr) + { + operator++(); + } + + + template + DequeIterator::DequeIterator(const iterator& x, Decrement) + : mpCurrent(x.mpCurrent), mpBegin(x.mpBegin), mpEnd(x.mpEnd), mpCurrentArrayPtr(x.mpCurrentArrayPtr) + { + operator--(); + } + + + template + typename DequeIterator::pointer + DequeIterator::operator->() const + { + return mpCurrent; + } + + + template + typename DequeIterator::reference + DequeIterator::operator*() const + { + return *mpCurrent; + } + + + template + typename DequeIterator::this_type& + DequeIterator::operator++() + { + if(EASTL_UNLIKELY(++mpCurrent == mpEnd)) + { + mpBegin = *++mpCurrentArrayPtr; + mpEnd = mpBegin + kDequeSubarraySize; + mpCurrent = mpBegin; + } + return *this; + } + + + template + typename DequeIterator::this_type + DequeIterator::operator++(int) + { + const this_type temp(*this); + operator++(); + return temp; + } + + + template + typename DequeIterator::this_type& + DequeIterator::operator--() + { + if(EASTL_UNLIKELY(mpCurrent == mpBegin)) + { + mpBegin = *--mpCurrentArrayPtr; + mpEnd = mpBegin + kDequeSubarraySize; + mpCurrent = mpEnd; // fall through... + } + --mpCurrent; + return *this; + } + + + template + typename DequeIterator::this_type + DequeIterator::operator--(int) + { + const this_type temp(*this); + operator--(); + return temp; + } + + + template + typename DequeIterator::this_type& + DequeIterator::operator+=(difference_type n) + { + const difference_type subarrayPosition = (mpCurrent - mpBegin) + n; + + // Cast from signed to unsigned (size_t) in order to obviate the need to compare to < 0. + if((size_t)subarrayPosition < (size_t)kDequeSubarraySize) // If the new position is within the current subarray (i.e. >= 0 && < kSubArraySize)... + mpCurrent += n; + else + { + // This implementation is a branchless version which works by offsetting + // the math to always be in the positive range. Much of the values here + // reduce to constants and both the multiplication and division are of + // power of two sizes and so this calculation ends up compiling down to + // just one addition, one shift and one subtraction. This algorithm has + // a theoretical weakness in that on 32 bit systems it will fail if the + // value of n is >= (2^32 - 2^24) or 4,278,190,080 of if kDequeSubarraySize + // is >= 2^24 or 16,777,216. + EASTL_CT_ASSERT((kDequeSubarraySize & (kDequeSubarraySize - 1)) == 0); // Verify that it is a power of 2. + const difference_type subarrayIndex = (((16777216 + subarrayPosition) / (difference_type)kDequeSubarraySize)) - (16777216 / (difference_type)kDequeSubarraySize); + + SetSubarray(mpCurrentArrayPtr + subarrayIndex); + mpCurrent = mpBegin + (subarrayPosition - (subarrayIndex * (difference_type)kDequeSubarraySize)); + } + return *this; + } + + + template + typename DequeIterator::this_type& + DequeIterator::operator-=(difference_type n) + { + return (*this).operator+=(-n); + } + + + template + typename DequeIterator::this_type + DequeIterator::operator+(difference_type n) const + { + return this_type(*this).operator+=(n); + } + + + template + typename DequeIterator::this_type + DequeIterator::operator-(difference_type n) const + { + return this_type(*this).operator+=(-n); + } + + + template + typename DequeIterator::this_type + DequeIterator::copy(const iterator& first, const iterator& last, true_type) + { + // To do: Implement this as a loop which does memcpys between subarrays appropriately. + // Currently we only do memcpy if the entire operation occurs within a single subarray. + if((first.mpBegin == last.mpBegin) && (first.mpBegin == mpBegin)) // If all operations are within the same subarray, implement the operation as a memmove. + { + // The following is equivalent to: eastl::copy(first.mpCurrent, last.mpCurrent, mpCurrent); + memmove(mpCurrent, first.mpCurrent, (size_t)((uintptr_t)last.mpCurrent - (uintptr_t)first.mpCurrent)); + return *this + (last.mpCurrent - first.mpCurrent); + } + return eastl::copy(first, last, *this); + } + + + template + typename DequeIterator::this_type + DequeIterator::copy(const iterator& first, const iterator& last, false_type) + { + return eastl::copy(first, last, *this); + } + + + template + void DequeIterator::copy_backward(const iterator& first, const iterator& last, true_type) + { + // To do: Implement this as a loop which does memmoves between subarrays appropriately. + // Currently we only do memcpy if the entire operation occurs within a single subarray. + if((first.mpBegin == last.mpBegin) && (first.mpBegin == mpBegin)) // If all operations are within the same subarray, implement the operation as a memcpy. + memmove(mpCurrent - (last.mpCurrent - first.mpCurrent), first.mpCurrent, (size_t)((uintptr_t)last.mpCurrent - (uintptr_t)first.mpCurrent)); + else + eastl::copy_backward(first, last, *this); + } + + + template + void DequeIterator::copy_backward(const iterator& first, const iterator& last, false_type) + { + eastl::copy_backward(first, last, *this); + } + + + template + void DequeIterator::SetSubarray(T** pCurrentArrayPtr) + { + mpCurrentArrayPtr = pCurrentArrayPtr; + mpBegin = *pCurrentArrayPtr; + mpEnd = mpBegin + kDequeSubarraySize; + } + + + // The C++ defect report #179 requires that we support comparisons between const and non-const iterators. + // Thus we provide additional template paremeters here to support this. The defect report does not + // require us to support comparisons between reverse_iterators and const_reverse_iterators. + template + inline bool operator==(const DequeIterator& a, + const DequeIterator& b) + { + return a.mpCurrent == b.mpCurrent; + } + + + template + inline bool operator!=(const DequeIterator& a, + const DequeIterator& b) + { + return a.mpCurrent != b.mpCurrent; + } + + + // We provide a version of operator!= for the case where the iterators are of the + // same type. This helps prevent ambiguity errors in the presence of rel_ops. + template + inline bool operator!=(const DequeIterator& a, + const DequeIterator& b) + { + return a.mpCurrent != b.mpCurrent; + } + + + template + inline bool operator<(const DequeIterator& a, + const DequeIterator& b) + { + return (a.mpCurrentArrayPtr == b.mpCurrentArrayPtr) ? (a.mpCurrent < b.mpCurrent) : (a.mpCurrentArrayPtr < b.mpCurrentArrayPtr); + } + + + template + inline bool operator>(const DequeIterator& a, + const DequeIterator& b) + { + return (a.mpCurrentArrayPtr == b.mpCurrentArrayPtr) ? (a.mpCurrent > b.mpCurrent) : (a.mpCurrentArrayPtr > b.mpCurrentArrayPtr); + } + + + template + inline bool operator<=(const DequeIterator& a, + const DequeIterator& b) + { + return (a.mpCurrentArrayPtr == b.mpCurrentArrayPtr) ? (a.mpCurrent <= b.mpCurrent) : (a.mpCurrentArrayPtr <= b.mpCurrentArrayPtr); + } + + + template + inline bool operator>=(const DequeIterator& a, + const DequeIterator& b) + { + return (a.mpCurrentArrayPtr == b.mpCurrentArrayPtr) ? (a.mpCurrent >= b.mpCurrent) : (a.mpCurrentArrayPtr >= b.mpCurrentArrayPtr); + } + + + // Random access iterators must support operator + and operator -. + // You can only add an integer to an iterator, and you cannot add two iterators. + template + inline DequeIterator + operator+(ptrdiff_t n, const DequeIterator& x) + { + return x + n; // Implement (n + x) in terms of (x + n). + } + + + // You can only add an integer to an iterator, but you can subtract two iterators. + // The C++ defect report #179 mentioned above specifically refers to + // operator - and states that we support the subtraction of const and non-const iterators. + template + inline typename DequeIterator::difference_type + operator-(const DequeIterator& a, + const DequeIterator& b) + { + // This is a fairly clever algorithm that has been used in STL deque implementations since the original HP STL: + typedef typename DequeIterator::difference_type difference_type; + + return ((difference_type)kDequeSubarraySize * ((a.mpCurrentArrayPtr - b.mpCurrentArrayPtr) - 1)) + (a.mpCurrent - a.mpBegin) + (b.mpEnd - b.mpCurrent); + } + + + + + /////////////////////////////////////////////////////////////////////// + // deque + /////////////////////////////////////////////////////////////////////// + + template + inline deque::deque() + : base_type((size_type)0) + { + // Empty + } + + + template + inline deque::deque(const allocator_type& allocator) + : base_type((size_type)0, allocator) + { + // Empty + } + + + template + inline deque::deque(size_type n, const allocator_type& allocator) + : base_type(n, allocator) + { + DoFillInit(value_type()); + } + + + template + inline deque::deque(size_type n, const value_type& value, const allocator_type& allocator) + : base_type(n, allocator) + { + DoFillInit(value); + } + + + template + inline deque::deque(const this_type& x) + : base_type(x.size(), x.mAllocator) + { + eastl::uninitialized_copy(x.mItBegin, x.mItEnd, mItBegin); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline deque::deque(this_type&& x) + : base_type((size_type)0, x.mAllocator) + { + swap(x); + } + + + template + inline deque::deque(this_type&& x, const allocator_type& allocator) + : base_type((size_type)0, allocator) + { + swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. + } + #endif + + + template + inline deque::deque(std::initializer_list ilist, const allocator_type& allocator) + : base_type(allocator) + { + DoInit(ilist.begin(), ilist.end(), false_type()); + } + + + template + template + inline deque::deque(InputIterator first, InputIterator last) + : base_type(EASTL_DEQUE_DEFAULT_ALLOCATOR) // Call the empty base constructor, which does nothing. We need to do all the work in our own DoInit. + { + DoInit(first, last, is_integral()); + } + + + template + inline deque::~deque() + { + // Call destructors. Parent class will free the memory. + for(iterator itCurrent(mItBegin); itCurrent != mItEnd; ++itCurrent) + itCurrent.mpCurrent->~value_type(); + } + + + template + typename deque::this_type& + deque::operator=(const this_type& x) + { + if(&x != this) // If not assigning to ourselves... + { + // If (EASTL_ALLOCATOR_COPY_ENABLED == 1) and the current contents are allocated by an + // allocator that's unequal to x's allocator, we need to reallocate our elements with + // our current allocator and reallocate it with x's allocator. If the allocators are + // equal then we can use a more optimal algorithm that doesn't reallocate our elements + // but instead can copy them in place. + + #if EASTL_ALLOCATOR_COPY_ENABLED + bool bSlowerPathwayRequired = (mAllocator != x.mAllocator); + #else + bool bSlowerPathwayRequired = false; + #endif + + if(bSlowerPathwayRequired) + { + // We can't currently use set_capacity(0) or shrink_to_fit, because they + // leave a remaining allocation with our old allocator. So we do a similar + // thing but set our allocator to x.mAllocator while doing so. + this_type temp(x.mAllocator); + DoSwap(temp); + // Now we have an empty container with an allocator equal to x.mAllocator, ready to assign from x. + } + + DoAssign(x.begin(), x.end(), eastl::false_type()); + } + + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename deque::this_type& + deque::operator=(this_type&& x) + { + if(this != &x) + { + set_capacity(0); // To consider: Are we really required to clear here? x is going away soon and will clear itself in its dtor. + swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. + } + return *this; + } + #endif + + + template + inline typename deque::this_type& + deque::operator=(std::initializer_list ilist) + { + DoAssign(ilist.begin(), ilist.end(), false_type()); + return *this; + } + + + template + inline void deque::assign(size_type n, const value_type& value) + { + DoAssignValues(n, value); + } + + + template + inline void deque::assign(std::initializer_list ilist) + { + DoAssign(ilist.begin(), ilist.end(), false_type()); + } + + + // It turns out that the C++ std::deque specifies a two argument + // version of assign that takes (int size, int value). These are not + // iterators, so we need to do a template compiler trick to do the right thing. + template + template + inline void deque::assign(InputIterator first, InputIterator last) + { + DoAssign(first, last, is_integral()); + } + + + template + inline typename deque::iterator + deque::begin() EA_NOEXCEPT + { + return mItBegin; + } + + + template + inline typename deque::const_iterator + deque::begin() const EA_NOEXCEPT + { + return mItBegin; + } + + + template + inline typename deque::const_iterator + deque::cbegin() const EA_NOEXCEPT + { + return mItBegin; + } + + + template + inline typename deque::iterator + deque::end() EA_NOEXCEPT + { + return mItEnd; + } + + + template + typename deque::const_iterator + deque::end() const EA_NOEXCEPT + { + return mItEnd; + } + + + template + inline typename deque::const_iterator + deque::cend() const EA_NOEXCEPT + { + return mItEnd; + } + + + template + inline typename deque::reverse_iterator + deque::rbegin() EA_NOEXCEPT + { + return reverse_iterator(mItEnd); + } + + + template + inline typename deque::const_reverse_iterator + deque::rbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(mItEnd); + } + + + template + inline typename deque::const_reverse_iterator + deque::crbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(mItEnd); + } + + + template + inline typename deque::reverse_iterator + deque::rend() EA_NOEXCEPT + { + return reverse_iterator(mItBegin); + } + + + template + inline typename deque::const_reverse_iterator + deque::rend() const EA_NOEXCEPT + { + return const_reverse_iterator(mItBegin); + } + + + template + inline typename deque::const_reverse_iterator + deque::crend() const EA_NOEXCEPT + { + return const_reverse_iterator(mItBegin); + } + + + template + inline bool deque::empty() const EA_NOEXCEPT + { + return mItBegin.mpCurrent == mItEnd.mpCurrent; + } + + + template + typename deque::size_type + inline deque::size() const EA_NOEXCEPT + { + return (size_type)(mItEnd - mItBegin); + } + + + template + inline void deque::resize(size_type n, const value_type& value) + { + const size_type nSizeCurrent = size(); + + if(n > nSizeCurrent) // We expect that more often than not, resizes will be upsizes. + insert(mItEnd, n - nSizeCurrent, value); + else + erase(mItBegin + (difference_type)n, mItEnd); + } + + + template + inline void deque::resize(size_type n) + { + resize(n, value_type()); + } + + + template + inline void deque::shrink_to_fit() + { + return set_capacity(0); + } + + + template + inline void deque::set_capacity(size_type n) + { + // Currently there isn't a way to remove all allocations from a deque, as it + // requires a single starting allocation for the subarrays. So we can't just + // free all memory without leaving it in a bad state. So the best means of + // implementing set_capacity() is to do what we do below. + + if(n == 0) + { + this_type temp(mAllocator); + DoSwap(temp); + } + else if(n < size()) + { + // We currently ignore the request to reduce capacity. To do: Implement this + // and do it in a way that doesn't result in temporarily ~doubling our memory usage. + // That might involve trimming unused subarrays from the front or back of + // the container. + resize(n); + } + } + + + template + typename deque::reference + deque::operator[](size_type n) + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED // We allow the user to use a reference to v[0] of an empty container. + if(EASTL_UNLIKELY((n != 0) && n >= (size_type)(mItEnd - mItBegin))) + EASTL_FAIL_MSG("deque::operator[] -- out of range"); + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(n >= (size_type)(mItEnd - mItBegin))) + EASTL_FAIL_MSG("deque::operator[] -- out of range"); + #endif + + // See DequeIterator::operator+=() for an explanation of the code below. + iterator it(mItBegin); + + const difference_type subarrayPosition = (difference_type)((it.mpCurrent - it.mpBegin) + (difference_type)n); + const difference_type subarrayIndex = (((16777216 + subarrayPosition) / (difference_type)kDequeSubarraySize)) - (16777216 / (difference_type)kDequeSubarraySize); + + return *(*(it.mpCurrentArrayPtr + subarrayIndex) + (subarrayPosition - (subarrayIndex * (difference_type)kDequeSubarraySize))); + } + + + template + typename deque::const_reference + deque::operator[](size_type n) const + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED // We allow the user to use a reference to v[0] of an empty container. + if(EASTL_UNLIKELY((n != 0) && n >= (size_type)(mItEnd - mItBegin))) + EASTL_FAIL_MSG("deque::operator[] -- out of range"); + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(n >= (size_type)(mItEnd - mItBegin))) + EASTL_FAIL_MSG("deque::operator[] -- out of range"); + #endif + + // See DequeIterator::operator+=() for an explanation of the code below. + iterator it(mItBegin); + + const difference_type subarrayPosition = (it.mpCurrent - it.mpBegin) + (difference_type)n; + const difference_type subarrayIndex = (((16777216 + subarrayPosition) / (difference_type)kDequeSubarraySize)) - (16777216 / (difference_type)kDequeSubarraySize); + + return *(*(it.mpCurrentArrayPtr + subarrayIndex) + (subarrayPosition - (subarrayIndex * (difference_type)kDequeSubarraySize))); + } + + + template + typename deque::reference + deque::at(size_type n) + { + #if EASTL_EXCEPTIONS_ENABLED + if(n >= (size_type)(mItEnd - mItBegin)) + throw std::out_of_range("deque::at -- out of range"); + #elif EASTL_ASSERT_ENABLED + if(n >= (size_type)(mItEnd - mItBegin)) + EASTL_FAIL_MSG("deque::at -- out of range"); + #endif + return *(mItBegin.operator+((difference_type)n)); + } + + + template + typename deque::const_reference + deque::at(size_type n) const + { + #if EASTL_EXCEPTIONS_ENABLED + if(n >= (size_type)(mItEnd - mItBegin)) + throw std::out_of_range("deque::at -- out of range"); + #elif EASTL_ASSERT_ENABLED + if(n >= (size_type)(mItEnd - mItBegin)) + EASTL_FAIL_MSG("deque::at -- out of range"); + #endif + return *(mItBegin.operator+((difference_type)n)); + } + + + template + typename deque::reference + deque::front() + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference an empty container. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY((size_type)(mItEnd == mItBegin))) + EASTL_FAIL_MSG("deque::front -- empty deque"); + #endif + + return *mItBegin; + } + + + template + typename deque::const_reference + deque::front() const + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference an empty container. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY((size_type)(mItEnd == mItBegin))) + EASTL_FAIL_MSG("deque::front -- empty deque"); + #endif + + return *mItBegin; + } + + + template + typename deque::reference + deque::back() + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference an empty container. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY((size_type)(mItEnd == mItBegin))) + EASTL_FAIL_MSG("deque::back -- empty deque"); + #endif + + return *iterator(mItEnd, typename iterator::Decrement()); + } + + + template + typename deque::const_reference + deque::back() const + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference an empty container. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY((size_type)(mItEnd == mItBegin))) + EASTL_FAIL_MSG("deque::back -- empty deque"); + #endif + + return *iterator(mItEnd, typename iterator::Decrement()); + } + + + template + void deque::push_front(const value_type& value) + { + emplace_front(value); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + void deque::push_front(value_type&& value) + { + emplace_front(eastl::move(value)); + } + #endif + + + template + typename deque::reference + deque::push_front() + { + emplace_front(value_type()); + return *mItBegin; // Same as return front(); + } + + + template + void deque::push_back(const value_type& value) + { + emplace_back(value); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + void deque::push_back(value_type&& value) + { + emplace_back(eastl::move(value)); + } + #endif + + + template + typename deque::reference + deque::push_back() + { + emplace_back(value_type()); + return *iterator(mItEnd, typename iterator::Decrement()); // Same thing as return back(); + } + + + template + void deque::pop_front() + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY((size_type)(mItEnd == mItBegin))) + EASTL_FAIL_MSG("deque::pop_front -- empty deque"); + #endif + + if((mItBegin.mpCurrent + 1) != mItBegin.mpEnd) // If the operation is very simple... + (mItBegin.mpCurrent++)->~value_type(); + else + { + // This is executed only when we are popping the end (last) item off the front-most subarray. + // In this case we need to free the subarray and point mItBegin to the next subarray. + #ifdef EA_DEBUG + value_type** pp = mItBegin.mpCurrentArrayPtr; + #endif + + mItBegin.mpCurrent->~value_type(); // mpCurrent == mpEnd - 1 + DoFreeSubarray(mItBegin.mpBegin); + mItBegin.SetSubarray(mItBegin.mpCurrentArrayPtr + 1); + mItBegin.mpCurrent = mItBegin.mpBegin; + + #ifdef EA_DEBUG + *pp = NULL; + #endif + } + } + + + template + void deque::pop_back() + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY((size_type)(mItEnd == mItBegin))) + EASTL_FAIL_MSG("deque::pop_back -- empty deque"); + #endif + + if(mItEnd.mpCurrent != mItEnd.mpBegin) // If the operation is very simple... + (--mItEnd.mpCurrent)->~value_type(); + else + { + // This is executed only when we are popping the first item off the last subarray. + // In this case we need to free the subarray and point mItEnd to the previous subarray. + #ifdef EA_DEBUG + value_type** pp = mItEnd.mpCurrentArrayPtr; + #endif + + DoFreeSubarray(mItEnd.mpBegin); + mItEnd.SetSubarray(mItEnd.mpCurrentArrayPtr - 1); + mItEnd.mpCurrent = mItEnd.mpEnd - 1; // Recall that mItEnd points to one-past the last item in the container. + mItEnd.mpCurrent->~value_type(); // Thus we need to call the destructor on the item *before* that last item. + + #ifdef EA_DEBUG + *pp = NULL; + #endif + } + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + template + typename deque::iterator + deque::emplace(const_iterator position, Args&&... args) + { + if(EASTL_UNLIKELY(position.mpCurrent == mItEnd.mpCurrent)) // If we are doing the same thing as push_back... + { + emplace_back(eastl::forward(args)...); + return iterator(mItEnd, typename iterator::Decrement()); // Unfortunately, we need to make an iterator here, as the above push_back is an operation that can invalidate existing iterators. + } + else if(EASTL_UNLIKELY(position.mpCurrent == mItBegin.mpCurrent)) // If we are doing the same thing as push_front... + { + emplace_front(eastl::forward(args)...); + return mItBegin; + } + + iterator itPosition(position, typename iterator::FromConst()); + #if EASTL_USE_FORWARD_WORKAROUND + auto valueSaved = value_type(eastl::forward(args)...); //Workaround for compiler bug in VS2013 + #else + value_type valueSaved(eastl::forward(args)...); // We need to save this because value may come from within our container. It would be somewhat tedious to make a workaround that could avoid this. + #endif + const difference_type i(itPosition - mItBegin); + + #if EASTL_ASSERT_ENABLED + EASTL_ASSERT(!empty()); // The push_front and push_back calls below assume that we are non-empty. It turns out this is never called unless so. + + if(EASTL_UNLIKELY(!(validate_iterator(itPosition) & isf_valid))) + EASTL_FAIL_MSG("deque::emplace -- invalid iterator"); + #endif + + if(i < (difference_type)(size() / 2)) // Should we insert at the front or at the back? We divide the range in half. + { + emplace_front(*mItBegin); // This operation potentially invalidates all existing iterators and so we need to assign them anew relative to mItBegin below. + + itPosition = mItBegin + i; + + const iterator newPosition (itPosition, typename iterator::Increment()); + iterator oldBegin (mItBegin, typename iterator::Increment()); + const iterator oldBeginPlus1(oldBegin, typename iterator::Increment()); + + oldBegin.copy(oldBeginPlus1, newPosition, eastl::has_trivial_relocate()); + } + else + { + emplace_back(*iterator(mItEnd, typename iterator::Decrement())); + + itPosition = mItBegin + i; + + iterator oldBack (mItEnd, typename iterator::Decrement()); + const iterator oldBackMinus1(oldBack, typename iterator::Decrement()); + + oldBack.copy_backward(itPosition, oldBackMinus1, eastl::has_trivial_relocate()); + } + + *itPosition = eastl::move(valueSaved); + + return itPosition; + } + + template + template + void deque::emplace_front(Args&&... args) + { + if(mItBegin.mpCurrent != mItBegin.mpBegin) // If we have room in the first subarray... we hope that usually this 'new' pathway gets executed, as it is slightly faster. + ::new((void*)--mItBegin.mpCurrent) value_type(eastl::forward(args)...); // Construct in place. If args is a single arg of type value_type&& then it this will be a move construction. + else + { + // To consider: Detect if value isn't coming from within this container and handle that efficiently. + #if EASTL_USE_FORWARD_WORKAROUND + auto valueSaved = value_type(eastl::forward(args)...); //Workaround for compiler bug in VS2013 + #else + value_type valueSaved(eastl::forward(args)...); // We need to make a temporary, because args may be a value_type that comes from within our container and the operations below may change the container. But we can use move instead of copy. + #endif + + if(mItBegin.mpCurrentArrayPtr == mpPtrArray) // If there are no more pointers in front of the current (first) one... + DoReallocPtrArray(1, kSideFront); + + mItBegin.mpCurrentArrayPtr[-1] = DoAllocateSubarray(); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + mItBegin.SetSubarray(mItBegin.mpCurrentArrayPtr - 1); + mItBegin.mpCurrent = mItBegin.mpEnd - 1; + ::new((void*)mItBegin.mpCurrent) value_type(eastl::move(valueSaved)); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + ++mItBegin; // The exception could only occur in the new operation above, after we have incremented mItBegin. So we need to undo it. + DoFreeSubarray(mItBegin.mpCurrentArrayPtr[-1]); + throw; + } + #endif + } + } + + template + template + void deque::emplace_back(Args&&... args) + { + if((mItEnd.mpCurrent + 1) != mItEnd.mpEnd) // If we have room in the last subarray... we hope that usually this 'new' pathway gets executed, as it is slightly faster. + ::new((void*)mItEnd.mpCurrent++) value_type(eastl::forward(args)...); // Construct in place. If args is a single arg of type value_type&& then it this will be a move construction. + else + { + // To consider: Detect if value isn't coming from within this container and handle that efficiently. + #if EASTL_USE_FORWARD_WORKAROUND + auto valueSaved = value_type(eastl::forward(args)...); //Workaround for compiler bug in VS2013 + #else + value_type valueSaved(eastl::forward(args)...); // We need to make a temporary, because args may be a value_type that comes from within our container and the operations below may change the container. But we can use move instead of copy. + #endif + if(((mItEnd.mpCurrentArrayPtr - mpPtrArray) + 1) >= (difference_type)mnPtrArraySize) // If there are no more pointers after the current (last) one. + DoReallocPtrArray(1, kSideBack); + + mItEnd.mpCurrentArrayPtr[1] = DoAllocateSubarray(); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + ::new((void*)mItEnd.mpCurrent) value_type(eastl::move(valueSaved)); // We can move valueSaved into position. + mItEnd.SetSubarray(mItEnd.mpCurrentArrayPtr + 1); + mItEnd.mpCurrent = mItEnd.mpBegin; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + // No need to execute '--mItEnd', as the exception could only occur in the new operation above before we set mItEnd. + DoFreeSubarray(mItEnd.mpCurrentArrayPtr[1]); + throw; + } + #endif + } + } + #else + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Note: The following two sets of three functions are nearly copies of the above three functions. + // We (nearly) duplicate code here instead of trying to fold the all nine of these functions into + // three more generic functions because: 1) you can't really make just three functions but rather + // would need to break them apart somewhat, and 2) these duplications are eventually going away + // because they aren't needed with C++11 compilers, though that may not be until the year 2020. + //////////////////////////////////////////////////////////////////////////////////////////////////// + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + typename deque::iterator + deque::emplace(const_iterator position, value_type&& value) + { + if(EASTL_UNLIKELY(position.mpCurrent == mItEnd.mpCurrent)) // If we are doing the same thing as push_back... + { + emplace_back(eastl::move(value)); + return iterator(mItEnd, typename iterator::Decrement()); // Unfortunately, we need to make an iterator here, as the above push_back is an operation that can invalidate existing iterators. + } + else if(EASTL_UNLIKELY(position.mpCurrent == mItBegin.mpCurrent)) // If we are doing the same thing as push_front... + { + emplace_front(eastl::move(value)); + return mItBegin; + } + + iterator itPosition(position, typename iterator::FromConst()); + value_type valueSaved(eastl::move(value)); // We need to save this because value may come from within our container. It would be somewhat tedious to make a workaround that could avoid this. + const difference_type i(itPosition - mItBegin); + + #if EASTL_ASSERT_ENABLED + EASTL_ASSERT(!empty()); // The push_front and push_back calls below assume that we are non-empty. It turns out this is never called unless so. + + if(EASTL_UNLIKELY(!(validate_iterator(itPosition) & isf_valid))) + EASTL_FAIL_MSG("deque::emplace -- invalid iterator"); + #endif + + if(i < (difference_type)(size() / 2)) // Should we insert at the front or at the back? We divide the range in half. + { + emplace_front(*mItBegin); // This operation potentially invalidates all existing iterators and so we need to assign them anew relative to mItBegin below. + + itPosition = mItBegin + i; + + const iterator newPosition (itPosition, typename iterator::Increment()); + iterator oldBegin (mItBegin, typename iterator::Increment()); + const iterator oldBeginPlus1(oldBegin, typename iterator::Increment()); + + oldBegin.copy(oldBeginPlus1, newPosition, eastl::has_trivial_relocate()); + } + else + { + emplace_back(*iterator(mItEnd, typename iterator::Decrement())); + + itPosition = mItBegin + i; + + iterator oldBack (mItEnd, typename iterator::Decrement()); + const iterator oldBackMinus1(oldBack, typename iterator::Decrement()); + + oldBack.copy_backward(itPosition, oldBackMinus1, eastl::has_trivial_relocate()); + } + + *itPosition = eastl::move(valueSaved); + + return itPosition; + } + + template + void deque::emplace_front(value_type&& value) + { + if(mItBegin.mpCurrent != mItBegin.mpBegin) // If we have room in the first subarray... we hope that usually this 'new' pathway gets executed, as it is slightly faster. + ::new((void*)--mItBegin.mpCurrent) value_type(eastl::move(value)); // Move value into position. + else + { + // To consider: Detect if value isn't coming from within this container and handle that efficiently. + value_type valueSaved(eastl::move(value)); // We need to make a temporary, because value may come from within our container and the operations below may change the container. But we can use move instead of copy. + + if(mItBegin.mpCurrentArrayPtr == mpPtrArray) // If there are no more pointers in front of the current (first) one... + DoReallocPtrArray(1, kSideFront); + + mItBegin.mpCurrentArrayPtr[-1] = DoAllocateSubarray(); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + mItBegin.SetSubarray(mItBegin.mpCurrentArrayPtr - 1); + mItBegin.mpCurrent = mItBegin.mpEnd - 1; + ::new((void*)mItBegin.mpCurrent) value_type(eastl::move(valueSaved)); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + ++mItBegin; // The exception could only occur in the new operation above, after we have incremented mItBegin. So we need to undo it. + DoFreeSubarray(mItBegin.mpCurrentArrayPtr[-1]); + throw; + } + #endif + } + } + + template + void deque::emplace_back(value_type&& value) + { + if((mItEnd.mpCurrent + 1) != mItEnd.mpEnd) // If we have room in the last subarray... we hope that usually this 'new' pathway gets executed, as it is slightly faster. + ::new((void*)mItEnd.mpCurrent++) value_type(eastl::move(value)); // Move value into position. + else + { + // To consider: Detect if value isn't coming from within this container and handle that efficiently. + value_type valueSaved(eastl::move(value)); // We need to make a temporary, because value may come from within our container and the operations below may change the container. But we can use move instead of copy. + + if(((mItEnd.mpCurrentArrayPtr - mpPtrArray) + 1) >= (difference_type)mnPtrArraySize) // If there are no more pointers after the current (last) one. + DoReallocPtrArray(1, kSideBack); + + mItEnd.mpCurrentArrayPtr[1] = DoAllocateSubarray(); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + ::new((void*)mItEnd.mpCurrent) value_type(eastl::move(valueSaved)); // We can move valueSaved into position. + mItEnd.SetSubarray(mItEnd.mpCurrentArrayPtr + 1); + mItEnd.mpCurrent = mItEnd.mpBegin; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + // No need to execute '--mItEnd', as the exception could only occur in the new operation above before we set mItEnd. + DoFreeSubarray(mItEnd.mpCurrentArrayPtr[1]); + throw; + } + #endif + } + } + #endif + + template + typename deque::iterator + deque::emplace(const_iterator position, const value_type& value) + { + if(EASTL_UNLIKELY(position.mpCurrent == mItEnd.mpCurrent)) // If we are doing the same thing as push_back... + { + emplace_back(value); + return iterator(mItEnd, typename iterator::Decrement()); // Unfortunately, we need to make an iterator here, as the above push_back is an operation that can invalidate existing iterators. + } + else if(EASTL_UNLIKELY(position.mpCurrent == mItBegin.mpCurrent)) // If we are doing the same thing as push_front... + { + emplace_front(value); + return mItBegin; + } + + iterator itPosition(position, typename iterator::FromConst()); + value_type valueSaved(value); // We need to save this because value may come from within our container. It would be somewhat tedious to make a workaround that could avoid this. + const difference_type i(itPosition - mItBegin); + + #if EASTL_ASSERT_ENABLED + EASTL_ASSERT(!empty()); // The push_front and push_back calls below assume that we are non-empty. It turns out this is never called unless so. + + if(EASTL_UNLIKELY(!(validate_iterator(itPosition) & isf_valid))) + EASTL_FAIL_MSG("deque::emplace -- invalid iterator"); + #endif + + if(i < (difference_type)(size() / 2)) // Should we insert at the front or at the back? We divide the range in half. + { + emplace_front(*mItBegin); // This operation potentially invalidates all existing iterators and so we need to assign them anew relative to mItBegin below. + + itPosition = mItBegin + i; + + const iterator newPosition (itPosition, typename iterator::Increment()); + iterator oldBegin (mItBegin, typename iterator::Increment()); + const iterator oldBeginPlus1(oldBegin, typename iterator::Increment()); + + oldBegin.copy(oldBeginPlus1, newPosition, eastl::has_trivial_relocate()); + } + else + { + emplace_back(*iterator(mItEnd, typename iterator::Decrement())); + + itPosition = mItBegin + i; + + iterator oldBack (mItEnd, typename iterator::Decrement()); + const iterator oldBackMinus1(oldBack, typename iterator::Decrement()); + + oldBack.copy_backward(itPosition, oldBackMinus1, eastl::has_trivial_relocate()); + } + + *itPosition = eastl::move(valueSaved); + + return itPosition; + } + + template + void deque::emplace_front(const value_type& value) + { + if(mItBegin.mpCurrent != mItBegin.mpBegin) // If we have room in the first subarray... + ::new((void*)--mItBegin.mpCurrent) value_type(value); // We hope that usually this 'new' pathway gets executed, as it is slightly faster. + else // Note that in this 'else' case we create a temporary, which is less desirable. + { + // To consider: Detect if value isn't coming from within this container and handle that efficiently. + value_type valueSaved(value); // We need to make a temporary, because value may come from within our container and the operations below may change the container. + + if(mItBegin.mpCurrentArrayPtr == mpPtrArray) // If there are no more pointers in front of the current (first) one... + DoReallocPtrArray(1, kSideFront); + + mItBegin.mpCurrentArrayPtr[-1] = DoAllocateSubarray(); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + mItBegin.SetSubarray(mItBegin.mpCurrentArrayPtr - 1); + mItBegin.mpCurrent = mItBegin.mpEnd - 1; + ::new((void*)mItBegin.mpCurrent) value_type(eastl::move(valueSaved)); // We can move valueSaved into position. + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + ++mItBegin; // The exception could only occur in the new operation above, after we have incremented mItBegin. So we need to undo it. + DoFreeSubarray(mItBegin.mpCurrentArrayPtr[-1]); + throw; + } + #endif + } + } + + template + void deque::emplace_back(const value_type& value) + { + if((mItEnd.mpCurrent + 1) != mItEnd.mpEnd) // If we have room in the last subarray... + ::new((void*)mItEnd.mpCurrent++) value_type(value); + else + { + // To consider: Detect if value isn't coming from within this container and handle that efficiently. + value_type valueSaved(value); // We need to make a temporary, because value may come from within our container and the operations below may change the container. + + if(((mItEnd.mpCurrentArrayPtr - mpPtrArray) + 1) >= (difference_type)mnPtrArraySize) // If there are no more pointers after the current (last) one. + DoReallocPtrArray(1, kSideBack); + + mItEnd.mpCurrentArrayPtr[1] = DoAllocateSubarray(); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + ::new((void*)mItEnd.mpCurrent) value_type(eastl::move(valueSaved)); // We can move valueSaved into position. + mItEnd.SetSubarray(mItEnd.mpCurrentArrayPtr + 1); + mItEnd.mpCurrent = mItEnd.mpBegin; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + // No need to execute '--mItEnd', as the exception could only occur in the new operation above before we set mItEnd. + DoFreeSubarray(mItEnd.mpCurrentArrayPtr[1]); + throw; + } + #endif + } + } + #endif + + + template + typename deque::iterator + deque::insert(const_iterator position, const value_type& value) + { + return emplace(position, value); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + typename deque::iterator + deque::insert(const_iterator position, value_type&& value) + { + return emplace(position, eastl::move(value)); + } + #endif + + + template + void deque::insert(const_iterator position, size_type n, const value_type& value) + { + DoInsertValues(position, n, value); + } + + + template + template + void deque::insert(const_iterator position, InputIterator first, InputIterator last) + { + DoInsert(position, first, last, is_integral()); // The C++ standard requires this sort of behaviour, as InputIterator might actually be Integer and 'first' is really 'count' and 'last' is really 'value'. + } + + + template + typename deque::iterator + deque::insert(const_iterator position, std::initializer_list ilist) + { + const difference_type i(position - mItBegin); + DoInsert(position, ilist.begin(), ilist.end(), false_type()); + return (mItBegin + i); + } + + + template + typename deque::iterator + deque::erase(const_iterator position) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(!(validate_iterator(position) & isf_valid))) + EASTL_FAIL_MSG("deque::erase -- invalid iterator"); + #endif + + iterator itPosition(position, typename iterator::FromConst()); + iterator itNext(itPosition, typename iterator::Increment()); + const difference_type i(itPosition - mItBegin); + + if(i < (difference_type)(size() / 2)) // Should we move the front entries forward or the back entries backward? We divide the range in half. + { + itNext.copy_backward(mItBegin, itPosition, eastl::has_trivial_relocate()); + pop_front(); + } + else + { + itPosition.copy(itNext, mItEnd, eastl::has_trivial_relocate()); + pop_back(); + } + + return mItBegin + i; + } + + + template + typename deque::iterator + deque::erase(const_iterator first, const_iterator last) + { + iterator itFirst(first, typename iterator::FromConst()); + iterator itLast(last, typename iterator::FromConst()); + + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(!(validate_iterator(itFirst) & isf_valid))) + EASTL_FAIL_MSG("deque::erase -- invalid iterator"); + if(EASTL_UNLIKELY(!(validate_iterator(itLast) & isf_valid))) + EASTL_FAIL_MSG("deque::erase -- invalid iterator"); + #endif + + if((itFirst != mItBegin) || (itLast != mItEnd)) // If not erasing everything... (We expect that the user won't call erase(begin, end) because instead the user would just call clear.) + { + const difference_type n(itLast - itFirst); + const difference_type i(itFirst - mItBegin); + + if(i < (difference_type)((size() - n) / 2)) // Should we move the front entries forward or the back entries backward? We divide the range in half. + { + const iterator itNewBegin(mItBegin + n); + value_type** const pPtrArrayBegin = mItBegin.mpCurrentArrayPtr; + + itLast.copy_backward(mItBegin, itFirst, eastl::has_trivial_relocate()); + + for(; mItBegin != itNewBegin; ++mItBegin) // Question: If value_type is a POD type, will the compiler generate this loop at all? + mItBegin.mpCurrent->~value_type(); // If so, then we need to make a specialization for destructing PODs. + + DoFreeSubarrays(pPtrArrayBegin, itNewBegin.mpCurrentArrayPtr); + + // mItBegin = itNewBegin; <-- Not necessary, as the above loop makes it so already. + } + else // Else we will be moving back entries backward. + { + iterator itNewEnd(mItEnd - n); + value_type** const pPtrArrayEnd = itNewEnd.mpCurrentArrayPtr + 1; + + itFirst.copy(itLast, mItEnd, eastl::has_trivial_relocate()); + + for(iterator itTemp(itNewEnd); itTemp != mItEnd; ++itTemp) + itTemp.mpCurrent->~value_type(); + + DoFreeSubarrays(pPtrArrayEnd, mItEnd.mpCurrentArrayPtr + 1); + + mItEnd = itNewEnd; + } + + return mItBegin + i; + } + + clear(); + return mItEnd; + } + + + template + typename deque::reverse_iterator + deque::erase(reverse_iterator position) + { + return reverse_iterator(erase((++position).base())); + } + + + template + typename deque::reverse_iterator + deque::erase(reverse_iterator first, reverse_iterator last) + { + // Version which erases in order from first to last. + // difference_type i(first.base() - last.base()); + // while(i--) + // first = erase(first); + // return first; + + // Version which erases in order from last to first, but is slightly more efficient: + return reverse_iterator(erase(last.base(), first.base())); + } + + + template + void deque::clear() + { + // Destroy all values and all subarrays they belong to, except for the first one, + // as we need to reserve some space for a valid mItBegin/mItEnd. + if(mItBegin.mpCurrentArrayPtr != mItEnd.mpCurrentArrayPtr) // If there are multiple subarrays (more often than not, this will be so)... + { + for(value_type* p1 = mItBegin.mpCurrent; p1 < mItBegin.mpEnd; ++p1) + p1->~value_type(); + for(value_type* p2 = mItEnd.mpBegin; p2 < mItEnd.mpCurrent; ++p2) + p2->~value_type(); + DoFreeSubarray(mItEnd.mpBegin); // Leave mItBegin with a valid subarray. + } + else + { + for(value_type* p = mItBegin.mpCurrent; p < mItEnd.mpCurrent; ++p) + p->~value_type(); + // Don't free the one existing subarray, as we need it for mItBegin/mItEnd. + } + + for(value_type** pPtrArray = mItBegin.mpCurrentArrayPtr + 1; pPtrArray < mItEnd.mpCurrentArrayPtr; ++pPtrArray) + { + for(value_type* p = *pPtrArray, *pEnd = *pPtrArray + kDequeSubarraySize; p < pEnd; ++p) + p->~value_type(); + DoFreeSubarray(*pPtrArray); + } + + mItEnd = mItBegin; // mItBegin/mItEnd will not be dereferencable. + } + + + //template + //void deque::reset_lose_memory() + //{ + // // The reset_lose_memory function is a special extension function which unilaterally + // // resets the container to an empty state without freeing the memory of + // // the contained objects. This is useful for very quickly tearing down a + // // container built into scratch memory. + // + // // Currently we are unable to get this reset_lose_memory operation to work correctly + // // as we haven't been able to find a good way to have a deque initialize + // // without allocating memory. We can lose the old memory, but DoInit + // // would necessarily do a ptrArray allocation. And this is not within + // // our definition of how reset_lose_memory works. + // base_type::DoInit(0); + // + // #if EASTL_RESET_ENABLED + // #else + // #endif + //} + + + template + void deque::swap(deque& x) + { + if(mAllocator == x.mAllocator) // If allocators are equivalent... + DoSwap(x); + else // else swap the contents. + { + const this_type temp(*this); // Can't call eastl::swap because that would + *this = x; // itself call this member swap function. + x = temp; + } + } + + + template + template + void deque::DoInit(Integer n, Integer value, true_type) + { + base_type::DoInit(n); // Call the base uninitialized init function. + DoFillInit(value); + } + + + template + template + void deque::DoInit(InputIterator first, InputIterator last, false_type) + { + typedef typename eastl::iterator_traits::iterator_category IC; + DoInitFromIterator(first, last, IC()); + } + + + template + template + void deque::DoInitFromIterator(InputIterator first, InputIterator last, EASTL_ITC_NS::input_iterator_tag) + { + base_type::DoInit(0); // Call the base uninitialized init function, but don't actually allocate any values. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + // We have little choice but to turn through the source iterator and call + // push_back for each item. It can be slow because it will keep reallocating the + // container memory as we go. We are not allowed to use distance() on an InputIterator. + for(; first != last; ++first) // InputIterators by definition actually only allow you to iterate through them once. + { // Thus the standard *requires* that we do this (inefficient) implementation. + push_back(*first); // Luckily, InputIterators are in practice almost never used, so this code will likely never get executed. + } + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + clear(); + throw; + } + #endif + } + + + template + template + void deque::DoInitFromIterator(ForwardIterator first, ForwardIterator last, EASTL_ITC_NS::forward_iterator_tag) + { + typedef typename eastl::remove_const::type non_const_iterator_type; // If T is a const type (e.g. const int) then we need to initialize it as if it were non-const. + typedef typename eastl::remove_const::type non_const_value_type; + + const size_type n = (size_type)eastl::distance(first, last); + value_type** pPtrArrayCurrent; + + base_type::DoInit(n); // Call the base uninitialized init function. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + for(pPtrArrayCurrent = mItBegin.mpCurrentArrayPtr; pPtrArrayCurrent < mItEnd.mpCurrentArrayPtr; ++pPtrArrayCurrent) // Copy to the known-to-be-completely-used subarrays. + { + // We implment an algorithm here whereby we use uninitialized_copy() and advance() instead of just iterating from first to last and constructing as we go. The reason for this is that we can take advantage of POD data types and implement construction as memcpy operations. + ForwardIterator current(first); // To do: Implement a specialization of this algorithm for non-PODs which eliminates the need for 'current'. + + eastl::advance(current, kDequeSubarraySize); + eastl::uninitialized_copy((non_const_iterator_type)first, (non_const_iterator_type)current, (non_const_value_type*)*pPtrArrayCurrent); + first = current; + } + + eastl::uninitialized_copy((non_const_iterator_type)first, (non_const_iterator_type)last, (non_const_value_type*)mItEnd.mpBegin); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + for(iterator itCurrent(mItBegin), itEnd(pPtrArrayCurrent, *pPtrArrayCurrent); itCurrent != itEnd; ++itCurrent) + itCurrent.mpCurrent->~value_type(); + throw; + } + #endif + } + + + template + void deque::DoFillInit(const value_type& value) + { + value_type** pPtrArrayCurrent = mItBegin.mpCurrentArrayPtr; + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + while(pPtrArrayCurrent < mItEnd.mpCurrentArrayPtr) + { + eastl::uninitialized_fill(*pPtrArrayCurrent, *pPtrArrayCurrent + kDequeSubarraySize, value); + ++pPtrArrayCurrent; + } + eastl::uninitialized_fill(mItEnd.mpBegin, mItEnd.mpCurrent, value); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + for(iterator itCurrent(mItBegin), itEnd(pPtrArrayCurrent, *pPtrArrayCurrent); itCurrent != itEnd; ++itCurrent) + itCurrent.mpCurrent->~value_type(); + throw; + } + #endif + } + + + template + template + void deque::DoAssign(Integer n, Integer value, true_type) // false_type means this is the integer version instead of iterator version. + { + DoAssignValues(static_cast(n), static_cast(value)); + } + + + template + template + void deque::DoAssign(InputIterator first, InputIterator last, false_type) // false_type means this is the iterator version instead of integer version. + { + // Actually, the implementation below requires first/last to be a ForwardIterator and not just an InputIterator. + // But Paul Pedriana if you somehow need to work with an InputIterator and we can deal with it. + const size_type n = (size_type)eastl::distance(first, last); + const size_type nSize = size(); + + if(n > nSize) // If we are increasing the size... + { + InputIterator atEnd(first); + + eastl::advance(atEnd, (difference_type)nSize); + eastl::copy(first, atEnd, mItBegin); + insert(mItEnd, atEnd, last); + } + else // n is <= size. + { + iterator itEnd(eastl::copy(first, last, mItBegin)); + + if(n < nSize) // If we need to erase any trailing elements... + erase(itEnd, mItEnd); + } + } + + + template + void deque::DoAssignValues(size_type n, const value_type& value) + { + const size_type nSize = size(); + + if(n > nSize) // If we are increasing the size... + { + eastl::fill(mItBegin, mItEnd, value); + insert(mItEnd, n - nSize, value); + } + else + { + erase(mItBegin + (difference_type)n, mItEnd); + eastl::fill(mItBegin, mItEnd, value); + } + } + + + template + template + void deque::DoInsert(const const_iterator& position, Integer n, Integer value, true_type) + { + DoInsertValues(position, (size_type)n, (value_type)value); + } + + + template + template + void deque::DoInsert(const const_iterator& position, const InputIterator& first, const InputIterator& last, false_type) + { + typedef typename eastl::iterator_traits::iterator_category IC; + DoInsertFromIterator(position, first, last, IC()); + } + + + template + template + void deque::DoInsertFromIterator(const_iterator position, const InputIterator& first, const InputIterator& last, EASTL_ITC_NS::forward_iterator_tag) + { + const size_type n = (size_type)eastl::distance(first, last); + + // This implementation is nearly identical to DoInsertValues below. + // If you make a bug fix to one, you will likely want to fix the other. + if(position.mpCurrent == mItBegin.mpCurrent) // If inserting at the beginning or into an empty container... + { + iterator itNewBegin(DoReallocSubarray(n, kSideFront)); // itNewBegin to mItBegin refers to memory that isn't initialized yet; so it's not truly a valid iterator. Or at least not a dereferencable one. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + // We would like to use move here instead of copy when possible, which would be useful for + // when inserting from a std::initializer_list, for example. + // To do: solve this by having a template or runtime parameter which specifies move vs copy. + eastl::uninitialized_copy(first, last, itNewBegin); + mItBegin = itNewBegin; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeSubarrays(itNewBegin.mpCurrentArrayPtr, mItBegin.mpCurrentArrayPtr); + throw; + } + #endif + } + else if(EASTL_UNLIKELY(position.mpCurrent == mItEnd.mpCurrent)) // If inserting at the end (i.e. appending)... + { + const iterator itNewEnd(DoReallocSubarray(n, kSideBack)); // mItEnd to itNewEnd refers to memory that isn't initialized yet; so it's not truly a valid iterator. Or at least not a dereferencable one. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + // We would like to use move here instead of copy when possible, which would be useful for + // when inserting from a std::initializer_list, for example. + // To do: solve this by having a template or runtime parameter which specifies move vs copy. + eastl::uninitialized_copy(first, last, mItEnd); + mItEnd = itNewEnd; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeSubarrays(mItEnd.mpCurrentArrayPtr + 1, itNewEnd.mpCurrentArrayPtr + 1); + throw; + } + #endif + } + else + { + const difference_type nInsertionIndex = position - mItBegin; + const size_type nSize = size(); + + if(nInsertionIndex < (difference_type)(nSize / 2)) // If the insertion index is in the front half of the deque... grow the deque at the front. + { + const iterator itNewBegin(DoReallocSubarray(n, kSideFront)); // itNewBegin to mItBegin refers to memory that isn't initialized yet; so it's not truly a valid iterator. Or at least not a dereferencable one. + const iterator itOldBegin(mItBegin); + const iterator itPosition(mItBegin + nInsertionIndex); // We need to reset this value because the reallocation above can invalidate iterators. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + // We have a problem here: we would like to use move instead of copy, but it may be that the range to be inserted comes from + // this container and comes from the segment we need to move. So we can't use move operations unless we are careful to handle + // that situation. The newly inserted contents must be contents that were moved to and not moved from. To do: solve this. + if(nInsertionIndex >= (difference_type)n) // If the newly inserted items will be entirely within the old area... + { + iterator itUCopyEnd(mItBegin + (difference_type)n); + + eastl::uninitialized_copy(mItBegin, itUCopyEnd, itNewBegin); // This can throw. + itUCopyEnd = eastl::copy(itUCopyEnd, itPosition, itOldBegin); // Recycle 'itUCopyEnd' to mean something else. + eastl::copy(first, last, itUCopyEnd); + } + else // Else the newly inserted items are going within the newly allocated area at the front. + { + InputIterator mid(first); + + eastl::advance(mid, (difference_type)n - nInsertionIndex); + eastl::uninitialized_copy_copy(mItBegin, itPosition, first, mid, itNewBegin); // This can throw. + eastl::copy(mid, last, itOldBegin); + } + mItBegin = itNewBegin; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeSubarrays(itNewBegin.mpCurrentArrayPtr, mItBegin.mpCurrentArrayPtr); + throw; + } + #endif + } + else + { + const iterator itNewEnd(DoReallocSubarray(n, kSideBack)); + const iterator itOldEnd(mItEnd); + const difference_type nPushedCount = (difference_type)nSize - nInsertionIndex; + const iterator itPosition(mItEnd - nPushedCount); // We need to reset this value because the reallocation above can invalidate iterators. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + // We have a problem here: we would like to use move instead of copy, but it may be that the range to be inserted comes from + // this container and comes from the segment we need to move. So we can't use move operations unless we are careful to handle + // that situation. The newly inserted contents must be contents that were moved to and not moved from. To do: solve this. + if(nPushedCount > (difference_type)n) + { + const iterator itUCopyEnd(mItEnd - (difference_type)n); + + eastl::uninitialized_copy(itUCopyEnd, mItEnd, mItEnd); + eastl::copy_backward(itPosition, itUCopyEnd, itOldEnd); + eastl::copy(first, last, itPosition); + } + else + { + InputIterator mid(first); + + eastl::advance(mid, nPushedCount); + eastl::uninitialized_copy_copy(mid, last, itPosition, mItEnd, mItEnd); + eastl::copy(first, mid, itPosition); + } + mItEnd = itNewEnd; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeSubarrays(mItEnd.mpCurrentArrayPtr + 1, itNewEnd.mpCurrentArrayPtr + 1); + throw; + } + #endif + } + } + } + + + template + void deque::DoInsertValues(const_iterator position, size_type n, const value_type& value) + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(!(validate_iterator(position) & isf_valid))) + EASTL_FAIL_MSG("deque::insert -- invalid iterator"); + #endif + + // This implementation is nearly identical to DoInsertFromIterator above. + // If you make a bug fix to one, you will likely want to fix the other. + if(position.mpCurrent == mItBegin.mpCurrent) // If inserting at the beginning... + { + const iterator itNewBegin(DoReallocSubarray(n, kSideFront)); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + // Note that we don't make a temp copy of 'value' here. This is because in a + // deque, insertion at either the front or back doesn't cause a reallocation + // or move of data in the middle. That's a key feature of deques, in fact. + eastl::uninitialized_fill(itNewBegin, mItBegin, value); + mItBegin = itNewBegin; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeSubarrays(itNewBegin.mpCurrentArrayPtr, mItBegin.mpCurrentArrayPtr); + throw; + } + #endif + } + else if(EASTL_UNLIKELY(position.mpCurrent == mItEnd.mpCurrent)) // If inserting at the end (i.e. appending)... + { + const iterator itNewEnd(DoReallocSubarray(n, kSideBack)); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + // Note that we don't make a temp copy of 'value' here. This is because in a + // deque, insertion at either the front or back doesn't cause a reallocation + // or move of data in the middle. That's a key feature of deques, in fact. + eastl::uninitialized_fill(mItEnd, itNewEnd, value); + mItEnd = itNewEnd; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeSubarrays(mItEnd.mpCurrentArrayPtr + 1, itNewEnd.mpCurrentArrayPtr + 1); + throw; + } + #endif + } + else + { + // A key purpose of a deque is to implement insertions and removals more efficiently + // than with a vector. We are inserting into the middle of the deque here. A quick and + // dirty implementation of this would be to reallocate the subarrays and simply push + // all values in the middle upward like you would do with a vector. Instead we implement + // the minimum amount of reallocations needed but may need to do some value moving, + // as the subarray sizes need to remain constant and can have no holes in them. + const difference_type nInsertionIndex = position - mItBegin; + const size_type nSize = size(); + const value_type valueSaved(value); + + if(nInsertionIndex < (difference_type)(nSize / 2)) // If the insertion index is in the front half of the deque... grow the deque at the front. + { + const iterator itNewBegin(DoReallocSubarray(n, kSideFront)); + const iterator itOldBegin(mItBegin); + const iterator itPosition(mItBegin + nInsertionIndex); // We need to reset this value because the reallocation above can invalidate iterators. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + if(nInsertionIndex >= (difference_type)n) // If the newly inserted items will be entirely within the old area... + { + iterator itUCopyEnd(mItBegin + (difference_type)n); + + eastl::uninitialized_move_if_noexcept(mItBegin, itUCopyEnd, itNewBegin); // This can throw. + itUCopyEnd = eastl::move(itUCopyEnd, itPosition, itOldBegin); // Recycle 'itUCopyEnd' to mean something else. + eastl::fill(itUCopyEnd, itPosition, valueSaved); + } + else // Else the newly inserted items are going within the newly allocated area at the front. + { + eastl::uninitialized_move_fill(mItBegin, itPosition, itNewBegin, mItBegin, valueSaved); // This can throw. + eastl::fill(itOldBegin, itPosition, valueSaved); + } + mItBegin = itNewBegin; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeSubarrays(itNewBegin.mpCurrentArrayPtr, mItBegin.mpCurrentArrayPtr); + throw; + } + #endif + } + else // Else the insertion index is in the back half of the deque, so grow the deque at the back. + { + const iterator itNewEnd(DoReallocSubarray(n, kSideBack)); + const iterator itOldEnd(mItEnd); + const difference_type nPushedCount = (difference_type)nSize - nInsertionIndex; + const iterator itPosition(mItEnd - nPushedCount); // We need to reset this value because the reallocation above can invalidate iterators. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + if(nPushedCount > (difference_type)n) // If the newly inserted items will be entirely within the old area... + { + iterator itUCopyEnd(mItEnd - (difference_type)n); + + eastl::uninitialized_move_if_noexcept(itUCopyEnd, mItEnd, mItEnd); // This can throw. + itUCopyEnd = eastl::move_backward(itPosition, itUCopyEnd, itOldEnd); // Recycle 'itUCopyEnd' to mean something else. + eastl::fill(itPosition, itUCopyEnd, valueSaved); + } + else // Else the newly inserted items are going within the newly allocated area at the back. + { + eastl::uninitialized_fill_move(mItEnd, itPosition + (difference_type)n, valueSaved, itPosition, mItEnd); // This can throw. + eastl::fill(itPosition, itOldEnd, valueSaved); + } + mItEnd = itNewEnd; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeSubarrays(mItEnd.mpCurrentArrayPtr + 1, itNewEnd.mpCurrentArrayPtr + 1); + throw; + } + #endif + } + } + } + + + template + inline void deque::DoSwap(this_type& x) + { + eastl::swap(mpPtrArray, x.mpPtrArray); + eastl::swap(mnPtrArraySize, x.mnPtrArraySize); + eastl::swap(mItBegin, x.mItBegin); + eastl::swap(mItEnd, x.mItEnd); + eastl::swap(mAllocator, x.mAllocator); // We do this even if EASTL_ALLOCATOR_COPY_ENABLED is 0. + + } + + + template + inline bool deque::validate() const + { + // To do: More detailed validation. + // To do: Try to make the validation resistant to crashes if the data is invalid. + if((end() - begin()) < 0) + return false; + return true; + } + + + template + inline int deque::validate_iterator(const_iterator i) const + { + // To do: We don't currently track isf_current, will need to make it do so. + // To do: Fix the validation below, as it will not catch all invalid iterators. + if((i - begin()) < 0) + return isf_none; + + if((end() - i) < 0) + return isf_none; + + if(i == end()) + return (isf_valid | isf_current); + + return (isf_valid | isf_current | isf_can_dereference); + } + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const deque& a, const deque& b) + { + return ((a.size() == b.size()) && equal(a.begin(), a.end(), b.begin())); + } + + template + inline bool operator!=(const deque& a, const deque& b) + { + return ((a.size() != b.size()) || !equal(a.begin(), a.end(), b.begin())); + } + + template + inline bool operator<(const deque& a, const deque& b) + { + return lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); + } + + template + inline bool operator>(const deque& a, const deque& b) + { + return b < a; + } + + template + inline bool operator<=(const deque& a, const deque& b) + { + return !(b < a); + } + + template + inline bool operator>=(const deque& a, const deque& b) + { + return !(a < b); + } + + template + inline void swap(deque& a, deque& b) + { + a.swap(b); + } + + +} // namespace eastl + + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + + +#endif // Header include guard + + + + + + + diff --git a/libs/eastl/include/EASTL/fixed_allocator.h b/libs/eastl/include/EASTL/fixed_allocator.h new file mode 100644 index 0000000..c3ee959 --- /dev/null +++ b/libs/eastl/include/EASTL/fixed_allocator.h @@ -0,0 +1,449 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements the following +// fixed_allocator +// fixed_allocator_with_overflow +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_FIXED_ALLOCATOR_H +#define EASTL_FIXED_ALLOCATOR_H + + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + #pragma warning(push, 0) + #include + #pragma warning(pop) +#else + #include +#endif + +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4275) // non dll-interface class used as base for DLL-interface classkey 'identifier' +#endif + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /////////////////////////////////////////////////////////////////////////// + // fixed_allocator + /////////////////////////////////////////////////////////////////////////// + + /// fixed_allocator + /// + /// Implements an allocator which allocates a single fixed size where + /// the size, alignment, and memory used for the pool is defined at + /// runtime by the user. This is different from fixed containers + /// such as fixed_list whereby the size and alignment are determined + /// at compile time and the memory is directly built into the container's + /// member data. + /// + /// If the pool's memory is exhausted or was never initialized, the + /// allocate function returns NULL. Consider the fixed_allocator_with_overflow + /// class as an alternative in order to deal with this situation. + /// + /// This class requires the user to call container.get_allocator().init() + /// after constructing the container. There currently isn't a way to + /// construct the container with the initialization parameters, though + /// with some effort such a thing could probably be made possible. + /// It's not as simple as it might first seem, due to the non-copyable + /// nature of fixed allocators. A side effect of this limitation is that + /// you cannot copy-construct a container using fixed_allocators. + /// + /// Another side-effect is that you cannot swap two containers using + /// a fixed_allocator, as a swap requires temporary memory allocated by + /// an equivalent allocator, and such a thing cannot be done implicitly. + /// A workaround for the swap limitation is that you can implement your + /// own swap whereby you provide an explicitly created temporary object. + /// + /// Note: Be careful to set the allocator's node size to the size of the + /// container node and not the size of the contained object. Note that the + /// example code below uses IntListNode. + /// + /// Example usage: + /// typedef eastl::list IntList; + /// typedef IntList::node_type IntListNode; + /// + /// IntListNode buffer[200]; + /// IntList intList; + /// intList.get_allocator().init(buffer, sizeof(buffer), sizeof(IntListNode), __alignof(IntListNode)); + /// + class EASTL_API fixed_allocator : public fixed_pool_base + { + public: + /// fixed_allocator + /// + /// Default constructor. The user usually will need to call init() after + /// constructing via this constructor. + /// + fixed_allocator(const char* /*pName*/ = EASTL_FIXED_POOL_DEFAULT_NAME) + : fixed_pool_base(NULL) + { + } + + + /// fixed_allocator + /// + /// Copy constructor. The user usually will need to call init() after + /// constructing via this constructor. By their nature, fixed-allocators + /// cannot be copied in any useful way, as by their nature the user + /// must manually initialize them. + /// + fixed_allocator(const fixed_allocator&) + : fixed_pool_base(NULL) + { + } + + + /// operator= + /// + /// By their nature, fixed-allocators cannot be copied in any + /// useful way, as by their nature the user must manually + /// initialize them. + /// + fixed_allocator& operator=(const fixed_allocator&) + { + return *this; + } + + + // init + // + // No init here, as the base class version is sufficient. + // + //void init(void* pMemory, size_t memorySize, size_t nodeSize, + // size_t alignment, size_t alignmentOffset = 0); + + + /// allocate + /// + /// Allocates a new object of the size specified upon class initialization. + /// Returns NULL if there is no more memory. + /// + void* allocate(size_t n, int /*flags*/ = 0) + { + // To consider: Verify that 'n' is what the user initialized us with. + + Link* pLink = mpHead; + + if(pLink) // If we have space... + { + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + if(++mnCurrentSize > mnPeakSize) + mnPeakSize = mnCurrentSize; + #endif + + mpHead = pLink->mpNext; + return pLink; + } + else + { + // If there's no free node in the free list, just + // allocate another from the reserved memory area + + if(mpNext != mpCapacity) + { + pLink = mpNext; + + mpNext = reinterpret_cast(reinterpret_cast(mpNext) + n); + + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + if(++mnCurrentSize > mnPeakSize) + mnPeakSize = mnCurrentSize; + #endif + + return pLink; + } + + // EASTL_ASSERT(false); To consider: enable this assert. However, we intentionally disable it because this isn't necessarily an assertable error. + return NULL; + } + } + + + /// allocate + /// + void* allocate(size_t n, size_t /*alignment*/, size_t /*offset*/, int flags = 0) + { + return allocate(n, flags); + } + + + /// deallocate + /// + /// Frees the given object which was allocated by allocate(). + /// If the given node was not allocated by allocate() then the behaviour + /// is undefined. + /// + void deallocate(void* p, size_t) + { + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + --mnCurrentSize; + #endif + + ((Link*)p)->mpNext = mpHead; + mpHead = ((Link*)p); + } + + + using fixed_pool_base::can_allocate; + + + const char* get_name() const + { + return EASTL_FIXED_POOL_DEFAULT_NAME; + } + + + void set_name(const char*) + { + // Nothing to do. We don't allocate memory. + } + + }; // fixed_allocator + + bool operator==(const fixed_allocator& a, const fixed_allocator& b); + bool operator!=(const fixed_allocator& a, const fixed_allocator& b); + + + + /////////////////////////////////////////////////////////////////////////// + // fixed_allocator_with_overflow + /////////////////////////////////////////////////////////////////////////// + + /// fixed_allocator_with_overflow + /// + /// Implements an allocator which allocates a single fixed size where + /// the size, alignment, and memory used for the pool is defined at + /// runtime by the user. This is different from fixed containers + /// such as fixed_list whereby the size and alignment are determined + /// at compile time and the memory is directly built into the container's + /// member data. + /// + /// Note: Be careful to set the allocator's node size to the size of the + /// container node and not the size of the contained object. Note that the + /// example code below uses IntListNode. + /// + /// This class requires the user to call container.get_allocator().init() + /// after constructing the container. There currently isn't a way to + /// construct the container with the initialization parameters, though + /// with some effort such a thing could probably be made possible. + /// It's not as simple as it might first seem, due to the non-copyable + /// nature of fixed allocators. A side effect of this limitation is that + /// you cannot copy-construct a container using fixed_allocators. + /// + /// Another side-effect is that you cannot swap two containers using + /// a fixed_allocator, as a swap requires temporary memory allocated by + /// an equivalent allocator, and such a thing cannot be done implicitly. + /// A workaround for the swap limitation is that you can implement your + /// own swap whereby you provide an explicitly created temporary object. + /// + /// Example usage: + /// typedef eastl::list IntList; + /// typedef IntList::node_type IntListNode; + /// + /// IntListNode buffer[200]; + /// IntList intList; + /// intList.get_allocator().init(buffer, sizeof(buffer), sizeof(IntListNode), __alignof(IntListNode)); + /// + class EASTL_API fixed_allocator_with_overflow : public fixed_pool_base + { + public: + /// fixed_allocator_with_overflow + /// + /// Default constructor. The user usually will need to call init() after + /// constructing via this constructor. + /// + fixed_allocator_with_overflow(const char* pName = EASTL_FIXED_POOL_DEFAULT_NAME) + : fixed_pool_base(NULL), + mOverflowAllocator(pName) + { + } + + + /// fixed_allocator_with_overflow + /// + /// Copy constructor. The user usually will need to call init() after + /// constructing via this constructor. By their nature, fixed-allocators + /// cannot be copied in any useful way, as by their nature the user + /// must manually initialize them. + /// + fixed_allocator_with_overflow(const fixed_allocator_with_overflow&) + : fixed_pool_base(NULL) + { + } + + + /// operator= + /// + /// By their nature, fixed-allocators cannot be copied in any + /// useful way, as by their nature the user must manually + /// initialize them. + /// + fixed_allocator_with_overflow& operator=(const fixed_allocator_with_overflow& x) + { + #if EASTL_ALLOCATOR_COPY_ENABLED + mOverflowAllocator = x.mOverflowAllocator; + #else + (void)x; + #endif + + return *this; + } + + + /// init + /// + void init(void* pMemory, size_t memorySize, size_t nodeSize, + size_t alignment, size_t alignmentOffset = 0) + { + fixed_pool_base::init(pMemory, memorySize, nodeSize, alignment, alignmentOffset); + + mpPoolBegin = pMemory; + mpPoolEnd = (void*)((uintptr_t)pMemory + memorySize); + mnNodeSize = (eastl_size_t)nodeSize; + } + + + /// allocate + /// + /// Allocates a new object of the size specified upon class initialization. + /// Returns NULL if there is no more memory. + /// + void* allocate(size_t /*n*/, int /*flags*/ = 0) + { + // To consider: Verify that 'n' is what the user initialized us with. + + void* p; + + if(mpHead) // If we have space... + { + p = mpHead; + mpHead = mpHead->mpNext; + } + else + p = mOverflowAllocator.allocate(mnNodeSize); + + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + if(p && (++mnCurrentSize > mnPeakSize)) + mnPeakSize = mnCurrentSize; + #endif + + return p; + } + + + /// allocate + /// + void* allocate(size_t n, size_t /*alignment*/, size_t /*offset*/, int flags = 0) + { + return allocate(n, flags); + } + + + /// deallocate + /// + /// Frees the given object which was allocated by allocate(). + /// If the given node was not allocated by allocate() then the behaviour + /// is undefined. + /// + void deallocate(void* p, size_t) + { + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + --mnCurrentSize; + #endif + + if((p >= mpPoolBegin) && (p < mpPoolEnd)) + { + ((Link*)p)->mpNext = mpHead; + mpHead = ((Link*)p); + } + else + mOverflowAllocator.deallocate(p, (size_t)mnNodeSize); + } + + + using fixed_pool_base::can_allocate; + + + const char* get_name() const + { + return mOverflowAllocator.get_name(); + } + + + void set_name(const char* pName) + { + mOverflowAllocator.set_name(pName); + } + + protected: + EASTLAllocatorType mOverflowAllocator; // To consider: Allow the user to define the type of this, presumably via a template parameter. + void* mpPoolBegin; // To consider: We have these member variables and ideally we shouldn't need them. The problem is that + void* mpPoolEnd; // the information about the pool buffer and object size is stored in the owning container + eastl_size_t mnNodeSize; // and we can't have access to it without increasing the amount of code we need and by templating + // more code. It may turn out that simply storing data here is smaller in the end. + }; // fixed_allocator_with_overflow // Granted, this class is usually used for debugging purposes, but perhaps there is an elegant solution. + + bool operator==(const fixed_allocator_with_overflow& a, const fixed_allocator_with_overflow& b); + bool operator!=(const fixed_allocator_with_overflow& a, const fixed_allocator_with_overflow& b); + + + + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + inline bool operator==(const fixed_allocator&, const fixed_allocator&) + { + return false; + } + + inline bool operator!=(const fixed_allocator&, const fixed_allocator&) + { + return false; + } + + inline bool operator==(const fixed_allocator_with_overflow&, const fixed_allocator_with_overflow&) + { + return false; + } + + inline bool operator!=(const fixed_allocator_with_overflow&, const fixed_allocator_with_overflow&) + { + return false; + } + + +} // namespace eastl + + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + + +#endif // Header include guard + + + diff --git a/libs/eastl/include/EASTL/fixed_hash_map.h b/libs/eastl/include/EASTL/fixed_hash_map.h new file mode 100644 index 0000000..6f06a6b --- /dev/null +++ b/libs/eastl/include/EASTL/fixed_hash_map.h @@ -0,0 +1,844 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements a hash_map and hash_multimap which use a fixed size +// memory pool for its buckets and nodes. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_FIXED_HASH_MAP_H +#define EASTL_FIXED_HASH_MAP_H + + +#include +#include + +EA_DISABLE_VC_WARNING(4127) // Conditional expression is constant + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + +namespace eastl +{ + /// EASTL_FIXED_HASH_MAP_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// In the case of fixed-size containers, the allocator name always refers + /// to overflow allocations. + /// + #ifndef EASTL_FIXED_HASH_MAP_DEFAULT_NAME + #define EASTL_FIXED_HASH_MAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_hash_map" // Unless the user overrides something, this is "EASTL fixed_hash_map". + #endif + + #ifndef EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME + #define EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_hash_multimap" // Unless the user overrides something, this is "EASTL fixed_hash_multimap". + #endif + + + /// EASTL_FIXED_HASH_MAP_DEFAULT_ALLOCATOR + /// EASTL_FIXED_HASH_MULTIMAP_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_FIXED_HASH_MAP_DEFAULT_ALLOCATOR + #define EASTL_FIXED_HASH_MAP_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_HASH_MAP_DEFAULT_NAME) + #endif + + #ifndef EASTL_FIXED_HASH_MULTIMAP_DEFAULT_ALLOCATOR + #define EASTL_FIXED_HASH_MULTIMAP_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME) + #endif + + + + /// fixed_hash_map + /// + /// Implements a hash_map with a fixed block of memory identified by the nodeCount and bucketCount + /// template parameters. + /// + /// Template parameters: + /// Key The key type for the map. This is a map of Key to T (value). + /// T The value type for the map. + /// nodeCount The max number of objects to contain. This value must be >= 1. + /// bucketCount The number of buckets to use. This value must be >= 2. + /// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted. + /// Hash hash_set hash function. See hash_set. + /// Predicate hash_set equality testing function. See hash_set. + /// + template , typename Predicate = eastl::equal_to, bool bCacheHashCode = false, typename OverflowAllocator = EASTLAllocatorType> + class fixed_hash_map : public hash_map::node_type), + nodeCount, + EASTL_ALIGN_OF(eastl::pair), + 0, + bEnableOverflow, + OverflowAllocator>, + bCacheHashCode> + { + public: + typedef fixed_hashtable_allocator::node_type), nodeCount, EASTL_ALIGN_OF(eastl::pair), 0, + bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; + typedef hash_map base_type; + typedef fixed_hash_map this_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::size_type size_type; + + enum { kMaxSize = nodeCount }; + + using base_type::mAllocator; + + protected: + node_type** mBucketBuffer[bucketCount + 1]; // '+1' because the hash table needs a null terminating bucket. + char mNodeBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. + + public: + explicit fixed_hash_map(const overflow_allocator_type& overflowAllocator); + + explicit fixed_hash_map(const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate()); + + fixed_hash_map(const Hash& hashFunction, + const Predicate& predicate, + const overflow_allocator_type& overflowAllocator); + + template + fixed_hash_map(InputIterator first, InputIterator last, + const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate()); + + fixed_hash_map(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + fixed_hash_map(this_type&& x); + fixed_hash_map(this_type&& x, const overflow_allocator_type& overflowAllocator); + #endif + fixed_hash_map(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_HASH_MAP_DEFAULT_ALLOCATOR); + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + + size_type max_size() const; + + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT; + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT; + void set_overflow_allocator(const overflow_allocator_type& allocator); + + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + }; // fixed_hash_map + + + + + + /// fixed_hash_multimap + /// + /// Implements a hash_multimap with a fixed block of memory identified by the nodeCount and bucketCount + /// template parameters. + /// + /// Template parameters: + /// Key The key type for the map. This is a map of Key to T (value). + /// T The value type for the map. + /// nodeCount The max number of objects to contain. This value must be >= 1. + /// bucketCount The number of buckets to use. This value must be >= 2. + /// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted. + /// Hash hash_set hash function. See hash_set. + /// Predicate hash_set equality testing function. See hash_set. + /// + template , typename Predicate = eastl::equal_to, bool bCacheHashCode = false, typename OverflowAllocator = EASTLAllocatorType> + class fixed_hash_multimap : public hash_multimap::node_type), + nodeCount, + EASTL_ALIGN_OF(eastl::pair), + 0, + bEnableOverflow, + OverflowAllocator>, + bCacheHashCode> + { + public: + typedef fixed_hashtable_allocator::node_type), nodeCount, EASTL_ALIGN_OF(eastl::pair), 0, + bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; + typedef hash_multimap base_type; + typedef fixed_hash_multimap this_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::size_type size_type; + + enum { kMaxSize = nodeCount }; + + using base_type::mAllocator; + + protected: + node_type** mBucketBuffer[bucketCount + 1]; // '+1' because the hash table needs a null terminating bucket. + char mNodeBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. + + public: + explicit fixed_hash_multimap(const overflow_allocator_type& overflowAllocator); + + explicit fixed_hash_multimap(const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate()); + + fixed_hash_multimap(const Hash& hashFunction, + const Predicate& predicate, + const overflow_allocator_type& overflowAllocator); + + template + fixed_hash_multimap(InputIterator first, InputIterator last, + const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate()); + + fixed_hash_multimap(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + fixed_hash_multimap(this_type&& x); + fixed_hash_multimap(this_type&& x, const overflow_allocator_type& overflowAllocator); + #endif + fixed_hash_multimap(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_HASH_MULTIMAP_DEFAULT_ALLOCATOR); + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + + size_type max_size() const; + + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT; + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT; + void set_overflow_allocator(const overflow_allocator_type& allocator); + + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + }; // fixed_hash_multimap + + + + + + + /////////////////////////////////////////////////////////////////////// + // fixed_hash_map + /////////////////////////////////////////////////////////////////////// + + template + inline fixed_hash_map:: + fixed_hash_map(const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(), + Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + } + + + template + inline fixed_hash_map:: + fixed_hash_map(const Hash& hashFunction, + const Predicate& predicate) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction, + predicate, fixed_allocator_type(NULL, mBucketBuffer)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + } + + + template + inline fixed_hash_map:: + fixed_hash_map(const Hash& hashFunction, + const Predicate& predicate, + const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction, + predicate, fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + } + + + template + template + fixed_hash_map:: + fixed_hash_map(InputIterator first, InputIterator last, + const Hash& hashFunction, + const Predicate& predicate) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction, + predicate, fixed_allocator_type(NULL, mBucketBuffer)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + base_type::insert(first, last); + } + + + template + inline fixed_hash_map:: + fixed_hash_map(const this_type& x) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), + x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline fixed_hash_map:: + fixed_hash_map(this_type&& x) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), + x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + { + // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } + + + template + inline fixed_hash_map:: + fixed_hash_map(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), + x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } + #endif + + + template + inline fixed_hash_map:: + fixed_hash_map(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(), + Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + base_type::insert(ilist.begin(), ilist.end()); + } + + + template + inline typename fixed_hash_map::this_type& + fixed_hash_map::operator=(const this_type& x) + { + base_type::operator=(x); + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename fixed_hash_map::this_type& + fixed_hash_map::operator=(this_type&& x) + { + base_type::operator=(x); + return *this; + } + #endif + + + template + inline typename fixed_hash_map::this_type& + fixed_hash_map::operator=(std::initializer_list ilist) + { + base_type::clear(); + base_type::insert(ilist.begin(), ilist.end()); + return *this; + } + + + template + inline void fixed_hash_map:: + swap(this_type& x) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(*this, x); + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void fixed_hash_map:: + reset() + { + reset_lose_memory(); + } + #endif + + + template + inline void fixed_hash_map:: + reset_lose_memory() + { + base_type::reset_lose_memory(); + base_type::get_allocator().reset(mNodeBuffer); + } + + + template + inline typename fixed_hash_map::size_type + fixed_hash_map::max_size() const + { + return kMaxSize; + } + + + template + inline const typename fixed_hash_map::overflow_allocator_type& + fixed_hash_map::get_overflow_allocator() const EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline typename fixed_hash_map::overflow_allocator_type& + fixed_hash_map::get_overflow_allocator() EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline void fixed_hash_map:: + set_overflow_allocator(const overflow_allocator_type& allocator) + { + mAllocator.set_overflow_allocator(allocator); + } + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline void swap(fixed_hash_map& a, + fixed_hash_map& b) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(a, b); + } + + + + + /////////////////////////////////////////////////////////////////////// + // fixed_hash_multimap + /////////////////////////////////////////////////////////////////////// + + template + inline fixed_hash_multimap:: + fixed_hash_multimap(const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(), + Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + } + + + template + inline fixed_hash_multimap:: + fixed_hash_multimap(const Hash& hashFunction, + const Predicate& predicate) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction, + predicate, fixed_allocator_type(NULL, mBucketBuffer)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + } + + + template + inline fixed_hash_multimap:: + fixed_hash_multimap(const Hash& hashFunction, + const Predicate& predicate, + const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction, + predicate, fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + } + + + template + template + fixed_hash_multimap:: + fixed_hash_multimap(InputIterator first, InputIterator last, + const Hash& hashFunction, + const Predicate& predicate) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction, + predicate, fixed_allocator_type(NULL, mBucketBuffer)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + base_type::insert(first, last); + } + + + template + inline fixed_hash_multimap:: + fixed_hash_multimap(const this_type& x) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), + x.equal_function(),fixed_allocator_type(NULL, mBucketBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline fixed_hash_multimap:: + fixed_hash_multimap(this_type&& x) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), + x.equal_function(),fixed_allocator_type(NULL, mBucketBuffer)) + { + // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } + + + template + inline fixed_hash_multimap:: + fixed_hash_multimap(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), + x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } + #endif + + + template + inline fixed_hash_multimap:: + fixed_hash_multimap(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(), + Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + base_type::insert(ilist.begin(), ilist.end()); + } + + + template + inline typename fixed_hash_multimap::this_type& + fixed_hash_multimap::operator=(const this_type& x) + { + base_type::operator=(x); + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename fixed_hash_multimap::this_type& + fixed_hash_multimap::operator=(this_type&& x) + { + base_type::operator=(x); + return *this; + } + #endif + + + template + inline typename fixed_hash_multimap::this_type& + fixed_hash_multimap::operator=(std::initializer_list ilist) + { + base_type::clear(); + base_type::insert(ilist.begin(), ilist.end()); + return *this; + } + + + template + inline void fixed_hash_multimap:: + swap(this_type& x) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(*this, x); + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void fixed_hash_multimap:: + reset() + { + reset_lose_memory(); + } + #endif + + template + inline void fixed_hash_multimap:: + reset_lose_memory() + { + base_type::reset_lose_memory(); + base_type::get_allocator().reset(mNodeBuffer); + } + + + template + inline typename fixed_hash_multimap::size_type + fixed_hash_multimap::max_size() const + { + return kMaxSize; + } + + + template + inline const typename fixed_hash_multimap::overflow_allocator_type& + fixed_hash_multimap::get_overflow_allocator() const EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline typename fixed_hash_multimap::overflow_allocator_type& + fixed_hash_multimap::get_overflow_allocator() EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline void fixed_hash_multimap::set_overflow_allocator(const overflow_allocator_type& allocator) + { + mAllocator.set_overflow_allocator(allocator); + } + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline void swap(fixed_hash_multimap& a, + fixed_hash_multimap& b) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(a, b); + } + + + /// Spore equivalent of fixed_hash_map; only reading is supported, adding elements might crash. + template , typename Predicate = eastl::equal_to> + class sp_fixed_hash_map : public hash_map + { + public: + typedef hash_map base_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::size_type size_type; + + public: + /* 20h */ int mPoolAllocator[5]; // actually part of mAllocator + /* 34h */ node_type** mBucketBuffer[bucketCount + 1]; + char mPoolBuffer[(nodeCount + 1) * sizeof(node_type) + (bucketCount + 1) * 4]; + }; + + + +} // namespace eastl + +EA_RESTORE_VC_WARNING() + +#endif // Header include guard + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/fixed_hash_set.h b/libs/eastl/include/EASTL/fixed_hash_set.h new file mode 100644 index 0000000..3bd81f0 --- /dev/null +++ b/libs/eastl/include/EASTL/fixed_hash_set.h @@ -0,0 +1,845 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements a hash_set which uses a fixed size memory pool for +// its buckets and nodes. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_FIXED_HASH_SET_H +#define EASTL_FIXED_HASH_SET_H + + +#include +#include + +EA_DISABLE_VC_WARNING(4127) // Conditional expression is constant + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + /// EASTL_FIXED_HASH_SET_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// In the case of fixed-size containers, the allocator name always refers + /// to overflow allocations. + /// + #ifndef EASTL_FIXED_HASH_SET_DEFAULT_NAME + #define EASTL_FIXED_HASH_SET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_hash_set" // Unless the user overrides something, this is "EASTL fixed_hash_set". + #endif + + #ifndef EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME + #define EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_hash_multiset" // Unless the user overrides something, this is "EASTL fixed_hash_multiset". + #endif + + + /// EASTL_FIXED_HASH_SET_DEFAULT_ALLOCATOR + /// EASTL_FIXED_HASH_MULTISET_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_FIXED_HASH_SET_DEFAULT_ALLOCATOR + #define EASTL_FIXED_HASH_SET_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_HASH_SET_DEFAULT_NAME) + #endif + + #ifndef EASTL_FIXED_HASH_MULTISET_DEFAULT_ALLOCATOR + #define EASTL_FIXED_HASH_MULTISET_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME) + #endif + + + + /// fixed_hash_set + /// + /// Implements a hash_set with a fixed block of memory identified by the nodeCount and bucketCount + /// template parameters. + /// + /// Template parameters: + /// Value The type of object the hash_set holds. + /// nodeCount The max number of objects to contain. This value must be >= 1. + /// bucketCount The number of buckets to use. This value must be >= 2. + /// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted. + /// Hash hash_set hash function. See hash_set. + /// Predicate hash_set equality testing function. See hash_set. + /// + template , typename Predicate = eastl::equal_to, bool bCacheHashCode = false, typename OverflowAllocator = EASTLAllocatorType> + class fixed_hash_set : public hash_set::node_type), + nodeCount, + EASTL_ALIGN_OF(Value), + 0, + bEnableOverflow, + OverflowAllocator>, + bCacheHashCode> + { + public: + typedef fixed_hashtable_allocator::node_type), nodeCount, EASTL_ALIGN_OF(Value), 0, + bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; + typedef fixed_hash_set this_type; + typedef hash_set base_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::size_type size_type; + + enum { kMaxSize = nodeCount }; + + using base_type::mAllocator; + + protected: + node_type** mBucketBuffer[bucketCount + 1]; // '+1' because the hash table needs a null terminating bucket. + char mNodeBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. + + public: + explicit fixed_hash_set(const overflow_allocator_type& overflowAllocator); + + explicit fixed_hash_set(const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate()); + + fixed_hash_set(const Hash& hashFunction, + const Predicate& predicate, + const overflow_allocator_type& overflowAllocator); + + template + fixed_hash_set(InputIterator first, InputIterator last, + const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate()); + + fixed_hash_set(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + fixed_hash_set(this_type&& x); + fixed_hash_set(this_type&& x, const overflow_allocator_type& overflowAllocator); + #endif + + fixed_hash_set(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_HASH_SET_DEFAULT_ALLOCATOR); + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + + size_type max_size() const; + + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT; + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT; + void set_overflow_allocator(const overflow_allocator_type& allocator); + + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + }; // fixed_hash_set + + + + + + + /// fixed_hash_multiset + /// + /// Implements a hash_multiset with a fixed block of memory identified by the nodeCount and bucketCount + /// template parameters. + /// + /// Value The type of object the hash_set holds. + /// nodeCount The max number of objects to contain. This value must be >= 1. + /// bucketCount The number of buckets to use. This value must be >= 2. + /// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted. + /// Hash hash_set hash function. See hash_set. + /// Predicate hash_set equality testing function. See hash_set. + /// + template , typename Predicate = eastl::equal_to, bool bCacheHashCode = false, typename OverflowAllocator = EASTLAllocatorType> + class fixed_hash_multiset : public hash_multiset::node_type), + nodeCount, + EASTL_ALIGN_OF(Value), + 0, + bEnableOverflow, + OverflowAllocator>, + bCacheHashCode> + { + public: + typedef fixed_hashtable_allocator::node_type), nodeCount, EASTL_ALIGN_OF(Value), 0, + bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; + typedef hash_multiset base_type; + typedef fixed_hash_multiset this_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::size_type size_type; + + enum { kMaxSize = nodeCount }; + + using base_type::mAllocator; + + protected: + node_type** mBucketBuffer[bucketCount + 1]; // '+1' because the hash table needs a null terminating bucket. + char mNodeBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. + + public: + explicit fixed_hash_multiset(const overflow_allocator_type& overflowAllocator); + + explicit fixed_hash_multiset(const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate()); + + fixed_hash_multiset(const Hash& hashFunction, + const Predicate& predicate, + const overflow_allocator_type& overflowAllocator); + + template + fixed_hash_multiset(InputIterator first, InputIterator last, + const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate()); + + fixed_hash_multiset(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + fixed_hash_multiset(this_type&& x); + fixed_hash_multiset(this_type&& x, const overflow_allocator_type& overflowAllocator); + #endif + fixed_hash_multiset(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_HASH_MULTISET_DEFAULT_ALLOCATOR); + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + + size_type max_size() const; + + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT; + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT; + void set_overflow_allocator(const overflow_allocator_type& allocator); + + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + }; // fixed_hash_multiset + + + + + + /////////////////////////////////////////////////////////////////////// + // fixed_hash_set + /////////////////////////////////////////////////////////////////////// + + template + inline fixed_hash_set:: + fixed_hash_set(const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), + Hash(), Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + } + + + template + inline fixed_hash_set:: + fixed_hash_set(const Hash& hashFunction, + const Predicate& predicate) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), + hashFunction, predicate, fixed_allocator_type(NULL, mBucketBuffer)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + } + + + template + inline fixed_hash_set:: + fixed_hash_set(const Hash& hashFunction, + const Predicate& predicate, + const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), + hashFunction, predicate, fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + } + + + template + template + fixed_hash_set:: + fixed_hash_set(InputIterator first, InputIterator last, + const Hash& hashFunction, + const Predicate& predicate) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction, + predicate, fixed_allocator_type(NULL, mBucketBuffer)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + base_type::insert(first, last); + } + + + template + inline fixed_hash_set:: + fixed_hash_set(const this_type& x) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), + x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline fixed_hash_set::fixed_hash_set(this_type&& x) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), + x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + { + // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } + + + template + inline fixed_hash_set::fixed_hash_set(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), + x.hash_function(), x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } + #endif + + + template + inline fixed_hash_set:: + fixed_hash_set(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(), + Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + base_type::insert(ilist.begin(), ilist.end()); + } + + + template + typename fixed_hash_set::this_type& + fixed_hash_set::operator=(const this_type& x) + { + base_type::operator=(x); + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename fixed_hash_set::this_type& + fixed_hash_set::operator=(this_type&& x) + { + operator=(x); + return *this; + } + #endif + + + template + inline typename fixed_hash_set::this_type& + fixed_hash_set::operator=(std::initializer_list ilist) + { + base_type::clear(); + base_type::insert(ilist.begin(), ilist.end()); + return *this; + } + + + template + inline void fixed_hash_set:: + swap(this_type& x) + { + // We must do a brute-force swap, because fixed containers cannot share memory allocations. + // Note that we create a temp value on the stack. This approach may fail if the size of the + // container is too large. We have a rule against allocating memory from the heap, and so + // if the user wants to swap two large objects of this class, the user will currently need + // to implement it manually. To consider: add code to allocate a temporary buffer if the + // size of the container is too large for the stack. + EASTL_ASSERT(sizeof(x) < EASTL_MAX_STACK_USAGE); // It is dangerous to try to create objects that are too big for the stack. + + const this_type temp(*this); // Can't call eastl::swap because that would + *this = x; // itself call this member swap function. + x = temp; + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + void fixed_hash_set:: + reset() + { + reset_lose_memory(); + } + #endif + + + template + void fixed_hash_set:: + reset_lose_memory() + { + base_type::reset_lose_memory(); + base_type::get_allocator().reset(mNodeBuffer); + } + + + template + inline typename fixed_hash_set::size_type + fixed_hash_set::max_size() const + { + return kMaxSize; + } + + + template + inline const typename fixed_hash_set::overflow_allocator_type& + fixed_hash_set::get_overflow_allocator() const EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline typename fixed_hash_set::overflow_allocator_type& + fixed_hash_set::get_overflow_allocator() EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline void fixed_hash_set:: + set_overflow_allocator(const overflow_allocator_type& allocator) + { + mAllocator.set_overflow_allocator(allocator); + } + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline void swap(fixed_hash_set& a, + fixed_hash_set& b) + { + a.swap(b); + } + + + + + /////////////////////////////////////////////////////////////////////// + // fixed_hash_multiset + /////////////////////////////////////////////////////////////////////// + + template + inline fixed_hash_multiset:: + fixed_hash_multiset(const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(), + Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + } + + + template + inline fixed_hash_multiset:: + fixed_hash_multiset(const Hash& hashFunction, + const Predicate& predicate) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction, + predicate, fixed_allocator_type(NULL, mBucketBuffer)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + } + + + template + inline fixed_hash_multiset:: + fixed_hash_multiset(const Hash& hashFunction, + const Predicate& predicate, + const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction, + predicate, fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + } + + + template + template + inline fixed_hash_multiset:: + fixed_hash_multiset(InputIterator first, InputIterator last, + const Hash& hashFunction, + const Predicate& predicate) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction, + predicate, fixed_allocator_type(NULL, mBucketBuffer)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + base_type::insert(first, last); + } + + + template + inline fixed_hash_multiset:: + fixed_hash_multiset(const this_type& x) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), + x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline fixed_hash_multiset::fixed_hash_multiset(this_type&& x) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), + x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + { + // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } + + + template + inline fixed_hash_multiset::fixed_hash_multiset(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), + x.hash_function(), x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + mAllocator.reset(mNodeBuffer); + base_type::insert(x.begin(), x.end()); + } + #endif + + + template + inline fixed_hash_multiset:: + fixed_hash_multiset(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator) + : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(), + Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + { + EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2)); + + if(!bEnableOverflow) + base_type::set_max_load_factor(10000.f); // Set it so that we will never resize. + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME); + #endif + + mAllocator.reset(mNodeBuffer); + base_type::insert(ilist.begin(), ilist.end()); + } + + + template + inline typename fixed_hash_multiset::this_type& + fixed_hash_multiset::operator=(const this_type& x) + { + base_type::operator=(x); + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename fixed_hash_multiset::this_type& + fixed_hash_multiset::operator=(this_type&& x) + { + base_type::operator=(x); + return *this; + } + #endif + + + template + inline typename fixed_hash_multiset::this_type& + fixed_hash_multiset::operator=(std::initializer_list ilist) + { + base_type::clear(); + base_type::insert(ilist.begin(), ilist.end()); + return *this; + } + + + template + inline void fixed_hash_multiset:: + swap(this_type& x) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(*this, x); + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void fixed_hash_multiset:: + reset() + { + reset_lose_memory(); + } + #endif + + template + inline void fixed_hash_multiset:: + reset_lose_memory() + { + base_type::reset_lose_memory(); + base_type::get_allocator().reset(mNodeBuffer); + } + + + template + inline typename fixed_hash_multiset::size_type + fixed_hash_multiset::max_size() const + { + return kMaxSize; + } + + + template + inline const typename fixed_hash_multiset::overflow_allocator_type& + fixed_hash_multiset::get_overflow_allocator() const EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline typename fixed_hash_multiset::overflow_allocator_type& + fixed_hash_multiset::get_overflow_allocator() EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline void fixed_hash_multiset:: + set_overflow_allocator(const overflow_allocator_type& allocator) + { + mAllocator.set_overflow_allocator(allocator); + } + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline void swap(fixed_hash_multiset& a, + fixed_hash_multiset& b) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(a, b); + } + + + + /// Spore equivalent of fixed_hash_set; only reading is supported, adding elements might crash. + template , typename Predicate = eastl::equal_to, bool bCacheHashCode = false, typename OverflowAllocator = EASTLAllocatorType> + class sp_fixed_hash_set : public hash_set + { + public: + typedef hash_set base_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::size_type size_type; + + public: + /* 20h */ int mPoolAllocator[5]; // actually part of mAllocator + /* 34h */ node_type** mBucketBuffer[bucketCount + 1]; + char mPoolBuffer[(nodeCount + 1) * sizeof(node_type) + (bucketCount + 1) * 4]; + }; + + +} // namespace eastl + +EA_RESTORE_VC_WARNING() + +#endif // Header include guard + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/fixed_list.h b/libs/eastl/include/EASTL/fixed_list.h new file mode 100644 index 0000000..c3cdf8b --- /dev/null +++ b/libs/eastl/include/EASTL/fixed_list.h @@ -0,0 +1,426 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements a list which uses a fixed size memory pool for its nodes. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_FIXED_LIST_H +#define EASTL_FIXED_LIST_H + + +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + /// EASTL_FIXED_LIST_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// In the case of fixed-size containers, the allocator name always refers + /// to overflow allocations. + /// + #ifndef EASTL_FIXED_LIST_DEFAULT_NAME + #define EASTL_FIXED_LIST_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_list" // Unless the user overrides something, this is "EASTL fixed_list". + #endif + + + /// EASTL_FIXED_LIST_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_FIXED_LIST_DEFAULT_ALLOCATOR + #define EASTL_FIXED_LIST_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_LIST_DEFAULT_NAME) + #endif + + + + /// fixed_list + /// + /// fixed_list is a list which uses a single block of contiguous memory + /// for its nodes. The purpose of this is to reduce memory usage relative + /// to a conventional memory allocation system (with block headers), to + /// increase allocation speed (often due to avoidance of mutex locks), + /// to increase performance (due to better memory locality), and to decrease + /// memory fragmentation due to the way that fixed block allocators work. + /// + /// The primary downside to a fixed_list is that the number of nodes it + /// can contain is fixed upon its declaration. If you want a fixed_list + /// that doesn't have this limitation, then you probably don't want a + /// fixed_list. You can always create your own memory allocator that works + /// the way you want. + /// + /// Template parameters: + /// T The type of object the list holds. + /// nodeCount The max number of objects to contain. + /// bEnableOverflow Whether or not we should use the overflow heap if our object pool is exhausted. + /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. + /// + template + class fixed_list : public list::node_type), + nodeCount, EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> > + { + public: + typedef fixed_node_allocator::node_type), nodeCount, + EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef OverflowAllocator overflow_allocator_type; + typedef list base_type; + typedef fixed_list this_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::iterator iterator; + + enum { kMaxSize = nodeCount }; + + using base_type::assign; + using base_type::resize; + using base_type::insert; + using base_type::size; + using base_type::get_allocator; + + protected: + char mBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. + + using base_type::mAllocator; + + public: + fixed_list(); + explicit fixed_list(const overflow_allocator_type& overflowAllocator); // Only applicable if bEnableOverflow is true. + explicit fixed_list(size_type n); // Currently we don't support overflowAllocator specification for other constructors, for simplicity. + fixed_list(size_type n, const value_type& value); + fixed_list(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + fixed_list(this_type&& x); + fixed_list(this_type&&, const overflow_allocator_type& overflowAllocator); + #endif + fixed_list(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_LIST_DEFAULT_ALLOCATOR); + + template + fixed_list(InputIterator first, InputIterator last); + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + size_type max_size() const; // Returns the max fixed size, which is the user-supplied nodeCount parameter. + bool full() const; // Returns true if the fixed space has been fully allocated. Note that if overflow is enabled, the container size can be greater than nodeCount but full() could return true because the fixed space may have a recently freed slot. + bool has_overflowed() const; // Returns true if the allocations spilled over into the overflow allocator. Meaningful only if overflow is enabled. + bool can_overflow() const; // Returns the value of the bEnableOverflow template parameter. + + // OverflowAllocator + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT; + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT; + void set_overflow_allocator(const overflow_allocator_type& allocator); + + // Deprecated: + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + }; // fixed_list + + + + /////////////////////////////////////////////////////////////////////// + // fixed_list + /////////////////////////////////////////////////////////////////////// + + template + inline fixed_list::fixed_list() + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_LIST_DEFAULT_NAME); + #endif + } + + + template + inline fixed_list::fixed_list(const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_LIST_DEFAULT_NAME); + #endif + } + + + template + inline fixed_list::fixed_list(size_type n) + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_LIST_DEFAULT_NAME); + #endif + + resize(n); + } + + + template + inline fixed_list::fixed_list(size_type n, const value_type& value) + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_LIST_DEFAULT_NAME); + #endif + + resize(n, value); + } + + + template + inline fixed_list::fixed_list(const this_type& x) + : base_type(fixed_allocator_type(mBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + assign(x.begin(), x.end()); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline fixed_list::fixed_list(this_type&& x) + : base_type(fixed_allocator_type(mBuffer)) + { + // Since we are a fixed_list, we can't normally swap pointers unless both this and + // x are using using overflow and the overflow allocators are equal. To do: + //if(has_overflowed() && x.has_overflowed() && (get_overflow_allocator() == x.get_overflow_allocator())) + //{ + // We can swap contents and may need to swap the allocators as well. + //} + + // The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that + // way then we may want to make a shared implementation. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + assign(x.begin(), x.end()); + } + + + template + inline fixed_list::fixed_list(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + // See comments above. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + assign(x.begin(), x.end()); + } + #endif + + + template + inline fixed_list::fixed_list(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + assign(ilist.begin(), ilist.end()); + } + + + template + template + fixed_list::fixed_list(InputIterator first, InputIterator last) + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_LIST_DEFAULT_NAME); + #endif + + assign(first, last); + } + + + template + inline typename fixed_list::this_type& + fixed_list::operator=(const this_type& x) + { + if(this != &x) + { + base_type::clear(); + + #if EASTL_ALLOCATOR_COPY_ENABLED + mAllocator = x.mAllocator; // The primary effect of this is to copy the overflow allocator. + #endif + + base_type::assign(x.begin(), x.end()); // It would probably be better to implement this like list::operator=. + } + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename fixed_list::this_type& + fixed_list::operator=(this_type&& x) + { + return operator=(x); + } + #endif + + + template + inline typename fixed_list::this_type& + fixed_list::operator=(std::initializer_list ilist) + { + base_type::clear(); + base_type::assign(ilist.begin(), ilist.end()); + return *this; + } + + + template + inline void fixed_list::swap(this_type& x) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(*this, x); + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void fixed_list::reset() + { + reset_lose_memory(); + } + #endif + + + template + inline void fixed_list::reset_lose_memory() + { + base_type::reset_lose_memory(); + get_allocator().reset(mBuffer); + } + + + template + inline typename fixed_list::size_type + fixed_list::max_size() const + { + return kMaxSize; + } + + + template + inline bool fixed_list::full() const + { + // Note: This implementation isn't right in the case of bEnableOverflow = true because it will return + // false for the case that there are free nodes from the buffer but also nodes from the dynamic heap. + // This can happen if the container exceeds the fixed size and then frees some of the nodes from the fixed buffer. + // The only simple fix for this is to take on another member variable which tracks whether this overflow + // has occurred at some point in the past. + return !mAllocator.can_allocate(); // This is the quickest way of detecting this. has_overflowed uses a different method because it can't use this quick method. + } + + + template + inline bool fixed_list::has_overflowed() const + { + #if EASTL_FIXED_SIZE_TRACKING_ENABLED // If we can use this faster pathway (as size() may be slow)... + return (mAllocator.mPool.mnPeakSize > kMaxSize); + #else + return (size() > kMaxSize); + #endif + } + + + template + inline bool fixed_list::can_overflow() const + { + return bEnableOverflow; + } + + + template + inline const typename fixed_list::overflow_allocator_type& + fixed_list::get_overflow_allocator() const EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline typename fixed_list::overflow_allocator_type& + fixed_list::get_overflow_allocator() EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline void + fixed_list::set_overflow_allocator(const overflow_allocator_type& allocator) + { + mAllocator.set_overflow_allocator(allocator); + } + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline void swap(fixed_list& a, + fixed_list& b) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(a, b); + } + + + + + /// Spore equivalent of fixed_list; only reading is supported, adding elements might crash. + template + class sp_fixed_list : public list + { + public: + typedef list base_type; + typedef typename base_type::node_type node_type; + + public: + /* 0Ch */ int mPoolAllocator[4]; // actually part of mAllocator + /* 1Ch */ node_type mPoolBuffer[nodeCount + 1]; + }; + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/fixed_map.h b/libs/eastl/include/EASTL/fixed_map.h new file mode 100644 index 0000000..6a4eb65 --- /dev/null +++ b/libs/eastl/include/EASTL/fixed_map.h @@ -0,0 +1,641 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements a map and multimap which use a fixed size memory +// pool for their nodes. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_FIXED_MAP_H +#define EASTL_FIXED_MAP_H + + +#include +#include // Included because fixed_rbtree_base resides here. + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + /// EASTL_FIXED_MAP_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// In the case of fixed-size containers, the allocator name always refers + /// to overflow allocations. + /// + #ifndef EASTL_FIXED_MAP_DEFAULT_NAME + #define EASTL_FIXED_MAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_map" // Unless the user overrides something, this is "EASTL fixed_map". + #endif + + #ifndef EASTL_FIXED_MULTIMAP_DEFAULT_NAME + #define EASTL_FIXED_MULTIMAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_multimap" // Unless the user overrides something, this is "EASTL fixed_multimap". + #endif + + + /// EASTL_FIXED_MAP_DEFAULT_ALLOCATOR + /// EASTL_FIXED_MULTIMAP_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_FIXED_MAP_DEFAULT_ALLOCATOR + #define EASTL_FIXED_MAP_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_MAP_DEFAULT_NAME) + #endif + + #ifndef EASTL_FIXED_MULTIMAP_DEFAULT_ALLOCATOR + #define EASTL_FIXED_MULTIMAP_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_MULTIMAP_DEFAULT_NAME) + #endif + + + + /// fixed_map + /// + /// Implements a map with a fixed block of memory identified by the + /// nodeCount template parameter. + /// + /// Key The key object (key in the key/value pair). + /// T The mapped object (value in the key/value pair). + /// nodeCount The max number of objects to contain. + /// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted. + /// Compare Compare function/object for set ordering. + /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. + /// + template , typename OverflowAllocator = EASTLAllocatorType> + class fixed_map : public map::node_type), + nodeCount, EASTL_ALIGN_OF(eastl::pair), 0, bEnableOverflow, OverflowAllocator> > + { + public: + typedef fixed_node_allocator::node_type), nodeCount, + EASTL_ALIGN_OF(eastl::pair), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; + typedef fixed_map this_type; + typedef map base_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::size_type size_type; + + enum { kMaxSize = nodeCount }; + + using base_type::insert; + + protected: + char mBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. + + using base_type::mAllocator; + + public: + fixed_map(); + explicit fixed_map(const overflow_allocator_type& overflowAllocator); + explicit fixed_map(const Compare& compare); + fixed_map(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + fixed_map(this_type&& x); + fixed_map(this_type&& x, const overflow_allocator_type& overflowAllocator); + #endif + fixed_map(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_MAP_DEFAULT_ALLOCATOR); + + template + fixed_map(InputIterator first, InputIterator last); + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + + size_type max_size() const; + + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT; + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT; + void set_overflow_allocator(const overflow_allocator_type& allocator); + + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + }; // fixed_map + + + + + /// fixed_multimap + /// + /// Implements a multimap with a fixed block of memory identified by the + /// nodeCount template parameter. + /// + /// Key The key object (key in the key/value pair). + /// T The mapped object (value in the key/value pair). + /// nodeCount The max number of objects to contain. + /// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted. + /// Compare Compare function/object for set ordering. + /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. + /// + template , typename OverflowAllocator = EASTLAllocatorType> + class fixed_multimap : public multimap::node_type), + nodeCount, EASTL_ALIGN_OF(eastl::pair), 0, bEnableOverflow, OverflowAllocator> > + { + public: + typedef fixed_node_allocator::node_type), nodeCount, + EASTL_ALIGN_OF(eastl::pair), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; + typedef multimap base_type; + typedef fixed_multimap this_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::size_type size_type; + + enum { kMaxSize = nodeCount }; + + using base_type::insert; + + protected: + char mBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. + + using base_type::mAllocator; + + public: + fixed_multimap(); + fixed_multimap(const overflow_allocator_type& overflowAllocator); + explicit fixed_multimap(const Compare& compare); + fixed_multimap(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + fixed_multimap(this_type&& x); + fixed_multimap(this_type&& x, const overflow_allocator_type& overflowAllocator); + #endif + fixed_multimap(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_MULTIMAP_DEFAULT_ALLOCATOR); + + template + fixed_multimap(InputIterator first, InputIterator last); + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + + size_type max_size() const; + + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT; + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT; + void set_overflow_allocator(const overflow_allocator_type& allocator); + + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + }; // fixed_multimap + + + + + + /////////////////////////////////////////////////////////////////////// + // fixed_map + /////////////////////////////////////////////////////////////////////// + + template + inline fixed_map::fixed_map() + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MAP_DEFAULT_NAME); + #endif + } + + + template + inline fixed_map::fixed_map(const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MAP_DEFAULT_NAME); + #endif + } + + + template + inline fixed_map::fixed_map(const Compare& compare) + : base_type(compare, fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MAP_DEFAULT_NAME); + #endif + } + + + template + inline fixed_map::fixed_map(const this_type& x) + : base_type(x.mCompare, fixed_allocator_type(mBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + base_type::operator=(x); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline fixed_map::fixed_map(this_type&& x) + : base_type(x.mCompare, fixed_allocator_type(mBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + base_type::operator=(x); + } + + + template + inline fixed_map::fixed_map(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(x.mCompare, fixed_allocator_type(mBuffer, overflowAllocator)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + base_type::operator=(x); + } + #endif + + + template + fixed_map::fixed_map(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MAP_DEFAULT_NAME); + #endif + + insert(ilist.begin(), ilist.end()); + } + + + template + template + fixed_map::fixed_map(InputIterator first, InputIterator last) + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MAP_DEFAULT_NAME); + #endif + + insert(first, last); + } + + + template + inline typename fixed_map::this_type& + fixed_map::operator=(const this_type& x) + { + base_type::operator=(x); + return *this; + } + + + template + inline typename fixed_map::this_type& + fixed_map::operator=(std::initializer_list ilist) + { + base_type::clear(); + insert(ilist.begin(), ilist.end()); + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename fixed_map::this_type& + fixed_map::operator=(this_type&& x) + { + base_type::operator=(x); + return *this; + } + #endif + + + template + inline void fixed_map::swap(this_type& x) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(*this, x); + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void fixed_map::reset() + { + reset_lose_memory(); + } + #endif + + + template + inline void fixed_map::reset_lose_memory() + { + base_type::reset_lose_memory(); + base_type::get_allocator().reset(mBuffer); + } + + + template + inline typename fixed_map::size_type + fixed_map::max_size() const + { + return kMaxSize; + } + + + template + inline const typename fixed_map::overflow_allocator_type& + fixed_map::get_overflow_allocator() const EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline typename fixed_map::overflow_allocator_type& + fixed_map::get_overflow_allocator() EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline void + fixed_map::set_overflow_allocator(const overflow_allocator_type& allocator) + { + mAllocator.set_overflow_allocator(allocator); + } + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline void swap(fixed_map& a, + fixed_map& b) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(a, b); + } + + + + + /////////////////////////////////////////////////////////////////////// + // fixed_multimap + /////////////////////////////////////////////////////////////////////// + + template + inline fixed_multimap::fixed_multimap() + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MULTIMAP_DEFAULT_NAME); + #endif + } + + + template + inline fixed_multimap::fixed_multimap(const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MULTIMAP_DEFAULT_NAME); + #endif + } + + + template + inline fixed_multimap::fixed_multimap(const Compare& compare) + : base_type(compare, fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MULTIMAP_DEFAULT_NAME); + #endif + } + + + template + inline fixed_multimap::fixed_multimap(const this_type& x) + : base_type(x.mCompare, fixed_allocator_type(mBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + base_type::operator=(x); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline fixed_multimap::fixed_multimap(this_type&& x) + : base_type(x.mCompare, fixed_allocator_type(mBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + base_type::operator=(x); + } + + + template + inline fixed_multimap::fixed_multimap(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(x.mCompare, fixed_allocator_type(mBuffer, overflowAllocator)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + base_type::operator=(x); + } + #endif + + + template + fixed_multimap::fixed_multimap(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MULTIMAP_DEFAULT_NAME); + #endif + + insert(ilist.begin(), ilist.end()); + } + + + template + template + fixed_multimap:: + fixed_multimap(InputIterator first, InputIterator last) + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MULTIMAP_DEFAULT_NAME); + #endif + + insert(first, last); + } + + + template + inline typename fixed_multimap::this_type& + fixed_multimap::operator=(const this_type& x) + { + base_type::operator=(x); + return *this; + } + + + template + inline typename fixed_multimap::this_type& + fixed_multimap::operator=(std::initializer_list ilist) + { + base_type::clear(); + insert(ilist.begin(), ilist.end()); + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename fixed_multimap::this_type& + fixed_multimap::operator=(this_type&& x) + { + base_type::operator=(x); + return *this; + } + #endif + + + template + inline void fixed_multimap::swap(this_type& x) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(*this, x); + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void fixed_multimap::reset() + { + reset_lose_memory(); + } + #endif + + + template + inline void fixed_multimap::reset_lose_memory() + { + base_type::reset_lose_memory(); + base_type::get_allocator().reset(mBuffer); + } + + + template + inline typename fixed_multimap::size_type + fixed_multimap::max_size() const + { + return kMaxSize; + } + + + template + inline const typename fixed_multimap::overflow_allocator_type& + fixed_multimap::get_overflow_allocator() const EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline typename fixed_multimap::overflow_allocator_type& + fixed_multimap::get_overflow_allocator() EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline void + fixed_multimap::set_overflow_allocator(const overflow_allocator_type& allocator) + { + mAllocator.set_overflow_allocator(allocator); + } + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline void swap(fixed_multimap& a, + fixed_multimap& b) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(a, b); + } + + + + /// Spore equivalent of fixed_map; only reading is supported, adding elements might crash. + template + class sp_fixed_map : public map + { + public: + typedef map base_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::size_type size_type; + + public: + /* 1Ch */ int mPoolAllocator[4]; // actually part of mAllocator + char mPoolBuffer[(nodeCount + 1) * sizeof(node_type)]; + }; + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + diff --git a/libs/eastl/include/EASTL/fixed_set.h b/libs/eastl/include/EASTL/fixed_set.h new file mode 100644 index 0000000..51c0d6c --- /dev/null +++ b/libs/eastl/include/EASTL/fixed_set.h @@ -0,0 +1,621 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements a set and multiset which use a fixed size memory +// pool for their nodes. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_FIXED_SET_H +#define EASTL_FIXED_SET_H + + +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + /// EASTL_FIXED_SET_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// In the case of fixed-size containers, the allocator name always refers + /// to overflow allocations. + /// + #ifndef EASTL_FIXED_SET_DEFAULT_NAME + #define EASTL_FIXED_SET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_set" // Unless the user overrides something, this is "EASTL fixed_set". + #endif + + #ifndef EASTL_FIXED_MULTISET_DEFAULT_NAME + #define EASTL_FIXED_MULTISET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_multiset" // Unless the user overrides something, this is "EASTL fixed_multiset". + #endif + + + /// EASTL_FIXED_SET_DEFAULT_ALLOCATOR + /// EASTL_FIXED_MULTISET_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_FIXED_SET_DEFAULT_ALLOCATOR + #define EASTL_FIXED_SET_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_SET_DEFAULT_NAME) + #endif + + #ifndef EASTL_FIXED_MULTISET_DEFAULT_ALLOCATOR + #define EASTL_FIXED_MULTISET_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_MULTISET_DEFAULT_NAME) + #endif + + + + /// fixed_set + /// + /// Implements a set with a fixed block of memory identified by the + /// nodeCount template parameter. + /// + /// Template parameters: + /// Key The type of object the set holds (a.k.a. value). + /// nodeCount The max number of objects to contain. + /// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted. + /// Compare Compare function/object for set ordering. + /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. + /// + template , typename OverflowAllocator = EASTLAllocatorType> + class fixed_set : public set::node_type), + nodeCount, EASTL_ALIGN_OF(Key), 0, bEnableOverflow, OverflowAllocator> > + { + public: + typedef fixed_node_allocator::node_type), nodeCount, + EASTL_ALIGN_OF(Key), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; + typedef set base_type; + typedef fixed_set this_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::size_type size_type; + + enum { kMaxSize = nodeCount }; + + using base_type::insert; + + protected: + char mBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. + + using base_type::mAllocator; + + public: + fixed_set(); + fixed_set(const overflow_allocator_type& overflowAllocator); + explicit fixed_set(const Compare& compare); + fixed_set(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + fixed_set(this_type&& x); + fixed_set(this_type&& x, const overflow_allocator_type& overflowAllocator); + #endif + fixed_set(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_SET_DEFAULT_ALLOCATOR); + + template + fixed_set(InputIterator first, InputIterator last); + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + + size_type max_size() const; + + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT; + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT; + void set_overflow_allocator(const overflow_allocator_type& allocator); + + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + }; // fixed_set + + + + + + + /// fixed_multiset + /// + /// Implements a multiset with a fixed block of memory identified by the + /// nodeCount template parameter. + /// + /// Key The type of object the set holds (a.k.a. value). + /// nodeCount The max number of objects to contain. + /// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted. + /// Compare Compare function/object for set ordering. + /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. + /// + template , typename OverflowAllocator = EASTLAllocatorType> + class fixed_multiset : public multiset::node_type), + nodeCount, EASTL_ALIGN_OF(Key), 0, bEnableOverflow, OverflowAllocator> > + { + public: + typedef fixed_node_allocator::node_type), nodeCount, + EASTL_ALIGN_OF(Key), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; + typedef multiset base_type; + typedef fixed_multiset this_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::size_type size_type; + + enum { kMaxSize = nodeCount }; + + using base_type::insert; + + protected: + char mBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. + + using base_type::mAllocator; + + public: + fixed_multiset(); + fixed_multiset(const overflow_allocator_type& overflowAllocator); + explicit fixed_multiset(const Compare& compare); + fixed_multiset(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + fixed_multiset(this_type&& x); + fixed_multiset(this_type&& x, const overflow_allocator_type& overflowAllocator); + #endif + fixed_multiset(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_MULTISET_DEFAULT_ALLOCATOR); + + template + fixed_multiset(InputIterator first, InputIterator last); + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + + size_type max_size() const; + + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT; + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT; + void set_overflow_allocator(const overflow_allocator_type& allocator); + + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + }; // fixed_multiset + + + + + /////////////////////////////////////////////////////////////////////// + // fixed_set + /////////////////////////////////////////////////////////////////////// + + template + inline fixed_set::fixed_set() + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_SET_DEFAULT_NAME); + #endif + } + + + template + inline fixed_set::fixed_set(const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_SET_DEFAULT_NAME); + #endif + } + + + template + inline fixed_set::fixed_set(const Compare& compare) + : base_type(compare, fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_SET_DEFAULT_NAME); + #endif + } + + + template + inline fixed_set::fixed_set(const this_type& x) + : base_type(x.mCompare, fixed_allocator_type(mBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + base_type::operator=(x); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline fixed_set::fixed_set(this_type&& x) + : base_type(x.mCompare, fixed_allocator_type(mBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + base_type::operator=(x); + } + + + template + inline fixed_set::fixed_set(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(x.mCompare, fixed_allocator_type(mBuffer, overflowAllocator)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + base_type::operator=(x); + } + #endif + + + template + fixed_set::fixed_set(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_SET_DEFAULT_NAME); + #endif + + insert(ilist.begin(), ilist.end()); + } + + + template + template + fixed_set::fixed_set(InputIterator first, InputIterator last) + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_SET_DEFAULT_NAME); + #endif + + insert(first, last); + } + + + template + inline typename fixed_set::this_type& + fixed_set::operator=(const this_type& x) + { + base_type::operator=(x); + return *this; + } + + + template + inline typename fixed_set::this_type& + fixed_set::operator=(std::initializer_list ilist) + { + base_type::clear(); + insert(ilist.begin(), ilist.end()); + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename fixed_set::this_type& + fixed_set::operator=(this_type&& x) + { + base_type::operator=(x); + return *this; + } + #endif + + + template + inline void fixed_set::swap(this_type& x) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(*this, x); + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void fixed_set::reset() + { + reset_lose_memory(); + } + #endif + + + template + inline void fixed_set::reset_lose_memory() + { + base_type::reset_lose_memory(); + base_type::get_allocator().reset(mBuffer); + } + + + template + inline typename fixed_set::size_type + fixed_set::max_size() const + { + return kMaxSize; + } + + + template + inline const typename fixed_set::overflow_allocator_type& + fixed_set::get_overflow_allocator() const EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline typename fixed_set::overflow_allocator_type& + fixed_set::get_overflow_allocator() EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline void fixed_set::set_overflow_allocator(const overflow_allocator_type& allocator) + { + mAllocator.set_overflow_allocator(allocator); + } + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline void swap(fixed_set& a, + fixed_set& b) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(a, b); + } + + + + /////////////////////////////////////////////////////////////////////// + // fixed_multiset + /////////////////////////////////////////////////////////////////////// + + template + inline fixed_multiset::fixed_multiset() + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MULTISET_DEFAULT_NAME); + #endif + } + + + template + inline fixed_multiset::fixed_multiset(const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MULTISET_DEFAULT_NAME); + #endif + } + + + template + inline fixed_multiset::fixed_multiset(const Compare& compare) + : base_type(compare, fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MULTISET_DEFAULT_NAME); + #endif + } + + + template + inline fixed_multiset::fixed_multiset(const this_type& x) + : base_type(x.mCompare, fixed_allocator_type(mBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + base_type::operator=(x); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline fixed_multiset::fixed_multiset(this_type&& x) + : base_type(x.mCompare, fixed_allocator_type(mBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + base_type::operator=(x); + } + + + template + inline fixed_multiset::fixed_multiset(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(x.mCompare, fixed_allocator_type(mBuffer, overflowAllocator)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + base_type::operator=(x); + } + #endif + + + template + fixed_multiset::fixed_multiset(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MULTISET_DEFAULT_NAME); + #endif + + insert(ilist.begin(), ilist.end()); + } + + + template + template + fixed_multiset::fixed_multiset(InputIterator first, InputIterator last) + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_MULTISET_DEFAULT_NAME); + #endif + + insert(first, last); + } + + + template + inline typename fixed_multiset::this_type& + fixed_multiset::operator=(const this_type& x) + { + base_type::operator=(x); + return *this; + } + + + template + inline typename fixed_multiset::this_type& + fixed_multiset::operator=(std::initializer_list ilist) + { + base_type::clear(); + insert(ilist.begin(), ilist.end()); + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename fixed_multiset::this_type& + fixed_multiset::operator=(this_type&& x) + { + base_type::operator=(x); + return *this; + } + #endif + + + template + inline void fixed_multiset::swap(this_type& x) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(*this, x); + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void fixed_multiset::reset() + { + reset_lose_memory(); + } + #endif + + + template + inline void fixed_multiset::reset_lose_memory() + { + base_type::reset_lose_memory(); + base_type::get_allocator().reset(mBuffer); + } + + + template + inline typename fixed_multiset::size_type + fixed_multiset::max_size() const + { + return kMaxSize; + } + + + template + inline const typename fixed_multiset::overflow_allocator_type& + fixed_multiset::get_overflow_allocator() const EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline typename fixed_multiset::overflow_allocator_type& + fixed_multiset::get_overflow_allocator() EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline void fixed_multiset::set_overflow_allocator(const overflow_allocator_type& allocator) + { + mAllocator.set_overflow_allocator(allocator); + } + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline void swap(fixed_multiset& a, + fixed_multiset& b) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(a, b); + } + + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + diff --git a/libs/eastl/include/EASTL/fixed_slist.h b/libs/eastl/include/EASTL/fixed_slist.h new file mode 100644 index 0000000..4933780 --- /dev/null +++ b/libs/eastl/include/EASTL/fixed_slist.h @@ -0,0 +1,414 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements an slist which uses a fixed size memory pool for its nodes. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_FIXED_SLIST_H +#define EASTL_FIXED_SLIST_H + + +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + /// EASTL_FIXED_SLIST_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// In the case of fixed-size containers, the allocator name always refers + /// to overflow allocations. + /// + #ifndef EASTL_FIXED_SLIST_DEFAULT_NAME + #define EASTL_FIXED_SLIST_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_slist" // Unless the user overrides something, this is "EASTL fixed_slist". + #endif + + + /// EASTL_FIXED_SLIST_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_FIXED_SLIST_DEFAULT_ALLOCATOR + #define EASTL_FIXED_SLIST_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_SLIST_DEFAULT_NAME) + #endif + + + + /// fixed_slist + /// + /// fixed_slist is an slist which uses a single block of contiguous memory + /// for its nodes. The purpose of this is to reduce memory usage relative + /// to a conventional memory allocation system (with block headers), to + /// increase allocation speed (often due to avoidance of mutex locks), + /// to increase performance (due to better memory locality), and to decrease + /// memory fragmentation due to the way that fixed block allocators work. + /// + /// The primary downside to a fixed_slist is that the number of nodes it + /// can contain is fixed upon its declaration. If you want a fixed_slist + /// that doesn't have this limitation, then you probably don't want a + /// fixed_slist. You can always create your own memory allocator that works + /// the way you want. + /// + /// Template parameters: + /// T The type of object the slist holds. + /// nodeCount The max number of objects to contain. + /// bEnableOverflow Whether or not we should use the overflow heap if our object pool is exhausted. + /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. + /// + template + class fixed_slist : public slist::node_type), + nodeCount, EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> > + { + public: + typedef fixed_node_allocator::node_type), nodeCount, + EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type; + typedef OverflowAllocator overflow_allocator_type; + typedef slist base_type; + typedef fixed_slist this_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::node_type node_type; + + enum { kMaxSize = nodeCount }; + + using base_type::assign; + using base_type::resize; + using base_type::size; + + protected: + char mBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. + + using base_type::mAllocator; + + public: + fixed_slist(); + explicit fixed_slist(const overflow_allocator_type& overflowAllocator); // Only applicable if bEnableOverflow is true. + explicit fixed_slist(size_type n); // Currently we don't support overflowAllocator specification for other constructors, for simplicity. + fixed_slist(size_type n, const value_type& value); + fixed_slist(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + fixed_slist(this_type&& x); + fixed_slist(this_type&&, const overflow_allocator_type&); + #endif + fixed_slist(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_SLIST_DEFAULT_ALLOCATOR); + + template + fixed_slist(InputIterator first, InputIterator last); + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + size_type max_size() const; // Returns the max fixed size, which is the user-supplied nodeCount parameter. + bool full() const; // Returns true if the fixed space has been fully allocated. Note that if overflow is enabled, the container size can be greater than nodeCount but full() could return true because the fixed space may have a recently freed slot. + bool has_overflowed() const; // Returns true if the allocations spilled over into the overflow allocator. Meaningful only if overflow is enabled. + bool can_overflow() const; // Returns the value of the bEnableOverflow template parameter. + + // OverflowAllocator + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT; + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT; + void set_overflow_allocator(const overflow_allocator_type& allocator); + + // Deprecated: + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + + }; // fixed_slist + + + + + /////////////////////////////////////////////////////////////////////// + // slist + /////////////////////////////////////////////////////////////////////// + + template + inline fixed_slist::fixed_slist() + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_SLIST_DEFAULT_NAME); + #endif + } + + + template + inline fixed_slist::fixed_slist(const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_SLIST_DEFAULT_NAME); + #endif + } + + + template + inline fixed_slist::fixed_slist(size_type n) + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_SLIST_DEFAULT_NAME); + #endif + + resize(n); + } + + + template + inline fixed_slist::fixed_slist(size_type n, const value_type& value) + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_SLIST_DEFAULT_NAME); + #endif + + resize(n, value); + } + + + template + inline fixed_slist::fixed_slist(const this_type& x) + : base_type(fixed_allocator_type(mBuffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + assign(x.begin(), x.end()); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline fixed_slist::fixed_slist(this_type&& x) + : base_type(fixed_allocator_type(mBuffer)) + { + // Since we are a fixed_list, we can't normally swap pointers unless both this and + // x are using using overflow and the overflow allocators are equal. To do: + //if(has_overflowed() && x.has_overflowed() && (get_overflow_allocator() == x.get_overflow_allocator())) + //{ + // We can swap contents and may need to swap the allocators as well. + //} + + // The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that + // way then we may want to make a shared implementation. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + assign(x.begin(), x.end()); + } + + template + inline fixed_slist::fixed_slist(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + // See comments above. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + assign(x.begin(), x.end()); + } + + #endif + + + template + inline fixed_slist::fixed_slist(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_SLIST_DEFAULT_NAME); + #endif + + assign(ilist.begin(), ilist.end()); + } + + + template + template + fixed_slist::fixed_slist(InputIterator first, InputIterator last) + : base_type(fixed_allocator_type(mBuffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_SLIST_DEFAULT_NAME); + #endif + + assign(first, last); + } + + + template + inline typename fixed_slist::this_type& + fixed_slist::operator=(const this_type& x) + { + if(this != &x) + { + base_type::clear(); + + #if EASTL_ALLOCATOR_COPY_ENABLED + mAllocator = x.mAllocator; // The primary effect of this is to copy the overflow allocator. + #endif + + base_type::assign(x.begin(), x.end()); // It would probably be better to implement this like slist::operator=. + } + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename fixed_slist::this_type& + fixed_slist::operator=(this_type&& x) + { + return operator=(x); + } + #endif + + + template + inline typename fixed_slist::this_type& + fixed_slist::operator=(std::initializer_list ilist) + { + base_type::clear(); + base_type::assign(ilist.begin(), ilist.end()); + return *this; + } + + + template + inline void fixed_slist::swap(this_type& x) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(*this, x); + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void fixed_slist::reset() + { + reset_lose_memory(); + } + #endif + + + template + inline void fixed_slist::reset_lose_memory() + { + base_type::reset_lose_memory(); + base_type::get_allocator().reset(mBuffer); + } + + + template + inline typename fixed_slist::size_type + fixed_slist::max_size() const + { + return kMaxSize; + } + + + template + inline bool fixed_slist::full() const + { + // Note: This implementation isn't right in the case of bEnableOverflow = true because it will return + // false for the case that there are free nodes from the buffer but also nodes from the dynamic heap. + // This can happen if the container exceeds the fixed size and then frees some of the nodes from the fixed buffer. + return !mAllocator.can_allocate(); // This is the quickest way of detecting this. has_overflowed uses a different method because it can't use this quick method. + } + + + template + inline bool fixed_slist::has_overflowed() const + { + #if EASTL_FIXED_SIZE_TRACKING_ENABLED // If we can use this faster pathway (as size() may be slow)... + return (mAllocator.mPool.mnPeakSize > kMaxSize); + #else + return (size() > kMaxSize); + #endif + } + + + template + inline bool fixed_slist::can_overflow() const + { + return bEnableOverflow; + } + + + template + inline const typename fixed_slist::overflow_allocator_type& + fixed_slist::get_overflow_allocator() const EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline typename fixed_slist::overflow_allocator_type& + fixed_slist::get_overflow_allocator() EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline void + fixed_slist::set_overflow_allocator(const overflow_allocator_type& allocator) + { + mAllocator.set_overflow_allocator(allocator); + } + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline void swap(fixed_slist& a, + fixed_slist& b) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(a, b); + } + + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/fixed_string.h b/libs/eastl/include/EASTL/fixed_string.h new file mode 100644 index 0000000..7b28f74 --- /dev/null +++ b/libs/eastl/include/EASTL/fixed_string.h @@ -0,0 +1,823 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements a string which uses a fixed size memory pool. +// The bEnableOverflow template parameter allows the container to resort to +// heap allocations if the memory pool is exhausted. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_FIXED_STRING_H +#define EASTL_FIXED_STRING_H + + +#include +#if EASTL_ABSTRACT_STRING_ENABLED + #include +#else // 'else' encompasses the entire rest of this file. +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + /// EASTL_FIXED_STRING_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// In the case of fixed-size containers, the allocator name always refers + /// to overflow allocations. + /// + #ifndef EASTL_FIXED_STRING_DEFAULT_NAME + #define EASTL_FIXED_STRING_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_string" // Unless the user overrides something, this is "EASTL fixed_string". + #endif + + + + /// fixed_string + /// + /// A fixed_string with bEnableOverflow == true is identical to a regular + /// string in terms of its behavior. All the expectations of regular string + /// apply to it and no additional expectations come from it. When bEnableOverflow + /// is false, fixed_string behaves like regular string with the exception that + /// its capacity can never increase. All operations you do on such a fixed_string + /// which require a capacity increase will result in undefined behavior or an + /// C++ allocation exception, depending on the configuration of EASTL. + /// + /// Note: The nodeCount value is the amount of characters to allocate, which needs to + /// take into account a terminating zero. Thus if you want to store strings with a strlen + /// of 30, the nodeCount value must be at least 31. + /// + /// Template parameters: + /// T The type of object the string holds (char, wchar_t, char8_t, char16_t, char32_t). + /// nodeCount The max number of objects to contain. + /// bEnableOverflow Whether or not we should use the overflow heap if our object pool is exhausted. + /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. + /// + /// Notes: + /// The nodeCount value must be at least 2, one for a character and one for a terminating 0. + /// + /// As of this writing, the string class necessarily reallocates when an insert of + /// self is done into self. As a result, the fixed_string class doesn't support + /// inserting self into self unless the bEnableOverflow template parameter is true. + /// + /// Example usage: + /// fixed_string fixedString("hello world"); // Can hold up to a strlen of 128. + /// + /// fixedString = "hola mundo"; + /// fixedString.clear(); + /// fixedString.resize(200); + /// fixedString.sprintf("%f", 1.5f); + /// + template + class fixed_string : public basic_string > + { + public: + typedef fixed_vector_allocator fixed_allocator_type; + typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type; + typedef basic_string base_type; + typedef fixed_string this_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::CtorDoNotInitialize CtorDoNotInitialize; + typedef typename base_type::CtorSprintf CtorSprintf; + typedef aligned_buffer aligned_buffer_type; + + enum { kMaxSize = nodeCount - 1 }; // -1 because we need to save one element for the silent terminating null. + + using base_type::mAllocator; + using base_type::npos; + using base_type::mpBegin; + using base_type::mpEnd; + using base_type::mpCapacity; + using base_type::append; + using base_type::resize; + using base_type::clear; + using base_type::size; + using base_type::sprintf_va_list; + using base_type::DoAllocate; + using base_type::DoFree; + + protected: + union // We define a union in order to avoid strict pointer aliasing issues with compilers like GCC. + { + value_type mArray[1]; + aligned_buffer_type mBuffer; // Question: Why are we doing this aligned_buffer thing? Why not just do an array of value_type, given that we are using just strings of char types. + }; + + public: + fixed_string(); + explicit fixed_string(const overflow_allocator_type& overflowAllocator); // Only applicable if bEnableOverflow is true. + fixed_string(const base_type& x, size_type position, size_type n = base_type::npos); // Currently we don't support overflowAllocator specification for other constructors, for simplicity. + fixed_string(const value_type* p, size_type n); + fixed_string(const value_type* p); + fixed_string(size_type n, const value_type& value); + fixed_string(const this_type& x); + fixed_string(const this_type& x, const overflow_allocator_type& overflowAllocator); + fixed_string(const base_type& x); + fixed_string(const value_type* pBegin, const value_type* pEnd); + fixed_string(CtorDoNotInitialize, size_type n); + fixed_string(CtorSprintf, const value_type* pFormat, ...); + fixed_string(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator); + + #if EASTL_MOVE_SEMANTICS_ENABLED + fixed_string(this_type&& x); + fixed_string(this_type&& x, const overflow_allocator_type& overflowAllocator); + #endif + + this_type& operator=(const this_type& x); + this_type& operator=(const base_type& x); + this_type& operator=(const value_type* p); + this_type& operator=(const value_type c); + this_type& operator=(std::initializer_list ilist); + + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + void set_capacity(size_type n); + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + size_type max_size() const; + bool full() const; // Returns true if the fixed space has been fully allocated. Note that if overflow is enabled, the container size can be greater than nodeCount but full() could return true because the fixed space may have a recently freed slot. + bool has_overflowed() const; // Returns true if the allocations spilled over into the overflow allocator. Meaningful only if overflow is enabled. + bool can_overflow() const; // Returns the value of the bEnableOverflow template parameter. + + // The inherited versions of substr/left/right call the basic_string constructor, + // which will call the overflow allocator and fail if bEnableOverflow == false + this_type substr(size_type position, size_type n) const; + this_type left(size_type n) const; + this_type right(size_type n) const; + + // OverflowAllocator + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT; + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT; + void set_overflow_allocator(const overflow_allocator_type& allocator); + + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + + }; // fixed_string + + + + + + /////////////////////////////////////////////////////////////////////// + // fixed_string + /////////////////////////////////////////////////////////////////////// + + template + inline fixed_string::fixed_string() + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + } + + + template + inline fixed_string::fixed_string(const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + } + + + template + inline fixed_string::fixed_string(const this_type& x) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(x); + } + + + template + inline fixed_string::fixed_string(const this_type& x, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(x); + } + + + template + inline fixed_string::fixed_string(const base_type& x) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.get_allocator().get_name()); + #endif + + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(x); + } + + + template + inline fixed_string::fixed_string(const base_type& x, size_type position, size_type n) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.get_allocator().get_name()); + #endif + + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(x, position, n); + } + + + template + inline fixed_string::fixed_string(const value_type* p, size_type n) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(p, n); + } + + + template + inline fixed_string::fixed_string(const value_type* p) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + append(p); // There better be enough space to hold the assigned string. + } + + + template + inline fixed_string::fixed_string(size_type n, const value_type& value) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(n, value); // There better be enough space to hold the assigned string. + } + + + template + inline fixed_string::fixed_string(const value_type* pBegin, const value_type* pEnd) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(pBegin, pEnd); + } + + + template + inline fixed_string::fixed_string(CtorDoNotInitialize, size_type n) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpBegin = mArray; + mpCapacity = mpBegin + nodeCount; + + if((mpBegin + n) < mpCapacity) + { + mpEnd = mpBegin + n; + *mpEnd = 0; + } + else + { + mpEnd = mArray; + *mpEnd = 0; + resize(n); + } + } + + + template + inline fixed_string::fixed_string(CtorSprintf, const value_type* pFormat, ...) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + va_list arguments; + va_start(arguments, pFormat); + sprintf_va_list(pFormat, arguments); + va_end(arguments); + } + + + template + inline fixed_string::fixed_string(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_STRING_DEFAULT_NAME); + #endif + + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(ilist.begin(), ilist.end()); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline fixed_string::fixed_string(this_type&& x) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + // We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers. + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.get_allocator().get_name()); + #endif + + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(x); // Let x destruct its own items. + } + + template + inline fixed_string::fixed_string(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator)) + { + // We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers. + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.get_allocator().get_name()); + #endif + + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + *mpBegin = 0; + + append(x); // Let x destruct its own items. + } + #endif + + + template + inline typename fixed_string::this_type& + fixed_string::operator=(const this_type& x) + { + if(this != &x) + { + clear(); + + #if EASTL_ALLOCATOR_COPY_ENABLED + mAllocator = x.mAllocator; + #endif + + append(x); + } + return *this; + } + + + template + inline typename fixed_string:: + this_type& fixed_string::operator=(const base_type& x) + { + if(static_cast(this) != &x) + { + clear(); + + #if EASTL_ALLOCATOR_COPY_ENABLED + mAllocator = x.get_allocator(); + #endif + + append(x); + } + return *this; + } + + + template + inline typename fixed_string:: + this_type& fixed_string::operator=(const value_type* p) + { + if(mpBegin != p) + { + clear(); + append(p); + } + return *this; + } + + + template + inline typename fixed_string:: + this_type& fixed_string::operator=(const value_type c) + { + clear(); + append((size_type)1, c); + return *this; + } + + + template + inline typename fixed_string:: + this_type& fixed_string::operator=(std::initializer_list ilist) + { + clear(); + append(ilist.begin(), ilist.end()); + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename fixed_string:: + this_type& fixed_string::operator=(this_type&& x) + { + // We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers. + + // if(static_cast(this) != &x) This should be impossible, so we disable it until proven otherwise. + { + clear(); + + #if EASTL_ALLOCATOR_COPY_ENABLED + mAllocator = x.get_allocator(); + #endif + + append(x); // Let x destruct its own items. + } + return *this; + } + #endif + + + template + inline void fixed_string::swap(this_type& x) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(*this, x); + } + + + template + inline void fixed_string::set_capacity(size_type n) + { + const size_type nPrevSize = (size_type)(mpEnd - mpBegin); + const size_type nPrevCapacity = (size_type)((mpCapacity - mpBegin) - 1); // -1 because the terminating 0 isn't included in the calculated capacity value. + + if(n == npos) // If the user means to set the capacity so that it equals the size (i.e. free excess capacity)... + n = nPrevSize; + + if(n != nPrevCapacity) // If the request results in a capacity change... + { + const size_type allocSize = (n + 1); // +1 because the terminating 0 isn't included in the supplied capacity value. So now n refers the amount of memory we need. + + if(can_overflow() && (((uintptr_t)mpBegin != (uintptr_t)mBuffer.buffer) || (allocSize > kMaxSize))) // If we are or would be using dynamically allocated memory instead of our fixed-size member buffer... + { + T* const pNewData = (allocSize <= kMaxSize) ? (T*)&mBuffer.buffer[0] : DoAllocate(allocSize); + T* const pCopyEnd = (n < nPrevSize) ? (mpBegin + n) : mpEnd; + CharStringUninitializedCopy(mpBegin, pCopyEnd, pNewData); // Copy [mpBegin, pCopyEnd) to pNewData. + if((uintptr_t)mpBegin != (uintptr_t)mBuffer.buffer) + DoFree(mpBegin, (size_type)(mpCapacity - mpBegin)); + + mpEnd = pNewData + (pCopyEnd - mpBegin); + mpBegin = pNewData; + mpCapacity = mpBegin + allocSize; + } // Else the new capacity would be within our fixed buffer. + else if(n < nPrevSize) // If the newly requested capacity is less than our size, we do what vector::set_capacity does and resize, even though we actually aren't reducing the capacity. + resize(n); + } + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void fixed_string::reset() + { + reset_lose_memory(); + } + #endif + + + template + inline void fixed_string::reset_lose_memory() + { + mpBegin = mpEnd = mArray; + mpCapacity = mpBegin + nodeCount; + } + + + template + inline typename fixed_string:: + size_type fixed_string::max_size() const + { + return kMaxSize; + } + + + template + inline bool fixed_string::full() const + { + // If size >= capacity, then we are definitely full. + // Also, if our size is smaller but we've switched away from mBuffer due to a previous overflow, then we are considered full. + return ((size_t)(mpEnd - mpBegin) >= kMaxSize) || ((void*)mpBegin != (void*)mBuffer.buffer); + } + + + template + inline bool fixed_string::has_overflowed() const + { + // This will be incorrect for the case that bOverflowEnabled is true and the container was resized + // down to a small size where the fixed buffer could take over ownership of the data again. + // The only simple fix for this is to take on another member variable which tracks whether this overflow + // has occurred at some point in the past. + return ((void*)mpBegin != (void*)mBuffer.buffer); + } + + + template + inline bool fixed_string::can_overflow() const + { + return bEnableOverflow; + } + + + template + inline typename fixed_string:: + this_type fixed_string::substr(size_type position, size_type n) const + { + #if EASTL_STRING_OPT_RANGE_ERRORS + if(position > (size_type)(mpEnd - mpBegin)) + base_type::ThrowRangeException(); + #endif + + return fixed_string(mpBegin + position, mpBegin + position + eastl::min_alt(n, (size_type)(mpEnd - mpBegin) - position)); + } + + + template + inline typename fixed_string:: + this_type fixed_string::left(size_type n) const + { + const size_type nLength = size(); + if(n < nLength) + return fixed_string(mpBegin, mpBegin + n); + return *this; + } + + + template + inline typename fixed_string:: + this_type fixed_string::right(size_type n) const + { + const size_type nLength = size(); + if(n < nLength) + return fixed_string(mpEnd - n, mpEnd); + return *this; + } + + + template + inline const typename fixed_string:: + overflow_allocator_type& fixed_string::get_overflow_allocator() const EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline typename fixed_string:: + overflow_allocator_type& fixed_string::get_overflow_allocator() EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline void + fixed_string::set_overflow_allocator(const overflow_allocator_type& allocator) + { + mAllocator.set_overflow_allocator(allocator); + } + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + + // Operator + + template + fixed_string operator+(const fixed_string& a, + const fixed_string& b) + { + // We have a problem here because need to return an fixed_string by value. This will typically result in it + // using stack space equal to its size. That size may be too large to be workable. + typedef fixed_string this_type; + + this_type result(const_cast(a).get_overflow_allocator()); + result.append(a); + result.append(b); + return result; + } + + + template + fixed_string operator+(const typename fixed_string::value_type* p, + const fixed_string& b) + { + typedef fixed_string this_type; + + const typename this_type::size_type n = (typename this_type::size_type)CharStrlen(p); + this_type result(const_cast(b).get_overflow_allocator()); + result.append(p, p + n); + result.append(b); + return result; + } + + + template + fixed_string operator+(typename fixed_string::value_type c, + const fixed_string& b) + { + typedef fixed_string this_type; + + this_type result(const_cast(b).get_overflow_allocator()); + result.push_back(c); + result.append(b); + return result; + } + + + template + fixed_string operator+(const fixed_string& a, + const typename fixed_string::value_type* p) + { + typedef fixed_string this_type; + + const typename this_type::size_type n = (typename this_type::size_type)CharStrlen(p); + this_type result(const_cast(a).get_overflow_allocator()); + result.append(a); + result.append(p, p + n); + return result; + } + + + template + fixed_string operator+(const fixed_string& a, + typename fixed_string::value_type c) + { + typedef fixed_string this_type; + + this_type result(const_cast(a).get_overflow_allocator()); + result.append(a); + result.push_back(c); + return result; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + fixed_string operator+(fixed_string&& a, + fixed_string&& b) + { + a.append(b); // Using an rvalue by name results in it becoming an lvalue. + return a; + } + + template + fixed_string operator+(fixed_string&& a, + const fixed_string& b) + { + a.append(b); + return a; + } + + template + fixed_string operator+(const typename fixed_string::value_type* p, + fixed_string&& b) + { + b.insert(0, p); + return b; + } + + template + fixed_string operator+(fixed_string&& a, + const typename fixed_string::value_type* p) + { + a.append(p); + return a; + } + + template + fixed_string operator+(fixed_string&& a, + typename fixed_string::value_type c) + { + a.push_back(c); + return a; + } + #endif + + + // operator ==, !=, <, >, <=, >= come from the string implementations. + + template + inline void swap(fixed_string& a, + fixed_string& b) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(a, b); + } + + +} // namespace eastl + + +#endif // EASTL_ABSTRACT_STRING_ENABLED + +#endif // Header include guard + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/fixed_substring.h b/libs/eastl/include/EASTL/fixed_substring.h new file mode 100644 index 0000000..317e1a9 --- /dev/null +++ b/libs/eastl/include/EASTL/fixed_substring.h @@ -0,0 +1,278 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_FIXED_SUBSTRING_H +#define EASTL_FIXED_SUBSTRING_H + + +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// fixed_substring + /// + /// Implements a string which is a reference to a segment of characters. + /// This class is efficient because it allocates no memory and copies no + /// memory during construction and assignment, but rather refers directly + /// to the segment of chracters. A common use of this is to have a + /// fixed_substring efficiently refer to a substring within another string. + /// + /// You cannot directly resize a fixed_substring (e.g. via resize, insert, + /// append, erase), but you can assign a different substring to it. + /// You can modify the characters within a substring in place. + /// As of this writing, in the name of being lean and simple it is the + /// user's responsibility to not call unsupported resizing functions + /// such as those listed above. A detailed listing of the functions which + /// are not supported is given below in the class declaration. + /// + /// The c_str function doesn't act as one might hope, as it simply + /// returns the pointer to the beginning of the string segment and the + /// 0-terminator may be beyond the end of the segment. If you want to + /// always be able to use c_str as expected, use the fixed string solution + /// we describe below. + /// + /// Another use of fixed_substring is to provide C++ string-like functionality + /// with a C character array. This allows you to work on a C character array + /// as if it were a C++ string as opposed using the C string API. Thus you + /// can do this: + /// + /// void DoSomethingForUser(char* timeStr, size_t timeStrCapacity) + /// { + /// fixed_substring tmp(timeStr, timeStrCapacity); + /// tmp = "hello "; + /// tmp += "world"; + /// } + /// + /// Note that this class constructs and assigns from const string pointers + /// and const string objects, yet this class does not declare its member + /// data as const. This is a concession in order to allow this implementation + /// to be simple and lean. It is the user's responsibility to make sure + /// that strings that should not or can not be modified are either not + /// used by fixed_substring or are not modified by fixed_substring. + /// + /// A more flexible alternative to fixed_substring is fixed_string. + /// fixed_string has none of the functional limitations that fixed_substring + /// has and like fixed_substring it doesn't allocate memory. However, + /// fixed_string makes a *copy* of the source string and uses local + /// memory to store that copy. Also, fixed_string objects on the stack + /// are going to have a limit as to their maximum size. + /// + /// Notes: + /// As of this writing, the string class necessarily reallocates when + /// an insert of self is done into self. As a result, the fixed_substring + /// class doesn't support inserting self into self. + /// + /// Example usage: + /// basic_string str("hello world"); + /// fixed_substring sub(str, 2, 5); // sub == "llo w" + /// + template + class fixed_substring : public basic_string + { + public: + typedef basic_string base_type; + typedef fixed_substring this_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + + using base_type::npos; + using base_type::mpBegin; + using base_type::mpEnd; + using base_type::mpCapacity; + using base_type::reset_lose_memory; + using base_type::mAllocator; + + public: + fixed_substring() + : base_type() + { + } + + fixed_substring(const base_type& x) + : base_type() + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.get_allocator().get_name()); + #endif + + assign(x); + } + + // We gain no benefit from having an rvalue move constructor or assignment operator, + // as this class is a const class. + + fixed_substring(const base_type& x, size_type position, size_type n = base_type::npos) + : base_type() + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.get_allocator().get_name()); + #endif + + assign(x, position, n); + } + + fixed_substring(const value_type* p, size_type n) + : base_type() + { + assign(p, n); + } + + fixed_substring(const value_type* p) + : base_type() + { + assign(p); + } + + fixed_substring(const value_type* pBegin, const value_type* pEnd) + : base_type() + { + assign(pBegin, pEnd); + } + + ~fixed_substring() + { + // We need to reset, as otherwise the parent destructor will + // attempt to free our memory. + reset_lose_memory(); + } + + this_type& operator=(const base_type& x) + { + assign(x); + return *this; + } + + this_type& operator=(const value_type* p) + { + assign(p); + return *this; + } + + this_type& assign(const base_type& x) + { + // By design, we need to cast away const-ness here. + mpBegin = const_cast(x.data()); + mpEnd = mpBegin + x.size(); + mpCapacity = mpEnd; + return *this; + } + + this_type& assign(const base_type& x, size_type position, size_type n) + { + // By design, we need to cast away const-ness here. + mpBegin = const_cast(x.data()) + position; + mpEnd = mpBegin + n; + mpCapacity = mpEnd; + return *this; + } + + this_type& assign(const value_type* p, size_type n) + { + // By design, we need to cast away const-ness here. + mpBegin = const_cast(p); + mpEnd = mpBegin + n; + mpCapacity = mpEnd; + return *this; + } + + this_type& assign(const value_type* p) + { + // By design, we need to cast away const-ness here. + mpBegin = const_cast(p); + mpEnd = mpBegin + CharStrlen(p); + mpCapacity = mpEnd; + return *this; + } + + this_type& assign(const value_type* pBegin, const value_type* pEnd) + { + // By design, we need to cast away const-ness here. + mpBegin = const_cast(pBegin); + mpEnd = const_cast(pEnd); + mpCapacity = mpEnd; + return *this; + } + + + // Partially supported functionality + // + // When using fixed_substring on a character sequence that is within another + // string, the following functions may do one of two things: + // 1 Attempt to reallocate + // 2 Write a 0 char at the end of the fixed_substring + // + // Item #1 will result in a crash, due to the attempt by the underlying + // string class to free the substring memory. Item #2 will result in a 0 + // char being written to the character array. Item #2 may or may not be + // a problem, depending on how you use fixed_substring. Thus the following + // functions cannot be used safely. + + #if 0 // !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) We may want to enable these deletions after some investigation of possible user impact. + this_type& operator=(value_type c) = delete; + void resize(size_type n, value_type c) = delete; + void resize(size_type n) = delete; + void reserve(size_type = 0) = delete; + void set_capacity(size_type n) = delete; + void clear() = delete; + this_type& operator+=(const base_type& x) = delete; + this_type& operator+=(const value_type* p) = delete; + this_type& operator+=(value_type c) = delete; + this_type& append(const base_type& x) = delete; + this_type& append(const base_type& x, size_type position, size_type n) = delete; + this_type& append(const value_type* p, size_type n) = delete; + this_type& append(const value_type* p) = delete; + this_type& append(size_type n) = delete; + this_type& append(size_type n, value_type c) = delete; + this_type& append(const value_type* pBegin, const value_type* pEnd) = delete; + this_type& append_sprintf_va_list(const value_type* pFormat, va_list arguments) = delete; + this_type& append_sprintf(const value_type* pFormat, ...) = delete; + void push_back(value_type c) = delete; + void pop_back() = delete; + this_type& assign(size_type n, value_type c) = delete; + this_type& insert(size_type position, const base_type& x) = delete; + this_type& insert(size_type position, const base_type& x, size_type beg, size_type n) = delete; + this_type& insert(size_type position, const value_type* p, size_type n) = delete; + this_type& insert(size_type position, const value_type* p) = delete; + this_type& insert(size_type position, size_type n, value_type c) = delete; + iterator insert(const_iterator p, value_type c) = delete; + void insert(const_iterator p, size_type n, value_type c) = delete; + void insert(const_iterator p, const value_type* pBegin, const value_type* pEnd) = delete; + this_type& erase(size_type position = 0, size_type n = npos) = delete; + iterator erase(const_iterator p) = delete; + iterator erase(const_iterator pBegin, const_iterator pEnd) = delete; + void swap(base_type& x) = delete; + this_type& sprintf_va_list(const value_type* pFormat, va_list arguments) = delete; + this_type& sprintf(const value_type* pFormat, ...) = delete; + #endif + + }; // fixed_substring + + +} // namespace eastl + + + +#endif // Header include guard + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/fixed_vector.h b/libs/eastl/include/EASTL/fixed_vector.h new file mode 100644 index 0000000..de91f39 --- /dev/null +++ b/libs/eastl/include/EASTL/fixed_vector.h @@ -0,0 +1,644 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements a vector which uses a fixed size memory pool. +// The bEnableOverflow template parameter allows the container to resort to +// heap allocations if the memory pool is exhausted. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_FIXED_VECTOR_H +#define EASTL_FIXED_VECTOR_H + + +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + /// EASTL_FIXED_VECTOR_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// In the case of fixed-size containers, the allocator name always refers + /// to overflow allocations. + /// + #ifndef EASTL_FIXED_VECTOR_DEFAULT_NAME + #define EASTL_FIXED_VECTOR_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_vector" // Unless the user overrides something, this is "EASTL fixed_vector". + #endif + + + /// EASTL_FIXED_VECTOR_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_FIXED_VECTOR_DEFAULT_ALLOCATOR + #define EASTL_FIXED_VECTOR_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_VECTOR_DEFAULT_NAME) + #endif + + + /// fixed_vector + /// + /// A fixed_vector with bEnableOverflow == true is identical to a regular + /// vector in terms of its behavior. All the expectations of regular vector + /// apply to it and no additional expectations come from it. When bEnableOverflow + /// is false, fixed_vector behaves like regular vector with the exception that + /// its capacity can never increase. All operations you do on such a fixed_vector + /// which require a capacity increase will result in undefined behavior or an + /// C++ allocation exception, depending on the configuration of EASTL. + /// + /// Template parameters: + /// T The type of object the vector holds. + /// nodeCount The max number of objects to contain. + /// bEnableOverflow Whether or not we should use the overflow heap if our object pool is exhausted. + /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. + /// + /// Note: The nodeCount value must be at least 1. + /// + /// Example usage: + /// fixed_vector fixedVector); + /// + /// fixedVector.push_back(Widget()); + /// fixedVector.resize(200); + /// fixedVector.clear(); + /// + template ::type> + class fixed_vector : public vector > + { + public: + typedef fixed_vector_allocator fixed_allocator_type; + typedef OverflowAllocator overflow_allocator_type; + typedef vector base_type; + typedef fixed_vector this_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::reference reference; + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef aligned_buffer aligned_buffer_type; + + enum { kMaxSize = nodeCount }; + + using base_type::mAllocator; + using base_type::mpBegin; + using base_type::mpEnd; + using base_type::mpCapacity; + using base_type::resize; + using base_type::clear; + using base_type::size; + using base_type::assign; + using base_type::npos; + using base_type::DoAllocate; + using base_type::DoFree; + using base_type::DoAssign; + using base_type::DoAssignFromIterator; + + protected: + aligned_buffer_type mBuffer; + + public: + fixed_vector(); + explicit fixed_vector(const overflow_allocator_type& overflowAllocator); // Only applicable if bEnableOverflow is true. + explicit fixed_vector(size_type n); // Currently we don't support overflowAllocator specification for other constructors, for simplicity. + fixed_vector(size_type n, const value_type& value); + fixed_vector(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + fixed_vector(this_type&& x); + fixed_vector(this_type&& x, const overflow_allocator_type& overflowAllocator); + #endif + fixed_vector(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_VECTOR_DEFAULT_ALLOCATOR); + + template + fixed_vector(InputIterator first, InputIterator last); + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + void set_capacity(size_type n); + void clear(bool freeOverflow); + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + size_type max_size() const; // Returns the max fixed size, which is the user-supplied nodeCount parameter. + bool full() const; // Returns true if the fixed space has been fully allocated. Note that if overflow is enabled, the container size can be greater than nodeCount but full() could return true because the fixed space may have a recently freed slot. + bool has_overflowed() const; // Returns true if the allocations spilled over into the overflow allocator. Meaningful only if overflow is enabled. + bool can_overflow() const; // Returns the value of the bEnableOverflow template parameter. + + void* push_back_uninitialized(); + void push_back(const value_type& value); // We implement push_back here because we have a specialization that's + reference push_back(); // smaller for the case of overflow being disabled. + #if EASTL_MOVE_SEMANTICS_ENABLED + void push_back(value_type&& value); + #endif + + // OverflowAllocator + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT; + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT; + void set_overflow_allocator(const overflow_allocator_type& allocator); + + // Deprecated: + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + + protected: + void* DoPushBackUninitialized(true_type); + void* DoPushBackUninitialized(false_type); + + void DoPushBack(true_type, const value_type& value); + void DoPushBack(false_type, const value_type& value); + + #if EASTL_MOVE_SEMANTICS_ENABLED + void DoPushBackMove(true_type, value_type&& value); + void DoPushBackMove(false_type, value_type&& value); + #endif + + reference DoPushBack(false_type); + reference DoPushBack(true_type); + + }; // fixed_vector + + + + + /////////////////////////////////////////////////////////////////////// + // fixed_vector + /////////////////////////////////////////////////////////////////////// + + template + inline fixed_vector::fixed_vector() + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME); + #endif + + mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0]; + mpCapacity = mpBegin + nodeCount; + } + + template + inline fixed_vector::fixed_vector(const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME); + #endif + + mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0]; + mpCapacity = mpBegin + nodeCount; + } + + template + inline fixed_vector::fixed_vector(size_type n) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME); + #endif + + mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0]; + mpCapacity = mpBegin + nodeCount; + resize(n); + } + + + template + inline fixed_vector::fixed_vector(size_type n, const value_type& value) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME); + #endif + + mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0]; + mpCapacity = mpBegin + nodeCount; + resize(n, value); + } + + + template + inline fixed_vector::fixed_vector(const this_type& x) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0]; + mpCapacity = mpBegin + nodeCount; + base_type::template DoAssign(x.begin(), x.end(), false_type()); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline fixed_vector::fixed_vector(this_type&& x) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + // Since we are a fixed_vector, we can't swap pointers. We can possibly so something like fixed_swap or + // we can just do an assignment from x. If we want to do the former then we need to have some complicated + // code to deal with overflow or no overflow, and whether the memory is in the fixed-size buffer or in + // the overflow allocator. 90% of the time the memory should be in the fixed buffer, in which case + // a simple assignment is no worse than the fancy pathway. + + // Since we are a fixed_list, we can't normally swap pointers unless both this and + // x are using using overflow and the overflow allocators are equal. To do: + //if(has_overflowed() && x.has_overflowed() && (get_overflow_allocator() == x.get_overflow_allocator())) + //{ + // We can swap contents and may need to swap the allocators as well. + //} + + // The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that + // way then we may want to make a shared implementation. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0]; + mpCapacity = mpBegin + nodeCount; + base_type::template DoAssign(x.begin(), x.end(), false_type()); + } + + + template + inline fixed_vector::fixed_vector(this_type&& x, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator)) + { + // See the discussion above. + + // The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that + // way then we may want to make a shared implementation. + mAllocator.copy_overflow_allocator(x.mAllocator); + + #if EASTL_NAME_ENABLED + mAllocator.set_name(x.mAllocator.get_name()); + #endif + + mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0]; + mpCapacity = mpBegin + nodeCount; + base_type::template DoAssign(x.begin(), x.end(), false_type()); + } + #endif + + + template + inline fixed_vector::fixed_vector(std::initializer_list ilist, const overflow_allocator_type& overflowAllocator) + : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator)) + { + typedef typename std::initializer_list::iterator InputIterator; + typedef typename eastl::iterator_traits::iterator_category IC; + + mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0]; + mpCapacity = mpBegin + nodeCount; + base_type::template DoAssignFromIterator(ilist.begin(), ilist.end(), IC()); + } + + + template + template + fixed_vector::fixed_vector(InputIterator first, InputIterator last) + : base_type(fixed_allocator_type(mBuffer.buffer)) + { + #if EASTL_NAME_ENABLED + mAllocator.set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME); + #endif + + mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0]; + mpCapacity = mpBegin + nodeCount; + base_type::template DoAssign(first, last, is_integral()); + } + + + template + inline typename fixed_vector::this_type& + fixed_vector::operator=(const this_type& x) + { + if(this != &x) + { + clear(); + + #if EASTL_ALLOCATOR_COPY_ENABLED + mAllocator = x.mAllocator; // The primary effect of this is to copy the overflow allocator. + #endif + + base_type::template DoAssign(x.begin(), x.end(), false_type()); // Shorter route. + } + return *this; + } + + + template + inline typename fixed_vector::this_type& + fixed_vector::operator=(std::initializer_list ilist) + { + typedef typename std::initializer_list::iterator InputIterator; + typedef typename eastl::iterator_traits::iterator_category IC; + + clear(); + base_type::template DoAssignFromIterator(ilist.begin(), ilist.end(), IC()); + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename fixed_vector::this_type& + fixed_vector::operator=(this_type&& x) + { + // Since we are a fixed_vector, we can't swap pointers. We can possibly so something like fixed_swap or + // we can just do an assignment from x. If we want to do the former then we need to have some complicated + // code to deal with overflow or no overflow, and whether the memory is in the fixed-size buffer or in + // the overflow allocator. 90% of the time the memory should be in the fixed buffer, in which case + // a simple assignment is no worse than the fancy pathway. + return operator=(x); + } + #endif + + + template + inline void fixed_vector::swap(this_type& x) + { + if((has_overflowed() && x.has_overflowed()) && (get_overflow_allocator() == x.get_overflow_allocator())) // If both containers are using the heap instead of local memory + { // then we can do a fast pointer swap instead of content swap. + eastl::swap(mpBegin, x.mpBegin); + eastl::swap(mpEnd, x.mpEnd); + eastl::swap(mpCapacity, x.mpCapacity); + } + else + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(*this, x); + } + } + + + template + inline void fixed_vector::set_capacity(size_type n) + { + const size_type nPrevSize = (size_type)(mpEnd - mpBegin); + const size_type nPrevCapacity = (size_type)(mpCapacity - mpBegin); + + if(n == npos) // If the user means to set the capacity so that it equals the size (i.e. free excess capacity)... + n = nPrevSize; + + if(n != nPrevCapacity) // If the request results in a capacity change... + { + if(can_overflow() && (((uintptr_t)mpBegin != (uintptr_t)mBuffer.buffer) || (n > kMaxSize))) // If we are or would be using dynamically allocated memory instead of our fixed-size member buffer... + { + T* const pNewData = (n <= kMaxSize) ? (T*)&mBuffer.buffer[0] : DoAllocate(n); + T* const pCopyEnd = (n < nPrevSize) ? (mpBegin + n) : mpEnd; + eastl::uninitialized_move_ptr(mpBegin, pCopyEnd, pNewData); // Move [mpBegin, pCopyEnd) to p. + eastl::destruct(mpBegin, mpEnd); + if((uintptr_t)mpBegin != (uintptr_t)mBuffer.buffer) + DoFree(mpBegin, (size_type)(mpCapacity - mpBegin)); + + mpEnd = pNewData + (pCopyEnd - mpBegin); + mpBegin = pNewData; + mpCapacity = mpBegin + n; + } // Else the new capacity would be within our fixed buffer. + else if(n < nPrevSize) // If the newly requested capacity is less than our size, we do what vector::set_capacity does and resize, even though we actually aren't reducing the capacity. + resize(n); + } + } + + + template + inline void fixed_vector::clear(bool freeOverflow) + { + base_type::clear(); + if (freeOverflow && mpBegin != (value_type*)&mBuffer.buffer[0]) + { + EASTLFree(mAllocator, mpBegin, (mpCapacity - mpBegin) * sizeof(T)); + mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0]; + mpCapacity = mpBegin + nodeCount; + } + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void fixed_vector::reset() + { + reset_lose_memory(); + } + #endif + + + template + inline void fixed_vector::reset_lose_memory() + { + mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0]; + mpCapacity = mpBegin + nodeCount; + } + + + template + inline typename fixed_vector::size_type + fixed_vector::max_size() const + { + return kMaxSize; + } + + + template + inline bool fixed_vector::full() const + { + // If size >= capacity, then we are definitely full. + // Also, if our size is smaller but we've switched away from mBuffer due to a previous overflow, then we are considered full. + return ((size_t)(mpEnd - mpBegin) >= kMaxSize) || ((void*)mpBegin != (void*)mBuffer.buffer); + } + + + template + inline bool fixed_vector::has_overflowed() const + { + // This will be incorrect for the case that bOverflowEnabled is true and the container was resized + // down to a small size where the fixed buffer could take over ownership of the data again. + // The only simple fix for this is to take on another member variable which tracks whether this overflow + // has occurred at some point in the past. + return ((void*)mpBegin != (void*)mBuffer.buffer); + } + + + template + inline bool fixed_vector::can_overflow() const + { + return bEnableOverflow; + } + + + template + inline void* fixed_vector::push_back_uninitialized() + { + return DoPushBackUninitialized(typename type_select::type()); + } + + + template + inline void* fixed_vector::DoPushBackUninitialized(true_type) + { + return base_type::push_back_uninitialized(); + } + + + template + inline void* fixed_vector::DoPushBackUninitialized(false_type) + { + EASTL_ASSERT(mpEnd < mpCapacity); + + return mpEnd++; + } + + + template + inline void fixed_vector::push_back(const value_type& value) + { + DoPushBack(typename type_select::type(), value); + } + + + template + inline void fixed_vector::DoPushBack(true_type, const value_type& value) + { + base_type::push_back(value); + } + + + // This template specializes for overflow NOT enabled. + // In this configuration, there is no need for the heavy weight push_back() which tests to see if the container should grow (it never will) + template + inline void fixed_vector::DoPushBack(false_type, const value_type& value) + { + EASTL_ASSERT(mpEnd < mpCapacity); + + ::new((void*)mpEnd++) value_type(value); + } + + + template + inline typename fixed_vector::reference fixed_vector::push_back() + { + return DoPushBack(typename type_select::type()); + } + + + template + inline typename fixed_vector::reference fixed_vector::DoPushBack(true_type) + { + return base_type::push_back(); + } + + + // This template specializes for overflow NOT enabled. + // In this configuration, there is no need for the heavy weight push_back() which tests to see if the container should grow (it never will) + template + inline typename fixed_vector::reference fixed_vector::DoPushBack(false_type) + { + EASTL_ASSERT(mpEnd < mpCapacity); + + ::new((void*)mpEnd++) value_type; // Note that this isn't value_type() as that syntax doesn't work on all compilers for POD types. + + return *(mpEnd - 1); // Same as return back(); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline void fixed_vector::push_back(value_type&& value) + { + DoPushBackMove(typename type_select::type(), eastl::move(value)); + } + + + template + inline void fixed_vector::DoPushBackMove(true_type, value_type&& value) + { + base_type::push_back(eastl::move(value)); // This will call vector::push_back(value_type &&), and possibly swap value with *mpEnd. + } + + + // This template specializes for overflow NOT enabled. + // In this configuration, there is no need for the heavy weight push_back() which tests to see if the container should grow (it never will) + template + inline void fixed_vector::DoPushBackMove(false_type, value_type&& value) + { + EASTL_ASSERT(mpEnd < mpCapacity); + + ::new((void*)mpEnd++) value_type(eastl::move(value)); // This will call the value_type(value_type&&) constructor, and possibly swap value with *mpEnd. + } + #endif + + + template + inline const typename fixed_vector::overflow_allocator_type& + fixed_vector::get_overflow_allocator() const EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline typename fixed_vector::overflow_allocator_type& + fixed_vector::get_overflow_allocator() EA_NOEXCEPT + { + return mAllocator.get_overflow_allocator(); + } + + + template + inline void + fixed_vector::set_overflow_allocator(const overflow_allocator_type& allocator) + { + mAllocator.set_overflow_allocator(allocator); + } + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + // operator ==, !=, <, >, <=, >= come from the vector implementations. + + template + inline void swap(fixed_vector& a, + fixed_vector& b) + { + // Fixed containers use a special swap that can deal with excessively large buffers. + eastl::fixed_swap(a, b); + } + + + +} // namespace eastl + + + +#endif // Header include guard + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/functional.h b/libs/eastl/include/EASTL/functional.h new file mode 100644 index 0000000..da9ac14 --- /dev/null +++ b/libs/eastl/include/EASTL/functional.h @@ -0,0 +1,1140 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_FUNCTIONAL_H +#define EASTL_FUNCTIONAL_H + + +#include +#include +#include +#include +#include +#include + + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + /////////////////////////////////////////////////////////////////////// + // Primary C++ functions + /////////////////////////////////////////////////////////////////////// + + template + struct plus : public binary_function + { + EA_CPP14_CONSTEXPR T operator()(const T& a, const T& b) const + { return a + b; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/plus_void + template <> + struct plus + { + typedef int is_transparent; + template + EA_CPP14_CONSTEXPR auto operator()(A&& a, B&& b) const + -> decltype(eastl::forward(a) + eastl::forward(b)) + { return eastl::forward(a) + eastl::forward(b); } + }; + + template + struct minus : public binary_function + { + EA_CPP14_CONSTEXPR T operator()(const T& a, const T& b) const + { return a - b; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/minus_void + template <> + struct minus + { + typedef int is_transparent; + template + EA_CPP14_CONSTEXPR auto operator()(A&& a, B&& b) const + -> decltype(eastl::forward(a) - eastl::forward(b)) + { return eastl::forward(a) - eastl::forward(b); } + }; + + template + struct multiplies : public binary_function + { + EA_CPP14_CONSTEXPR T operator()(const T& a, const T& b) const + { return a * b; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/multiplies_void + template <> + struct multiplies + { + typedef int is_transparent; + template + EA_CPP14_CONSTEXPR auto operator()(A&& a, B&& b) const + -> decltype(eastl::forward(a) * eastl::forward(b)) + { return eastl::forward(a) * eastl::forward(b); } + }; + + template + struct divides : public binary_function + { + EA_CPP14_CONSTEXPR T operator()(const T& a, const T& b) const + { return a / b; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/divides_void + template <> + struct divides + { + typedef int is_transparent; + template + EA_CPP14_CONSTEXPR auto operator()(A&& a, B&& b) const + -> decltype(eastl::forward(a) / eastl::forward(b)) + { return eastl::forward(a) / eastl::forward(b); } + }; + + template + struct modulus : public binary_function + { + EA_CPP14_CONSTEXPR T operator()(const T& a, const T& b) const + { return a % b; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/modulus_void + template <> + struct modulus + { + typedef int is_transparent; + template + EA_CPP14_CONSTEXPR auto operator()(A&& a, B&& b) const + -> decltype(eastl::forward(a) % eastl::forward(b)) + { return eastl::forward(a) % eastl::forward(b); } + }; + + template + struct negate : public unary_function + { + EA_CPP14_CONSTEXPR T operator()(const T& a) const + { return -a; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/negate_void + template <> + struct negate + { + typedef int is_transparent; + template + EA_CPP14_CONSTEXPR auto operator()(T&& t) const + -> decltype(-eastl::forward(t)) + { return -eastl::forward(t); } + }; + + template + struct equal_to : public binary_function + { + EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const + { return a == b; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/equal_to_void + template <> + struct equal_to + { + typedef int is_transparent; + template + EA_CPP14_CONSTEXPR auto operator()(A&& a, B&& b) const + -> decltype(eastl::forward(a) == eastl::forward(b)) + { return eastl::forward(a) == eastl::forward(b); } + }; + + template + bool validate_equal_to(const T& a, const T& b, Compare compare) + { + return compare(a, b) == compare(b, a); + } + + template + struct not_equal_to : public binary_function + { + EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const + { return a != b; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/not_equal_to_void + template <> + struct not_equal_to + { + typedef int is_transparent; + template + EA_CPP14_CONSTEXPR auto operator()(A&& a, B&& b) const + -> decltype(eastl::forward(a) != eastl::forward(b)) + { return eastl::forward(a) != eastl::forward(b); } + }; + + template + bool validate_not_equal_to(const T& a, const T& b, Compare compare) + { + return compare(a, b) == compare(b, a); // We want the not equal comparison results to be equal. + } + + /// str_equal_to + /// + /// Compares two 0-terminated string types. + /// The T types are expected to be iterators or act like iterators. + /// The expected behavior of str_less is the same as (strcmp(p1, p2) == 0). + /// + /// Example usage: + /// hash_set, str_equal_to > stringHashSet; + /// + /// Note: + /// You couldn't use str_equal_to like this: + /// bool result = equal("hi", "hi" + 2, "ho", str_equal_to()); + /// This is because equal tests an array of something, with each element by + /// the comparison function. But str_equal_to tests an array of something itself. + /// + /// To consider: Update this code to use existing word-based comparison optimizations, + /// such as that used in the EAStdC Strcmp function. + /// + template + struct str_equal_to : public binary_function + { + EA_CPP14_CONSTEXPR bool operator()(T a, T b) const + { + while(*a && (*a == *b)) + { + ++a; + ++b; + } + return (*a == *b); + } + }; + + template + struct greater : public binary_function + { + EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const + { return a > b; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/greater_void + template <> + struct greater + { + template + EA_CPP14_CONSTEXPR auto operator()(A&& a, B&& b) const + -> decltype(eastl::forward(a) > eastl::forward(b)) + { return eastl::forward(a) > eastl::forward(b); } + }; + + template + bool validate_greater(const T& a, const T& b, Compare compare) + { + return !compare(a, b) || !compare(b, a); // If (a > b), then !(b > a) + } + + + template + bool validate_less(const T& a, const T& b, Compare compare) + { + return !compare(a, b) || !compare(b, a); // If (a < b), then !(b < a) + } + + /// str_less + /// + /// Compares two 0-terminated string types. + /// The T types are expected to be iterators or act like iterators, + /// and that includes being a pointer to a C character array. + /// The expected behavior of str_less is the same as (strcmp(p1, p2) < 0). + /// This function is not Unicode-correct and it's not guaranteed to work + /// with all Unicode strings. + /// + /// Example usage: + /// set > stringSet; + /// + /// To consider: Update this code to use existing word-based comparison optimizations, + /// such as that used in the EAStdC Strcmp function. + /// + template + struct str_less : public binary_function + { + bool operator()(T a, T b) const + { + while(static_cast::type>::type>(*a) == + static_cast::type>::type>(*b)) + { + if(*a == 0) + return (*b != 0); + ++a; + ++b; + } + + char aValue = static_cast::type>(*a); + char bValue = static_cast::type>(*b); + + typename make_unsigned::type aValueU = static_cast::type>(aValue); + typename make_unsigned::type bValueU = static_cast::type>(bValue); + + return aValueU < bValueU; + + //return (static_cast::type>::type>(*a) < + // static_cast::type>::type>(*b)); + } + }; + + template + struct greater_equal : public binary_function + { + EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const + { return a >= b; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/greater_equal_void + template <> + struct greater_equal + { + template + EA_CPP14_CONSTEXPR auto operator()(A&& a, B&& b) const + -> decltype(eastl::forward(a) >= eastl::forward(b)) + { return eastl::forward(a) >= eastl::forward(b); } + }; + + template + bool validate_greater_equal(const T& a, const T& b, Compare compare) + { + return !compare(a, b) || !compare(b, a); // If (a >= b), then !(b >= a) + } + + template + struct less_equal : public binary_function + { + EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const + { return a <= b; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/less_equal_void + template <> + struct less_equal + { + template + EA_CPP14_CONSTEXPR auto operator()(A&& a, B&& b) const + -> decltype(eastl::forward(a) <= eastl::forward(b)) + { return eastl::forward(a) <= eastl::forward(b); } + }; + + template + bool validate_less_equal(const T& a, const T& b, Compare compare) + { + return !compare(a, b) || !compare(b, a); // If (a <= b), then !(b <= a) + } + + template + struct logical_and : public binary_function + { + EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const + { return a && b; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/logical_and_void + template <> + struct logical_and + { + template + EA_CPP14_CONSTEXPR auto operator()(A&& a, B&& b) const + -> decltype(eastl::forward(a) && eastl::forward(b)) + { return eastl::forward(a) && eastl::forward(b); } + }; + + template + struct logical_or : public binary_function + { + EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const + { return a || b; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/logical_or_void + template <> + struct logical_or + { + template + EA_CPP14_CONSTEXPR auto operator()(A&& a, B&& b) const + -> decltype(eastl::forward(a) || eastl::forward(b)) + { return eastl::forward(a) || eastl::forward(b); } + }; + + template + struct logical_not : public unary_function + { + EA_CPP14_CONSTEXPR bool operator()(const T& a) const + { return !a; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/logical_not_void + template <> + struct logical_not + { + template + EA_CPP14_CONSTEXPR auto operator()(T&& t) const + -> decltype(!eastl::forward(t)) + { return !eastl::forward(t); } + }; + + + + /////////////////////////////////////////////////////////////////////// + // Dual type functions + /////////////////////////////////////////////////////////////////////// + + template + struct equal_to_2 : public binary_function + { + EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const + { return a == b; } + EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const // If you are getting a 'operator() already defined' error related to on this line while compiling a + { return b == a; } // hashtable class (e.g. hash_map), it's likely that you are using hashtable::find_as when you should + }; // be using hashtable::find instead. The problem is that (const T, U) collide. To do: make this work. + + template + struct equal_to_2 : public equal_to + { + }; + + + template + struct not_equal_to_2 : public binary_function + { + EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const + { return a != b; } + EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const + { return b != a; } + }; + + template + struct not_equal_to_2 : public not_equal_to + { + }; + + + template + struct less_2 : public binary_function + { + EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const + { return a < b; } + EA_CPP14_CONSTEXPR bool operator()(const U& b, const T& a) const + { return b < a; } + }; + + template + struct less_2 : public less + { + }; + + + + + /// unary_negate + /// + template + class unary_negate : public unary_function + { + protected: + Predicate mPredicate; + public: + explicit unary_negate(const Predicate& a) + : mPredicate(a) {} + EA_CPP14_CONSTEXPR bool operator()(const typename Predicate::argument_type& a) const + { return !mPredicate(a); } + }; + + template + inline EA_CPP14_CONSTEXPR unary_negate not1(const Predicate& predicate) + { return unary_negate(predicate); } + + + + /// binary_negate + /// + template + class binary_negate : public binary_function + { + protected: + Predicate mPredicate; + public: + explicit binary_negate(const Predicate& a) + : mPredicate(a) { } + EA_CPP14_CONSTEXPR bool operator()(const typename Predicate::first_argument_type& a, const typename Predicate::second_argument_type& b) const + { return !mPredicate(a, b); } + }; + + template + inline EA_CPP14_CONSTEXPR binary_negate not2(const Predicate& predicate) + { return binary_negate(predicate); } + + + + /// unary_compose + /// + template + struct unary_compose : public unary_function + { + protected: + Operation1 op1; + Operation2 op2; + + public: + unary_compose(const Operation1& x, const Operation2& y) + : op1(x), op2(y) {} + + typename Operation1::result_type operator()(const typename Operation2::argument_type& x) const + { return op1(op2(x)); } + + typename Operation1::result_type operator()(typename Operation2::argument_type& x) const + { return op1(op2(x)); } + }; + + template + inline unary_compose + compose1(const Operation1& op1, const Operation2& op2) + { + return unary_compose(op1,op2); + } + + + /// binary_compose + /// + template + class binary_compose : public unary_function + { + protected: + Operation1 op1; + Operation2 op2; + Operation3 op3; + + public: + // Support binary functors too. + typedef typename Operation2::argument_type first_argument_type; + typedef typename Operation3::argument_type second_argument_type; + + binary_compose(const Operation1& x, const Operation2& y, const Operation3& z) + : op1(x), op2(y), op3(z) { } + + typename Operation1::result_type operator()(const typename Operation2::argument_type& x) const + { return op1(op2(x),op3(x)); } + + typename Operation1::result_type operator()(typename Operation2::argument_type& x) const + { return op1(op2(x),op3(x)); } + + typename Operation1::result_type operator()(const typename Operation2::argument_type& x,const typename Operation3::argument_type& y) const + { return op1(op2(x),op3(y)); } + + typename Operation1::result_type operator()(typename Operation2::argument_type& x, typename Operation3::argument_type& y) const + { return op1(op2(x),op3(y)); } + }; + + + template + inline binary_compose + compose2(const Operation1& op1, const Operation2& op2, const Operation3& op3) + { + return binary_compose(op1, op2, op3); + } + + + + /////////////////////////////////////////////////////////////////////// + // pointer_to_unary_function + /////////////////////////////////////////////////////////////////////// + + /// pointer_to_unary_function + /// + /// This is an adapter template which converts a pointer to a standalone + /// function to a function object. This allows standalone functions to + /// work in many cases where the system requires a function object. + /// + /// Example usage: + /// ptrdiff_t Rand(ptrdiff_t n) { return rand() % n; } // Note: The C rand function is poor and slow. + /// pointer_to_unary_function randInstance(Rand); + /// random_shuffle(pArrayBegin, pArrayEnd, randInstance); + /// + template + class pointer_to_unary_function : public unary_function + { + protected: + Result (*mpFunction)(Arg); + + public: + pointer_to_unary_function() + { } + + explicit pointer_to_unary_function(Result (*pFunction)(Arg)) + : mpFunction(pFunction) { } + + Result operator()(Arg x) const + { return mpFunction(x); } + }; + + + /// ptr_fun + /// + /// This ptr_fun is simply shorthand for usage of pointer_to_unary_function. + /// + /// Example usage (actually, you don't need to use ptr_fun here, but it works anyway): + /// int factorial(int x) { return (x > 1) ? (x * factorial(x - 1)) : x; } + /// transform(pIntArrayBegin, pIntArrayEnd, pIntArrayBegin, ptr_fun(factorial)); + /// + template + inline pointer_to_unary_function + ptr_fun(Result (*pFunction)(Arg)) + { return pointer_to_unary_function(pFunction); } + + + + + + /////////////////////////////////////////////////////////////////////// + // pointer_to_binary_function + /////////////////////////////////////////////////////////////////////// + + /// pointer_to_binary_function + /// + /// This is an adapter template which converts a pointer to a standalone + /// function to a function object. This allows standalone functions to + /// work in many cases where the system requires a function object. + /// + template + class pointer_to_binary_function : public binary_function + { + protected: + Result (*mpFunction)(Arg1, Arg2); + + public: + pointer_to_binary_function() + { } + + explicit pointer_to_binary_function(Result (*pFunction)(Arg1, Arg2)) + : mpFunction(pFunction) {} + + Result operator()(Arg1 x, Arg2 y) const + { return mpFunction(x, y); } + }; + + + /// This ptr_fun is simply shorthand for usage of pointer_to_binary_function. + /// + /// Example usage (actually, you don't need to use ptr_fun here, but it works anyway): + /// int multiply(int x, int y) { return x * y; } + /// transform(pIntArray1Begin, pIntArray1End, pIntArray2Begin, pIntArray1Begin, ptr_fun(multiply)); + /// + template + inline pointer_to_binary_function + ptr_fun(Result (*pFunction)(Arg1, Arg2)) + { return pointer_to_binary_function(pFunction); } + + + + + + + /////////////////////////////////////////////////////////////////////// + // mem_fun + // mem_fun1 + // + // Note that mem_fun calls member functions via *pointers* to classes + // and not instances of classes. mem_fun_ref is for calling functions + // via instances of classes or references to classes. + // + // NOTE: + // mem_fun was deprecated in C++11 and removed in C++17, in favor + // of the more general mem_fn and bind. + // + /////////////////////////////////////////////////////////////////////// + + /// mem_fun_t + /// + /// Member function with no arguments. + /// + template + class mem_fun_t : public unary_function + { + public: + typedef Result (T::*MemberFunction)(); + + inline explicit mem_fun_t(MemberFunction pMemberFunction) + : mpMemberFunction(pMemberFunction) + { + // Empty + } + + inline Result operator()(T* pT) const + { + return (pT->*mpMemberFunction)(); + } + + protected: + MemberFunction mpMemberFunction; + }; + + + /// mem_fun1_t + /// + /// Member function with one argument. + /// + template + class mem_fun1_t : public binary_function + { + public: + typedef Result (T::*MemberFunction)(Argument); + + inline explicit mem_fun1_t(MemberFunction pMemberFunction) + : mpMemberFunction(pMemberFunction) + { + // Empty + } + + inline Result operator()(T* pT, Argument arg) const + { + return (pT->*mpMemberFunction)(arg); + } + + protected: + MemberFunction mpMemberFunction; + }; + + + /// const_mem_fun_t + /// + /// Const member function with no arguments. + /// Note that we inherit from unary_function + /// instead of what the C++ standard specifies: unary_function. + /// The C++ standard is in error and this has been recognized by the defect group. + /// + template + class const_mem_fun_t : public unary_function + { + public: + typedef Result (T::*MemberFunction)() const; + + inline explicit const_mem_fun_t(MemberFunction pMemberFunction) + : mpMemberFunction(pMemberFunction) + { + // Empty + } + + inline Result operator()(const T* pT) const + { + return (pT->*mpMemberFunction)(); + } + + protected: + MemberFunction mpMemberFunction; + }; + + + /// const_mem_fun1_t + /// + /// Const member function with one argument. + /// Note that we inherit from unary_function + /// instead of what the C++ standard specifies: unary_function. + /// The C++ standard is in error and this has been recognized by the defect group. + /// + template + class const_mem_fun1_t : public binary_function + { + public: + typedef Result (T::*MemberFunction)(Argument) const; + + inline explicit const_mem_fun1_t(MemberFunction pMemberFunction) + : mpMemberFunction(pMemberFunction) + { + // Empty + } + + inline Result operator()(const T* pT, Argument arg) const + { + return (pT->*mpMemberFunction)(arg); + } + + protected: + MemberFunction mpMemberFunction; + }; + + + /// mem_fun + /// + /// This is the high level interface to the mem_fun_t family. + /// + /// Example usage: + /// struct TestClass { void print() { puts("hello"); } } + /// TestClass* pTestClassArray[3] = { ... }; + /// for_each(pTestClassArray, pTestClassArray + 3, &TestClass::print); + /// + /// Note: using conventional inlining here to avoid issues on GCC/Linux + /// + template + inline mem_fun_t + mem_fun(Result (T::*MemberFunction)()) + { + return eastl::mem_fun_t(MemberFunction); + } + + template + inline mem_fun1_t + mem_fun(Result (T::*MemberFunction)(Argument)) + { + return eastl::mem_fun1_t(MemberFunction); + } + + template + inline const_mem_fun_t + mem_fun(Result (T::*MemberFunction)() const) + { + return eastl::const_mem_fun_t(MemberFunction); + } + + template + inline const_mem_fun1_t + mem_fun(Result (T::*MemberFunction)(Argument) const) + { + return eastl::const_mem_fun1_t(MemberFunction); + } + + + + + + /////////////////////////////////////////////////////////////////////// + // mem_fun_ref + // mem_fun1_ref + // + /////////////////////////////////////////////////////////////////////// + + /// mem_fun_ref_t + /// + template + class mem_fun_ref_t : public unary_function + { + public: + typedef Result (T::*MemberFunction)(); + + inline explicit mem_fun_ref_t(MemberFunction pMemberFunction) + : mpMemberFunction(pMemberFunction) + { + // Empty + } + + inline Result operator()(T& t) const + { + return (t.*mpMemberFunction)(); + } + + protected: + MemberFunction mpMemberFunction; + }; + + + /// mem_fun1_ref_t + /// + template + class mem_fun1_ref_t : public binary_function + { + public: + typedef Result (T::*MemberFunction)(Argument); + + inline explicit mem_fun1_ref_t(MemberFunction pMemberFunction) + : mpMemberFunction(pMemberFunction) + { + // Empty + } + + inline Result operator()(T& t, Argument arg) const + { + return (t.*mpMemberFunction)(arg); + } + + protected: + MemberFunction mpMemberFunction; + }; + + + /// const_mem_fun_ref_t + /// + template + class const_mem_fun_ref_t : public unary_function + { + public: + typedef Result (T::*MemberFunction)() const; + + inline explicit const_mem_fun_ref_t(MemberFunction pMemberFunction) + : mpMemberFunction(pMemberFunction) + { + // Empty + } + + inline Result operator()(const T& t) const + { + return (t.*mpMemberFunction)(); + } + + protected: + MemberFunction mpMemberFunction; + }; + + + /// const_mem_fun1_ref_t + /// + template + class const_mem_fun1_ref_t : public binary_function + { + public: + typedef Result (T::*MemberFunction)(Argument) const; + + inline explicit const_mem_fun1_ref_t(MemberFunction pMemberFunction) + : mpMemberFunction(pMemberFunction) + { + // Empty + } + + inline Result operator()(const T& t, Argument arg) const + { + return (t.*mpMemberFunction)(arg); + } + + protected: + MemberFunction mpMemberFunction; + }; + + + /// mem_fun_ref + /// Example usage: + /// struct TestClass { void print() { puts("hello"); } } + /// TestClass testClassArray[3]; + /// for_each(testClassArray, testClassArray + 3, &TestClass::print); + /// + /// Note: using conventional inlining here to avoid issues on GCC/Linux + /// + template + inline mem_fun_ref_t + mem_fun_ref(Result (T::*MemberFunction)()) + { + return eastl::mem_fun_ref_t(MemberFunction); + } + + template + inline mem_fun1_ref_t + mem_fun_ref(Result (T::*MemberFunction)(Argument)) + { + return eastl::mem_fun1_ref_t(MemberFunction); + } + + template + inline const_mem_fun_ref_t + mem_fun_ref(Result (T::*MemberFunction)() const) + { + return eastl::const_mem_fun_ref_t(MemberFunction); + } + + template + inline const_mem_fun1_ref_t + mem_fun_ref(Result (T::*MemberFunction)(Argument) const) + { + return eastl::const_mem_fun1_ref_t(MemberFunction); + } + + + + + /////////////////////////////////////////////////////////////////////// + // hash + /////////////////////////////////////////////////////////////////////// + + template struct hash; + + template struct hash // Note that we use the pointer as-is and don't divide by sizeof(T*). This is because the table is of a prime size and this division doesn't benefit distribution. + { size_t operator()(T* p) const { return size_t(uintptr_t(p)); } }; + + template <> struct hash + { size_t operator()(bool val) const { return static_cast(val); } }; + + template <> struct hash + { size_t operator()(char val) const { return static_cast(val); } }; + + template <> struct hash + { size_t operator()(signed char val) const { return static_cast(val); } }; + + template <> struct hash + { size_t operator()(unsigned char val) const { return static_cast(val); } }; + + #if defined(EA_CHAR16_NATIVE) && EA_CHAR16_NATIVE + template <> struct hash + { size_t operator()(char16_t val) const { return static_cast(val); } }; + #endif + + #if defined(EA_CHAR32_NATIVE) && EA_CHAR32_NATIVE + template <> struct hash + { size_t operator()(char32_t val) const { return static_cast(val); } }; + #endif + + // If wchar_t is a native type instead of simply a define to an existing type... + #if !defined(EA_WCHAR_T_NON_NATIVE) + template <> struct hash + { size_t operator()(wchar_t val) const { return static_cast(val); } }; + #endif + + template <> struct hash + { size_t operator()(signed short val) const { return static_cast(val); } }; + + template <> struct hash + { size_t operator()(unsigned short val) const { return static_cast(val); } }; + + template <> struct hash + { size_t operator()(signed int val) const { return static_cast(val); } }; + + template <> struct hash + { size_t operator()(unsigned int val) const { return static_cast(val); } }; + + template <> struct hash + { size_t operator()(signed long val) const { return static_cast(val); } }; + + template <> struct hash + { size_t operator()(unsigned long val) const { return static_cast(val); } }; + + template <> struct hash + { size_t operator()(signed long long val) const { return static_cast(val); } }; + + template <> struct hash + { size_t operator()(unsigned long long val) const { return static_cast(val); } }; + + template <> struct hash + { size_t operator()(float val) const { return static_cast(val); } }; + + template <> struct hash + { size_t operator()(double val) const { return static_cast(val); } }; + + template <> struct hash + { size_t operator()(long double val) const { return static_cast(val); } }; + + + /////////////////////////////////////////////////////////////////////////// + // string hashes + // + // Note that our string hashes here intentionally are slow for long strings. + // The reasoning for this is so: + // - The large majority of hashed strings are only a few bytes long. + // - The hash function is significantly more efficient if it can make this assumption. + // - The user is welcome to make a custom hash for those uncommon cases where + // long strings need to be hashed. Indeed, the user can probably make a + // special hash customized for such strings that's better than what we provide. + /////////////////////////////////////////////////////////////////////////// + + template <> struct hash + { + size_t operator()(const char8_t* p) const + { + uint32_t c, result = 2166136261U; // FNV1 hash. Perhaps the best string hash. Intentionally uint32_t instead of size_t, so the behavior is the same regardless of size. + while((c = (uint8_t)*p++) != 0) // Using '!=' disables compiler warnings. + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + + template <> struct hash + { + size_t operator()(const char8_t* p) const + { + uint32_t c, result = 2166136261U; // Intentionally uint32_t instead of size_t, so the behavior is the same regardless of size. + while((c = (uint8_t)*p++) != 0) // cast to unsigned 8 bit. + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + + template <> struct hash + { + size_t operator()(const char16_t* p) const + { + uint32_t c, result = 2166136261U; // Intentionally uint32_t instead of size_t, so the behavior is the same regardless of size. + while((c = (uint16_t)*p++) != 0) // cast to unsigned 16 bit. + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + + template <> struct hash + { + size_t operator()(const char16_t* p) const + { + uint32_t c, result = 2166136261U; // Intentionally uint32_t instead of size_t, so the behavior is the same regardless of size. + while((c = (uint16_t)*p++) != 0) // cast to unsigned 16 bit. + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + + template <> struct hash + { + size_t operator()(const char32_t* p) const + { + uint32_t c, result = 2166136261U; // Intentionally uint32_t instead of size_t, so the behavior is the same regardless of size. + while((c = (uint32_t)*p++) != 0) // cast to unsigned 32 bit. + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + + template <> struct hash + { + size_t operator()(const char32_t* p) const + { + uint32_t c, result = 2166136261U; // Intentionally uint32_t instead of size_t, so the behavior is the same regardless of size. + while((c = (uint32_t)*p++) != 0) // cast to unsigned 32 bit. + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + + /// string_hash + /// + /// Defines a generic string hash for an arbitrary EASTL basic_string container. + /// + /// Example usage: + /// eastl::hash_set > hashSet; + /// + template + struct string_hash + { + typedef String string_type; + typedef typename String::value_type value_type; + typedef typename eastl::add_unsigned::type unsigned_value_type; + + size_t operator()(const string_type& s) const + { + const unsigned_value_type* p = (const unsigned_value_type*)s.c_str(); + uint32_t c, result = 2166136261U; // Intentionally uint32_t instead of size_t, so the behavior is the same regardless of size. + while((c = *p++) != 0) + result = (result * 16777619) ^ c; + return (size_t)result; + } + }; + + +} // namespace eastl + +#if EASTL_FUNCTION_ENABLED + EA_DISABLE_VC_WARNING(4510 4512 4610) // disable warning: function_manager not generating default constructor and default assignment operators. + #include + EA_RESTORE_VC_WARNING() +#endif + + +#endif // Header include guard + + + + + + + diff --git a/libs/eastl/include/EASTL/hash_map.h b/libs/eastl/include/EASTL/hash_map.h new file mode 100644 index 0000000..6cf2c1c --- /dev/null +++ b/libs/eastl/include/EASTL/hash_map.h @@ -0,0 +1,536 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file is based on the TR1 (technical report 1) reference implementation +// of the unordered_set/unordered_map C++ classes as of about 4/2005. Most likely +// many or all C++ library vendors' implementations of this classes will be +// based off of the reference version and so will look pretty similar to this +// file as well as other vendors' versions. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_HASH_MAP_H +#define EASTL_HASH_MAP_H + + +#include +#include +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// EASTL_HASH_MAP_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_HASH_MAP_DEFAULT_NAME + #define EASTL_HASH_MAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " hash_map" // Unless the user overrides something, this is "EASTL hash_map". + #endif + + + /// EASTL_HASH_MULTIMAP_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_HASH_MULTIMAP_DEFAULT_NAME + #define EASTL_HASH_MULTIMAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " hash_multimap" // Unless the user overrides something, this is "EASTL hash_multimap". + #endif + + + /// EASTL_HASH_MAP_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_HASH_MAP_DEFAULT_ALLOCATOR + #define EASTL_HASH_MAP_DEFAULT_ALLOCATOR allocator_type(EASTL_HASH_MAP_DEFAULT_NAME) + #endif + + /// EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR + #define EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR allocator_type(EASTL_HASH_MULTIMAP_DEFAULT_NAME) + #endif + + + + /// hash_map + /// + /// Implements a hash_map, which is a hashed associative container. + /// Lookups are O(1) (that is, they are fast) but the container is + /// not sorted. Note that lookups are only O(1) if the hash table + /// is well-distributed (non-colliding). The lookup approaches + /// O(n) behavior as the table becomes increasingly poorly distributed. + /// + /// set_max_load_factor + /// If you want to make a hashtable never increase its bucket usage, + /// call set_max_load_factor with a very high value such as 100000.f. + /// + /// bCacheHashCode + /// We provide the boolean bCacheHashCode template parameter in order + /// to allow the storing of the hash code of the key within the map. + /// When this option is disabled, the rehashing of the table will + /// call the hash function on the key. Setting bCacheHashCode to true + /// is useful for cases whereby the calculation of the hash value for + /// a contained object is very expensive. + /// + /// find_as + /// In order to support the ability to have a hashtable of strings but + /// be able to do efficiently lookups via char pointers (i.e. so they + /// aren't converted to string objects), we provide the find_as + /// function. This function allows you to do a find with a key of a + /// type other than the hashtable key type. + /// + /// Example find_as usage: + /// hash_map hashMap; + /// i = hashMap.find_as("hello"); // Use default hash and compare. + /// + /// Example find_as usage (namespaces omitted for brevity): + /// hash_map hashMap; + /// i = hashMap.find_as("hello", hash(), equal_to_2()); + /// + template , + typename Predicate = eastl::equal_to, typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false> + class hash_map + : public hashtable, Allocator, eastl::use_first >, Predicate, + Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, true> + { + public: + typedef hashtable, Allocator, + eastl::use_first >, + Predicate, Hash, mod_range_hashing, default_ranged_hash, + prime_rehash_policy, bCacheHashCode, true, true> base_type; + typedef hash_map this_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::key_type key_type; + typedef T mapped_type; + typedef typename base_type::value_type value_type; // Note that this is pair. + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::insert_return_type insert_return_type; + typedef typename base_type::iterator iterator; + + using base_type::insert; + + public: + /// hash_map + /// + /// Default constructor. + /// + explicit hash_map(const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR) + : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(), + Predicate(), eastl::use_first >(), allocator) + { + // Empty + } + + + /// hash_map + /// + /// Constructor which creates an empty container, but start with nBucketCount buckets. + /// We default to a small nBucketCount value, though the user really should manually + /// specify an appropriate value in order to prevent memory from being reallocated. + /// + explicit hash_map(size_type nBucketCount, const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR) + : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), + predicate, eastl::use_first >(), allocator) + { + // Empty + } + + + hash_map(const this_type& x) + : base_type(x) + { + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + hash_map(this_type&& x) + : base_type(eastl::move(x)) + { + } + + + hash_map(this_type&& x, const allocator_type& allocator) + : base_type(eastl::move(x), allocator) + { + } + #endif + + + /// hash_map + /// + /// initializer_list-based constructor. + /// Allows for initializing with brace values (e.g. hash_map hm = { {3,"c"}, {4,"d"}, {5,"e"} }; ) + /// + hash_map(std::initializer_list ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR) + : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), + predicate, eastl::use_first >(), allocator) + { + // Empty + } + + + /// hash_map + /// + /// An input bucket count of <= 1 causes the bucket count to be equal to the number of + /// elements in the input range. + /// + template + hash_map(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR) + : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), + predicate, eastl::use_first >(), allocator) + { + // Empty + } + + + this_type& operator=(const this_type& x) + { + return static_cast(base_type::operator=(x)); + } + + + this_type& operator=(std::initializer_list ilist) + { + return static_cast(base_type::operator=(ilist)); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x) + { + return static_cast(base_type::operator=(eastl::move(x))); + } + #endif + + + /// insert + /// + /// This is an extension to the C++ standard. We insert a default-constructed + /// element with the given key. The reason for this is that we can avoid the + /// potentially expensive operation of creating and/or copying a mapped_type + /// object on the stack. + insert_return_type insert(const key_type& key) + { + return base_type::DoInsertKey(true_type(), key); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + insert_return_type insert(key_type&& key) + { + return base_type::DoInsertKey(true_type(), eastl::move(key)); + } + #endif + + + mapped_type& operator[](const key_type& key) + { + return (*base_type::DoInsertKey(true_type(), key).first).second; + + // Slower reference version: + //const typename base_type::iterator it = base_type::find(key); + //if(it != base_type::end()) + // return (*it).second; + //return (*base_type::insert(value_type(key, mapped_type())).first).second; + } + + #if EASTL_MOVE_SEMANTICS_ENABLED + mapped_type& operator[](key_type&& key) + { + // The Standard states that this function "inserts the value value_type(std::move(key), mapped_type())" + return (*base_type::DoInsertKey(true_type(), eastl::move(key)).first).second; + } + #endif + + + }; // hash_map + + + + + + + /// hash_multimap + /// + /// Implements a hash_multimap, which is the same thing as a hash_map + /// except that contained elements need not be unique. See the + /// documentation for hash_set for details. + /// + template , typename Predicate = eastl::equal_to, + typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false> + class hash_multimap + : public hashtable, Allocator, eastl::use_first >, Predicate, + Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, false> + { + public: + typedef hashtable, Allocator, + eastl::use_first >, + Predicate, Hash, mod_range_hashing, default_ranged_hash, + prime_rehash_policy, bCacheHashCode, true, false> base_type; + typedef hash_multimap this_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::key_type key_type; + typedef T mapped_type; + typedef typename base_type::value_type value_type; // Note that this is pair. + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::insert_return_type insert_return_type; + typedef typename base_type::iterator iterator; + + using base_type::insert; + + public: + /// hash_multimap + /// + /// Default constructor. + /// + explicit hash_multimap(const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR) + : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(), + Predicate(), eastl::use_first >(), allocator) + { + // Empty + } + + + /// hash_multimap + /// + /// Constructor which creates an empty container, but start with nBucketCount buckets. + /// We default to a small nBucketCount value, though the user really should manually + /// specify an appropriate value in order to prevent memory from being reallocated. + /// + explicit hash_multimap(size_type nBucketCount, const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR) + : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), + predicate, eastl::use_first >(), allocator) + { + // Empty + } + + + hash_multimap(const this_type& x) + : base_type(x) + { + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + hash_multimap(this_type&& x) + : base_type(eastl::move(x)) + { + } + + + hash_multimap(this_type&& x, const allocator_type& allocator) + : base_type(eastl::move(x), allocator) + { + } + #endif + + + /// hash_multimap + /// + /// initializer_list-based constructor. + /// Allows for initializing with brace values (e.g. hash_multimap hm = { {3,"c"}, {3,"C"}, {4,"d"} }; ) + /// + hash_multimap(std::initializer_list ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR) + : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), + predicate, eastl::use_first >(), allocator) + { + // Empty + } + + + /// hash_multimap + /// + /// An input bucket count of <= 1 causes the bucket count to be equal to the number of + /// elements in the input range. + /// + template + hash_multimap(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR) + : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), + predicate, eastl::use_first >(), allocator) + { + // Empty + } + + + this_type& operator=(const this_type& x) + { + return static_cast(base_type::operator=(x)); + } + + + this_type& operator=(std::initializer_list ilist) + { + return static_cast(base_type::operator=(ilist)); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x) + { + return static_cast(base_type::operator=(eastl::move(x))); + } + #endif + + + /// insert + /// + /// This is an extension to the C++ standard. We insert a default-constructed + /// element with the given key. The reason for this is that we can avoid the + /// potentially expensive operation of creating and/or copying a mapped_type + /// object on the stack. + insert_return_type insert(const key_type& key) + { + return base_type::DoInsertKey(false_type(), key); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + insert_return_type insert(key_type&& key) + { + return base_type::DoInsertKey(false_type(), eastl::move(key)); + } + #endif + + + }; // hash_multimap + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const hash_map& a, + const hash_map& b) + { + typedef typename hash_map::const_iterator const_iterator; + + // We implement branching with the assumption that the return value is usually false. + if(a.size() != b.size()) + return false; + + // For map (with its unique keys), we need only test that each element in a can be found in b, + // as there can be only one such pairing per element. multimap needs to do a something more elaborate. + for(const_iterator ai = a.begin(), aiEnd = a.end(), biEnd = b.end(); ai != aiEnd; ++ai) + { + const_iterator bi = b.find(ai->first); + + if((bi == biEnd) || !(*ai == *bi)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair. + return false; // It's possible that two elements in the two containers have identical keys but different values. + } + + return true; + } + + template + inline bool operator!=(const hash_map& a, + const hash_map& b) + { + return !(a == b); + } + + + template + inline bool operator==(const hash_multimap& a, + const hash_multimap& b) + { + typedef typename hash_multimap::const_iterator const_iterator; + typedef typename eastl::iterator_traits::difference_type difference_type; + + // We implement branching with the assumption that the return value is usually false. + if(a.size() != b.size()) + return false; + + // We can't simply search for each element of a in b, as it may be that the bucket for + // two elements in a has those same two elements in b but in different order (which should + // still result in equality). Also it's possible that one bucket in a has two elements which + // both match a solitary element in the equivalent bucket in b (which shouldn't result in equality). + eastl::pair aRange; + eastl::pair bRange; + + for(const_iterator ai = a.begin(), aiEnd = a.end(); ai != aiEnd; ai = aRange.second) // For each element in a... + { + aRange = a.equal_range(ai->first); // Get the range of elements in a that are equal to ai. + bRange = b.equal_range(ai->first); // Get the range of elements in b that are equal to ai. + + // We need to verify that aRange == bRange. First make sure the range sizes are equivalent... + const difference_type aDistance = eastl::distance(aRange.first, aRange.second); + const difference_type bDistance = eastl::distance(bRange.first, bRange.second); + + if(aDistance != bDistance) + return false; + + // At this point, aDistance > 0 and aDistance == bDistance. + // Implement a fast pathway for the case that there's just a single element. + if(aDistance == 1) + { + if(!(*aRange.first == *bRange.first)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair. + return false; // It's possible that two elements in the two containers have identical keys but different values. Ditto for the permutation case below. + } + else + { + // Check to see if these aRange and bRange are any permutation of each other. + // This check gets slower as there are more elements in the range. + if(!eastl::is_permutation(aRange.first, aRange.second, bRange.first)) + return false; + } + } + + return true; + } + + template + inline bool operator!=(const hash_multimap& a, + const hash_multimap& b) + { + return !(a == b); + } + + +} // namespace eastl + + +// Test stuff related with Spore +struct test_hashtable +{ + /* 00h */ int field_28; + /* 04h */ void* mpBucketArray; // node_type** mpBucketArray ? + /* 08h */ int mnBucketCount; // mnBucketCount + /* 0Ch */ int mnElementCount; // mnElementCount + + //prime_rehash_policy + /* 10h */ float mfMaxLoadFactor; + /* 14h */ float mfGrowthFactor; + /* 18h */ int mnNextResize; + + /* 1Ch */ void* mAllocator; // mAllocator // points to this+8 (in PFIndexModifiable) +}; +// static_assert(sizeof(test_hashtable) == 0x20, "sizeof(test_hashtable) != 20h"); +// +// static_assert(sizeof(eastl::hash_map) == 0x20, "sizeof(hash_map) != 20h"); + +#endif // Header include guard + + + + + + diff --git a/libs/eastl/include/EASTL/hash_set.h b/libs/eastl/include/EASTL/hash_set.h new file mode 100644 index 0000000..f776de4 --- /dev/null +++ b/libs/eastl/include/EASTL/hash_set.h @@ -0,0 +1,440 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file is based on the TR1 (technical report 1) reference implementation +// of the unordered_set/unordered_map C++ classes as of about 4/2005. Most likely +// many or all C++ library vendors' implementations of this classes will be +// based off of the reference version and so will look pretty similar to this +// file as well as other vendors' versions. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_HASH_SET_H +#define EASTL_HASH_SET_H + + +#include +#include +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// EASTL_HASH_SET_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_HASH_SET_DEFAULT_NAME + #define EASTL_HASH_SET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " hash_set" // Unless the user overrides something, this is "EASTL hash_set". + #endif + + + /// EASTL_HASH_MULTISET_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_HASH_MULTISET_DEFAULT_NAME + #define EASTL_HASH_MULTISET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " hash_multiset" // Unless the user overrides something, this is "EASTL hash_multiset". + #endif + + + /// EASTL_HASH_SET_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_HASH_SET_DEFAULT_ALLOCATOR + #define EASTL_HASH_SET_DEFAULT_ALLOCATOR allocator_type(EASTL_HASH_SET_DEFAULT_NAME) + #endif + + /// EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR + #define EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR allocator_type(EASTL_HASH_MULTISET_DEFAULT_NAME) + #endif + + + + /// hash_set + /// + /// Implements a hash_set, which is a hashed unique-item container. + /// Lookups are O(1) (that is, they are fast) but the container is + /// not sorted. Note that lookups are only O(1) if the hash table + /// is well-distributed (non-colliding). The lookup approaches + /// O(n) behavior as the table becomes increasingly poorly distributed. + /// + /// set_max_load_factor + /// If you want to make a hashtable never increase its bucket usage, + /// call set_max_load_factor with a very high value such as 100000.f. + /// + /// bCacheHashCode + /// We provide the boolean bCacheHashCode template parameter in order + /// to allow the storing of the hash code of the key within the map. + /// When this option is disabled, the rehashing of the table will + /// call the hash function on the key. Setting bCacheHashCode to true + /// is useful for cases whereby the calculation of the hash value for + /// a contained object is very expensive. + /// + /// find_as + /// In order to support the ability to have a hashtable of strings but + /// be able to do efficiently lookups via char pointers (i.e. so they + /// aren't converted to string objects), we provide the find_as + /// function. This function allows you to do a find with a key of a + /// type other than the hashtable key type. + /// + /// Example find_as usage: + /// hash_set hashSet; + /// i = hashSet.find_as("hello"); // Use default hash and compare. + /// + /// Example find_as usage (namespaces omitted for brevity): + /// hash_set hashSet; + /// i = hashSet.find_as("hello", hash(), equal_to_2()); + /// + template , typename Predicate = eastl::equal_to, + typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false> + class hash_set + : public hashtable, Predicate, + Hash, mod_range_hashing, default_ranged_hash, + prime_rehash_policy, bCacheHashCode, false, true> + { + public: + typedef hashtable, Predicate, + Hash, mod_range_hashing, default_ranged_hash, + prime_rehash_policy, bCacheHashCode, false, true> base_type; + typedef hash_set this_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::node_type node_type; + + public: + /// hash_set + /// + /// Default constructor. + /// + explicit hash_set(const allocator_type& allocator = EASTL_HASH_SET_DEFAULT_ALLOCATOR) + : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(), Predicate(), eastl::use_self(), allocator) + { + // Empty + } + + + /// hash_set + /// + /// Constructor which creates an empty container, but start with nBucketCount buckets. + /// We default to a small nBucketCount value, though the user really should manually + /// specify an appropriate value in order to prevent memory from being reallocated. + /// + explicit hash_set(size_type nBucketCount, const Hash& hashFunction = Hash(), const Predicate& predicate = Predicate(), + const allocator_type& allocator = EASTL_HASH_SET_DEFAULT_ALLOCATOR) + : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self(), allocator) + { + // Empty + } + + + hash_set(const this_type& x) + : base_type(x) + { + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + hash_set(this_type&& x) + : base_type(eastl::move(x)) + { + } + + + hash_set(this_type&& x, const allocator_type& allocator) + : base_type(eastl::move(x), allocator) + { + } + #endif + + + /// hash_set + /// + /// initializer_list-based constructor. + /// Allows for initializing with brace values (e.g. hash_set hs = { 3, 4, 5, }; ) + /// + hash_set(std::initializer_list ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_SET_DEFAULT_ALLOCATOR) + : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self(), allocator) + { + // Empty + } + + + /// hash_set + /// + /// An input bucket count of <= 1 causes the bucket count to be equal to the number of + /// elements in the input range. + /// + template + hash_set(FowardIterator first, FowardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_SET_DEFAULT_ALLOCATOR) + : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self(), allocator) + { + // Empty + } + + + this_type& operator=(const this_type& x) + { + return static_cast(base_type::operator=(x)); + } + + + this_type& operator=(std::initializer_list ilist) + { + return static_cast(base_type::operator=(ilist)); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x) + { + return static_cast(base_type::operator=(eastl::move(x))); + } + #endif + + }; // hash_set + + + + + + + /// hash_multiset + /// + /// Implements a hash_multiset, which is the same thing as a hash_set + /// except that contained elements need not be unique. See the documentation + /// for hash_set for details. + /// + template , typename Predicate = eastl::equal_to, + typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false> + class hash_multiset + : public hashtable, Predicate, + Hash, mod_range_hashing, default_ranged_hash, + prime_rehash_policy, bCacheHashCode, false, false> + { + public: + typedef hashtable, Predicate, + Hash, mod_range_hashing, default_ranged_hash, + prime_rehash_policy, bCacheHashCode, false, false> base_type; + typedef hash_multiset this_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::node_type node_type; + + public: + /// hash_multiset + /// + /// Default constructor. + /// + explicit hash_multiset(const allocator_type& allocator = EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR) + : base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(), Predicate(), eastl::use_self(), allocator) + { + // Empty + } + + + /// hash_multiset + /// + /// Constructor which creates an empty container, but start with nBucketCount buckets. + /// We default to a small nBucketCount value, though the user really should manually + /// specify an appropriate value in order to prevent memory from being reallocated. + /// + explicit hash_multiset(size_type nBucketCount, const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR) + : base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self(), allocator) + { + // Empty + } + + + hash_multiset(const this_type& x) + : base_type(x) + { + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + hash_multiset(this_type&& x) + : base_type(eastl::move(x)) + { + } + + + hash_multiset(this_type&& x, const allocator_type& allocator) + : base_type(eastl::move(x), allocator) + { + } + #endif + + + /// hash_multiset + /// + /// initializer_list-based constructor. + /// Allows for initializing with brace values (e.g. hash_set hs = { 3, 3, 4, }; ) + /// + hash_multiset(std::initializer_list ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR) + : base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self(), allocator) + { + // Empty + } + + + /// hash_multiset + /// + /// An input bucket count of <= 1 causes the bucket count to be equal to the number of + /// elements in the input range. + /// + template + hash_multiset(FowardIterator first, FowardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(), + const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR) + : base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self(), allocator) + { + // Empty + } + + + this_type& operator=(const this_type& x) + { + return static_cast(base_type::operator=(x)); + } + + + this_type& operator=(std::initializer_list ilist) + { + return static_cast(base_type::operator=(ilist)); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x) + { + return static_cast(base_type::operator=(eastl::move(x))); + } + #endif + + }; // hash_multiset + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const hash_set& a, + const hash_set& b) + { + typedef typename hash_set::const_iterator const_iterator; + + // We implement branching with the assumption that the return value is usually false. + if(a.size() != b.size()) + return false; + + // For set (with its unique keys), we need only test that each element in a can be found in b, + // as there can be only one such pairing per element. multiset needs to do a something more elaborate. + for(const_iterator ai = a.begin(), aiEnd = a.end(), biEnd = b.end(); ai != aiEnd; ++ai) + { + const_iterator bi = b.find(*ai); + + if((bi == biEnd) || !(*ai == *bi)) // We have to compare values in addition to making sure the lookups succeeded. This is because the lookup is done via the user-supplised Predicate + return false; // which isn't strictly required to be identical to the Value operator==, though 99% of the time it will be so. + } + + return true; + } + + template + inline bool operator!=(const hash_set& a, + const hash_set& b) + { + return !(a == b); + } + + + template + inline bool operator==(const hash_multiset& a, + const hash_multiset& b) + { + typedef typename hash_multiset::const_iterator const_iterator; + typedef typename eastl::iterator_traits::difference_type difference_type; + + // We implement branching with the assumption that the return value is usually false. + if(a.size() != b.size()) + return false; + + // We can't simply search for each element of a in b, as it may be that the bucket for + // two elements in a has those same two elements in b but in different order (which should + // still result in equality). Also it's possible that one bucket in a has two elements which + // both match a solitary element in the equivalent bucket in b (which shouldn't result in equality). + eastl::pair aRange; + eastl::pair bRange; + + for(const_iterator ai = a.begin(), aiEnd = a.end(); ai != aiEnd; ai = aRange.second) // For each element in a... + { + aRange = a.equal_range(*ai); // Get the range of elements in a that are equal to ai. + bRange = b.equal_range(*ai); // Get the range of elements in b that are equal to ai. + + // We need to verify that aRange == bRange. First make sure the range sizes are equivalent... + const difference_type aDistance = eastl::distance(aRange.first, aRange.second); + const difference_type bDistance = eastl::distance(bRange.first, bRange.second); + + if(aDistance != bDistance) + return false; + + // At this point, aDistance > 0 and aDistance == bDistance. + // Implement a fast pathway for the case that there's just a single element. + if(aDistance == 1) + { + if(!(*aRange.first == *bRange.first)) // We have to compare values in addition to making sure the distance (element count) was equal. This is because the lookup is done via the user-supplised Predicate + return false; // which isn't strictly required to be identical to the Value operator==, though 99% of the time it will be so. Ditto for the is_permutation usage below. + } + else + { + // Check to see if these aRange and bRange are any permutation of each other. + // This check gets slower as there are more elements in the range. + if(!eastl::is_permutation(aRange.first, aRange.second, bRange.first)) + return false; + } + } + + return true; + } + + template + inline bool operator!=(const hash_multiset& a, + const hash_multiset& b) + { + return !(a == b); + } + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/heap.h b/libs/eastl/include/EASTL/heap.h new file mode 100644 index 0000000..6472368 --- /dev/null +++ b/libs/eastl/include/EASTL/heap.h @@ -0,0 +1,589 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements heap functionality much like the std C++ heap algorithms. +// Such heaps are not the same thing as memory heaps or pools, but rather are +// semi-sorted random access containers which have the primary purpose of +// supporting the implementation of priority_queue and similar data structures. +// +// The primary distinctions between this heap functionality and std::heap are: +// - This heap exposes some extra functionality such as is_heap and change_heap. +// - This heap is more efficient than versions found in typical STL +// implementations such as STLPort, Microsoft, and Metrowerks. This comes +// about due to better use of array dereferencing and branch prediction. +// You should expect of 5-30%, depending on the usage and platform. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// The publicly usable functions we define are: +// push_heap -- Adds an entry to a heap. Same as C++ std::push_heap. +// pop_heap -- Removes the top entry from a heap. Same as C++ std::pop_heap. +// make_heap -- Converts an array to a heap. Same as C++ std::make_heap. +// sort_heap -- Sorts a heap in place. Same as C++ std::sort_heap. +// remove_heap -- Removes an arbitrary entry from a heap. +// change_heap -- Changes the priority of an entry in the heap. +// is_heap -- Returns true if an array appears is in heap format. Same as C++11 std::is_heap. +// is_heap_until -- Returns largest part of the range which is a heap. Same as C++11 std::is_heap_until. +/////////////////////////////////////////////////////////////////////////////// + + + +#ifndef EASTL_HEAP_H +#define EASTL_HEAP_H + + +#include +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /////////////////////////////////////////////////////////////////////// + // promote_heap (internal function) + /////////////////////////////////////////////////////////////////////// + + /// promote_heap + /// + /// Moves a value in the heap from a given position upward until + /// it is sorted correctly. It's kind of like bubble-sort, except that + /// instead of moving linearly from the back of a list to the front, + /// it moves from the bottom of the tree up the branches towards the + /// top. But otherwise is just like bubble-sort. + /// + /// This function requires that the value argument refer to a value + /// that is currently not within the heap. + /// + template + inline void promote_heap(RandomAccessIterator first, Distance topPosition, Distance position, const T& value) + { + for(Distance parentPosition = (position - 1) >> 1; // This formula assumes that (position > 0). // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>. + (position > topPosition) && (*(first + parentPosition) < value); + parentPosition = (position - 1) >> 1) + { + *(first + position) = *(first + parentPosition); // Swap the node with its parent. + position = parentPosition; + } + + *(first + position) = value; + } + + /// promote_heap + /// + /// Takes a Compare(a, b) function (or function object) which returns true if a < b. + /// For example, you could use the standard 'less' comparison object. + /// + /// The Compare function must work equivalently to the compare function used + /// to make and maintain the heap. + /// + /// This function requires that the value argument refer to a value + /// that is currently not within the heap. + /// + template + inline void promote_heap(RandomAccessIterator first, Distance topPosition, Distance position, const T& value, Compare compare) + { + for(Distance parentPosition = (position - 1) >> 1; // This formula assumes that (position > 0). // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>. + (position > topPosition) && compare(*(first + parentPosition), value); + parentPosition = (position - 1) >> 1) + { + *(first + position) = *(first + parentPosition); // Swap the node with its parent. + position = parentPosition; + } + + *(first + position) = value; + } + + + + /////////////////////////////////////////////////////////////////////// + // adjust_heap (internal function) + /////////////////////////////////////////////////////////////////////// + + /// adjust_heap + /// + /// Given a position that has just been vacated, this function moves + /// new values into that vacated position appropriately. The value + /// argument is an entry which will be inserted into the heap after + /// we move nodes into the positions that were vacated. + /// + /// This function requires that the value argument refer to a value + /// that is currently not within the heap. + /// + template + void adjust_heap(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, const T& value) + { + // We do the conventional approach of moving the position down to the + // bottom then inserting the value at the back and moving it up. + Distance childPosition = (2 * position) + 2; + + for(; childPosition < heapSize; childPosition = (2 * childPosition) + 2) + { + if(*(first + childPosition) < *(first + (childPosition - 1))) // Choose the larger of the two children. + --childPosition; + *(first + position) = *(first + childPosition); // Swap positions with this child. + position = childPosition; + } + + if(childPosition == heapSize) // If we are at the very last index of the bottom... + { + *(first + position) = *(first + (childPosition - 1)); + position = childPosition - 1; + } + + eastl::promote_heap(first, topPosition, position, value); + } + + + /// adjust_heap + /// + /// The Compare function must work equivalently to the compare function used + /// to make and maintain the heap. + /// + /// This function requires that the value argument refer to a value + /// that is currently not within the heap. + /// + template + void adjust_heap(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, const T& value, Compare compare) + { + // We do the conventional approach of moving the position down to the + // bottom then inserting the value at the back and moving it up. + Distance childPosition = (2 * position) + 2; + + for(; childPosition < heapSize; childPosition = (2 * childPosition) + 2) + { + if(compare(*(first + childPosition), *(first + (childPosition - 1)))) // Choose the larger of the two children. + --childPosition; + *(first + position) = *(first + childPosition); // Swap positions with this child. + position = childPosition; + } + + if(childPosition == heapSize) // If we are at the bottom... + { + *(first + position) = *(first + (childPosition - 1)); + position = childPosition - 1; + } + + eastl::promote_heap(first, topPosition, position, value, compare); + } + + + + + /////////////////////////////////////////////////////////////////////// + // push_heap + /////////////////////////////////////////////////////////////////////// + + /// push_heap + /// + /// Adds an item to a heap (which is an array). The item necessarily + /// comes from the back of the heap (array). Thus, the insertion of a + /// new item in a heap is a two step process: push_back and push_heap. + /// + /// Example usage: + /// vector heap; + /// + /// heap.push_back(3); + /// push_heap(heap.begin(), heap.end()); // Places '3' appropriately. + /// + template + inline void push_heap(RandomAccessIterator first, RandomAccessIterator last) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::iterator_traits::value_type value_type; + + const value_type tempBottom(*(last - 1)); + + eastl::promote_heap + (first, (difference_type)0, (difference_type)(last - first - 1), tempBottom); + } + + + /// push_heap + /// + /// This version is useful for cases where your object comparison is unusual + /// or where you want to have the heap store pointers to objects instead of + /// storing the objects themselves (often in order to improve cache coherency + /// while doing sorting). + /// + /// The Compare function must work equivalently to the compare function used + /// to make and maintain the heap. + /// + template + inline void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::iterator_traits::value_type value_type; + + const value_type tempBottom(*(last - 1)); + + eastl::promote_heap + (first, (difference_type)0, (difference_type)(last - first - 1), tempBottom, compare); + } + + + + + /////////////////////////////////////////////////////////////////////// + // pop_heap + /////////////////////////////////////////////////////////////////////// + + /// pop_heap + /// + /// Removes the first item from the heap (which is an array), and adjusts + /// the heap so that the highest priority item becomes the new first item. + /// + /// Example usage: + /// vector heap; + /// + /// heap.push_back(2); + /// heap.push_back(3); + /// heap.push_back(1); + /// + /// pop_heap(heap.begin(), heap.end()); // Moves heap[0] to the back of the heap and adjusts the heap. + /// heap.pop_back(); // Remove value that was just at the top of the heap + /// + template + inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::iterator_traits::value_type value_type; + + const value_type tempBottom(*(last - 1)); + *(last - 1) = *first; + eastl::adjust_heap + (first, (difference_type)0, (difference_type)(last - first - 1), 0, tempBottom); + } + + + + /// pop_heap + /// + /// This version is useful for cases where your object comparison is unusual + /// or where you want to have the heap store pointers to objects instead of + /// storing the objects themselves (often in order to improve cache coherency + /// while doing sorting). + /// + /// The Compare function must work equivalently to the compare function used + /// to make and maintain the heap. + /// + template + inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::iterator_traits::value_type value_type; + + const value_type tempBottom(*(last - 1)); + *(last - 1) = *first; + eastl::adjust_heap + (first, (difference_type)0, (difference_type)(last - first - 1), 0, tempBottom, compare); + } + + + + + /////////////////////////////////////////////////////////////////////// + // make_heap + /////////////////////////////////////////////////////////////////////// + + + /// make_heap + /// + /// Given an array, this function converts it into heap format. + /// The complexity is O(n), where n is count of the range. + /// The input range is not required to be in any order. + /// + template + void make_heap(RandomAccessIterator first, RandomAccessIterator last) + { + // We do bottom-up heap construction as per Sedgewick. Such construction is O(n). + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::iterator_traits::value_type value_type; + + const difference_type heapSize = last - first; + + if(heapSize >= 2) // If there is anything to do... (we need this check because otherwise the math fails below). + { + difference_type parentPosition = ((heapSize - 2) >> 1) + 1; // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>. + + do{ + --parentPosition; + const value_type temp(*(first + parentPosition)); + eastl::adjust_heap + (first, parentPosition, heapSize, parentPosition, temp); + } while(parentPosition != 0); + } + } + + + template + void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::iterator_traits::value_type value_type; + + const difference_type heapSize = last - first; + + if(heapSize >= 2) // If there is anything to do... (we need this check because otherwise the math fails below). + { + difference_type parentPosition = ((heapSize - 2) >> 1) + 1; // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>. + + do{ + --parentPosition; + const value_type temp(*(first + parentPosition)); + eastl::adjust_heap + (first, parentPosition, heapSize, parentPosition, temp, compare); + } while(parentPosition != 0); + } + } + + + + + /////////////////////////////////////////////////////////////////////// + // sort_heap + /////////////////////////////////////////////////////////////////////// + + /// sort_heap + /// + /// After the application if this algorithm, the range it was applied to + /// is no longer a heap, though it will be a reverse heap (smallest first). + /// The item with the lowest priority will be first, and the highest last. + /// This is not a stable sort because the relative order of equivalent + /// elements is not necessarily preserved. + /// The range referenced must be valid; all pointers must be dereferenceable + /// and within the sequence the last position is reachable from the first + /// by incrementation. + /// The complexity is at most O(n * log(n)), where n is count of the range. + /// + template + inline void sort_heap(RandomAccessIterator first, RandomAccessIterator last) + { + for(; (last - first) > 1; --last) // We simply use the heap to sort itself. + eastl::pop_heap(first, last); + } + + + /// sort_heap + /// + /// The Compare function must work equivalently to the compare function used + /// to make and maintain the heap. + /// + template + inline void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare) + { + for(; (last - first) > 1; --last) // We simply use the heap to sort itself. + eastl::pop_heap(first, last, compare); + } + + + + /////////////////////////////////////////////////////////////////////// + // remove_heap + /////////////////////////////////////////////////////////////////////// + + /// remove_heap + /// + /// Removes an arbitrary entry from the heap and adjusts the heap appropriately. + /// This function is unlike pop_heap in that pop_heap moves the top item + /// to the back of the heap, whereas remove_heap moves an arbitrary item to + /// the back of the heap. + /// + /// Note: Since this function moves the element to the back of the heap and + /// doesn't actually remove it from the given container, the user must call + /// the container erase function if the user wants to erase the element + /// from the container. + /// + template + inline void remove_heap(RandomAccessIterator first, Distance heapSize, Distance position) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::iterator_traits::value_type value_type; + + const value_type tempBottom(*(first + heapSize - 1)); + *(first + heapSize - 1) = *(first + position); + eastl::adjust_heap + (first, (difference_type)0, (difference_type)(heapSize - 1), (difference_type)position, tempBottom); + } + + + /// remove_heap + /// + /// The Compare function must work equivalently to the compare function used + /// to make and maintain the heap. + /// + /// Note: Since this function moves the element to the back of the heap and + /// doesn't actually remove it from the given container, the user must call + /// the container erase function if the user wants to erase the element + /// from the container. + /// + template + inline void remove_heap(RandomAccessIterator first, Distance heapSize, Distance position, Compare compare) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::iterator_traits::value_type value_type; + + const value_type tempBottom(*(first + heapSize - 1)); + *(first + heapSize - 1) = *(first + position); + eastl::adjust_heap + (first, (difference_type)0, (difference_type)(heapSize - 1), (difference_type)position, tempBottom, compare); + } + + + + /////////////////////////////////////////////////////////////////////// + // change_heap + /////////////////////////////////////////////////////////////////////// + + /// change_heap + /// + /// Given a value in the heap that has changed in priority, this function + /// adjusts the heap appropriately. The heap size remains unchanged after + /// this operation. + /// + template + inline void change_heap(RandomAccessIterator first, Distance heapSize, Distance position) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::iterator_traits::value_type value_type; + + eastl::remove_heap(first, heapSize, position); + + value_type tempBottom(*(first + heapSize - 1)); + + eastl::promote_heap + (first, (difference_type)0, (difference_type)(heapSize - 1), tempBottom); + } + + + /// change_heap + /// + /// The Compare function must work equivalently to the compare function used + /// to make and maintain the heap. + /// + template + inline void change_heap(RandomAccessIterator first, Distance heapSize, Distance position, Compare compare) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::iterator_traits::value_type value_type; + + eastl::remove_heap(first, heapSize, position, compare); + + value_type tempBottom(*(first + heapSize - 1)); + + eastl::promote_heap + (first, (difference_type)0, (difference_type)(heapSize - 1), tempBottom, compare); + } + + + + /////////////////////////////////////////////////////////////////////// + // is_heap_until + /////////////////////////////////////////////////////////////////////// + + /// is_heap_until + /// + template + inline RandomAccessIterator is_heap_until(RandomAccessIterator first, RandomAccessIterator last) + { + int counter = 0; + + for(RandomAccessIterator child = first + 1; child < last; ++child, counter ^= 1) + { + if(*first < *child) // We must use operator <, and are not allowed to use > or >= here. + return child; + first += counter; // counter switches between 0 and 1 every time through. + } + + return last; + } + + + /// is_heap_until + /// + /// The Compare function must work equivalently to the compare function used + /// to make and maintain the heap. + /// + template + inline RandomAccessIterator is_heap_until(RandomAccessIterator first, RandomAccessIterator last, Compare compare) + { + int counter = 0; + + for(RandomAccessIterator child = first + 1; child < last; ++child, counter ^= 1) + { + if(compare(*first, *child)) + return child; + first += counter; // counter switches between 0 and 1 every time through. + } + + return last; + } + + + + /////////////////////////////////////////////////////////////////////// + // is_heap + /////////////////////////////////////////////////////////////////////// + + /// is_heap + /// + /// This is a useful debugging algorithm for verifying that a random + /// access container is in heap format. + /// + template + inline bool is_heap(RandomAccessIterator first, RandomAccessIterator last) + { + return (eastl::is_heap_until(first, last) == last); + } + + + /// is_heap + /// + /// The Compare function must work equivalently to the compare function used + /// to make and maintain the heap. + /// + template + inline bool is_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare) + { + return (eastl::is_heap_until(first, last, compare) == last); + } + + + // To consider: The following may be a faster implementation for most cases. + // + // template + // inline bool is_heap(RandomAccessIterator first, RandomAccessIterator last) + // { + // if(((uintptr_t)(last - first) & 1) == 0) // If the range has an even number of elements... + // --last; + // + // RandomAccessIterator parent = first, child = (first + 1); + // + // for(; child < last; child += 2, ++parent) + // { + // if((*parent < *child) || (*parent < *(child + 1))) + // return false; + // } + // + // if((((uintptr_t)(last - first) & 1) == 0) && (*parent < *child)) + // return false; + // + // return true; + // } + + +} // namespace eastl + + +#endif // Header include guard + + + + diff --git a/libs/eastl/include/EASTL/initializer_list.h b/libs/eastl/include/EASTL/initializer_list.h new file mode 100644 index 0000000..912eabb --- /dev/null +++ b/libs/eastl/include/EASTL/initializer_list.h @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +// +// This file #includes if it's available, else it defines +// its own version of std::initializer_list. It does not define eastl::initializer_list +// because that would not provide any use, due to how the C++11 Standard works. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INITIALIZER_LIST_H +#define EASTL_INITIALIZER_LIST_H + + +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) +#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed + // improvements in apps as a result. +#endif + +// Older EABase versions have a bug in EA_HAVE_CPP11_INITIALIZER_LIST for the +// combination of clang/libstdc++, so we implement a fix for that here. +#if (EABASE_VERSION_N < 20042) // If using a version of EABase that has a bug or doesn't have support at all... +#error Version error +#if defined(EA_HAVE_CPP11_INITIALIZER_LIST) +#undef EA_HAVE_CPP11_INITIALIZER_LIST +#endif +#if defined(EA_NO_HAVE_CPP11_INITIALIZER_LIST) +#undef EA_NO_HAVE_CPP11_INITIALIZER_LIST +#endif + +#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 520) && \ + !defined(EA_COMPILER_NO_INITIALIZER_LISTS) // Dinkumware. VS2010+ +#define EA_HAVE_CPP11_INITIALIZER_LIST 1 +#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_CLANG) && \ + (EA_COMPILER_VERSION >= 301) && !defined(EA_COMPILER_NO_INITIALIZER_LISTS) && !defined(EA_PLATFORM_APPLE) +#define EA_HAVE_CPP11_INITIALIZER_LIST 1 +#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && \ + (EA_COMPILER_VERSION >= 4004) && !defined(EA_COMPILER_NO_INITIALIZER_LISTS) && !defined(EA_PLATFORM_APPLE) +#define EA_HAVE_CPP11_INITIALIZER_LIST 1 +#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1) && !defined(EA_COMPILER_NO_INITIALIZER_LISTS) +#define EA_HAVE_CPP11_INITIALIZER_LIST 1 +#else +#define EA_NO_HAVE_CPP11_INITIALIZER_LIST 1 +#endif + +#endif + + +#if defined(EA_HAVE_CPP11_INITIALIZER_LIST) // If the compiler can generate calls to std::initializer_list... + +// The initializer_list type must be declared in the std namespace, as that's the +// namespace the compiler uses when generating code to use it. +#ifdef _MSC_VER +#pragma warning(push, 0) +#endif +#include +#ifdef _MSC_VER +#pragma warning(pop) +#endif +//#error "This should stop compiling" +#else +//#error This should never happen + +// If you get an error here about initializer_list being already defined, then the EA_HAVE_CPP11_INITIALIZER_LIST define +// from needs to be updated. +namespace std +{ +// See the C++11 Standard, section 18.9. +template +class initializer_list +{ +public: + typedef E value_type; + typedef const E& reference; + typedef const E& const_reference; + typedef size_t size_type; + typedef const E* iterator; // Must be const, as initializer_list (and its mpArray) is an immutable temp object. + typedef const E* const_iterator; + +private: + iterator mpArray; + size_type mArraySize; + + // This constructor is private, but the C++ compiler has the ability to call it, as per the C++11 Standard. + initializer_list(const_iterator pArray, size_type arraySize) : mpArray(pArray), mArraySize(arraySize) {} + +public: + initializer_list() EA_NOEXCEPT // EA_NOEXCEPT requires a recent version of EABase. + : mpArray(NULL), + mArraySize(0) + { + } + + size_type size() const EA_NOEXCEPT { return mArraySize; } + const_iterator begin() const EA_NOEXCEPT + { + return mpArray; + } // Must be const_iterator, as initializer_list (and its mpArray) is an immutable temp object. + const_iterator end() const EA_NOEXCEPT { return mpArray + mArraySize; } +}; + + +template +const T* begin(std::initializer_list ilist) EA_NOEXCEPT +{ + return ilist.begin(); +} + +template +const T* end(std::initializer_list ilist) EA_NOEXCEPT +{ + return ilist.end(); +} +} // namespace std + +#endif + + +#endif // Header include guard diff --git a/libs/eastl/include/EASTL/internal/allocator_traits.h b/libs/eastl/include/EASTL/internal/allocator_traits.h new file mode 100644 index 0000000..7d7c423 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/allocator_traits.h @@ -0,0 +1,392 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// The code in this file is a modification of the libcxx implementation. We copy +// the license information here as required. +//////////////////////////////////////////////////////////////////////////////// +//===------------------------ functional ----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include +#include + +namespace eastl +{ +#if EASTL_FUNCTION_ENABLED + namespace Internal + { + // has_value_type + template + struct has_value_type + { + private: + template static eastl::no_type test(...); + template static eastl::yes_type test(typename U::value_type* = 0); + public: + static const bool value = sizeof(test(0)) == sizeof(eastl::yes_type); + }; + + template ::value> + struct value_type + { + typedef typename Alloc::value_type type; + }; + + template + struct value_type + { + typedef char type; + }; + + + // has_pointer_type + namespace has_pointer_type_imp + { + template static eastl::no_type test(...); + template static eastl::yes_type test(typename U::pointer* = 0); + } + + template + struct has_pointer_type + : public integral_constant(0)) == sizeof(eastl::yes_type)> + { + }; + + namespace PointerTypeInternal + { + template ::value> + struct pointer_type + { + typedef typename D::pointer type; + }; + + template + struct pointer_type + { + typedef T* type; + }; + } + + template + struct pointer_type + { + typedef typename PointerTypeInternal::pointer_type::type>::type type; + }; + + + // has_const_pointer + template + struct has_const_pointer + { + private: + template static eastl::no_type test(...); + template static eastl::yes_type test(typename U::const_pointer* = 0); + public: + static const bool value = sizeof(test(0)) == sizeof(eastl::yes_type); + }; + + template ::value> + struct const_pointer + { + typedef typename Alloc::const_pointer type; + }; + + template + struct const_pointer + { + #ifndef EA_COMPILER_NO_TEMPLATE_ALIASES + typedef typename pointer_traits::template rebind type; + #else + typedef typename pointer_traits::template rebind::other type; + #endif + }; + + + // has_void_pointer + template + struct has_void_pointer + { + private: + template static eastl::no_type test(...); + template static eastl::yes_type test(typename U::void_pointer* = 0); + public: + static const bool value = sizeof(test(0)) == sizeof(eastl::yes_type); + }; + + template ::value> + struct void_pointer + { + typedef typename Alloc::void_pointer type; + }; + + template + struct void_pointer + { + #ifndef EA_COMPILER_NO_TEMPLATE_ALIASES + typedef typename pointer_traits::template rebind type; + #else + typedef typename pointer_traits::template rebind::other type; + #endif + }; + + + // has_const_void_pointer + template + struct has_const_void_pointer + { + private: + template static eastl::no_type test(...); + template static eastl::yes_type test(typename U::const_void_pointer* = 0); + public: + static const bool value = sizeof(test(0)) == sizeof(eastl::yes_type); + }; + + template ::value> + struct const_void_pointer + { + typedef typename Alloc::const_void_pointer type; + }; + + template + struct const_void_pointer + { + #ifndef EA_COMPILER_NO_TEMPLATE_ALIASES + typedef typename pointer_traits::template rebind type; + #else + typedef typename pointer_traits::template rebind::other type; + #endif + }; + + + // alloc_traits_difference_type + template ::value> + struct alloc_traits_difference_type + { + typedef typename pointer_traits::difference_type type; + }; + + template + struct alloc_traits_difference_type + { + typedef typename Alloc::difference_type type; + }; + + + // has_size_type + template + struct has_size_type + { + private: + template static eastl::no_type test(...); + template static char test(typename U::size_type* = 0); + public: + static const bool value = sizeof(test(0)) == sizeof(eastl::yes_type); + }; + + template ::value> + struct size_type + { + typedef typename make_unsigned::type type; + }; + + template + struct size_type + { + typedef typename Alloc::size_type type; + }; + + +#if EASTL_VARIADIC_TEMPLATES_ENABLED + // has_construct + template + decltype(eastl::declval().construct(eastl::declval(), eastl::declval()...), eastl::true_type()) + has_construct_test(Alloc&& a, T* p, Args&&... args); + + template + eastl::false_type has_construct_test(const Alloc& a, Pointer&& p, Args&&... args); + + template + struct has_construct + : public eastl::integral_constant< bool, + eastl::is_same(), eastl::declval(), + eastl::declval()...)), + eastl::true_type>::value> + { + }; +#else + // has_construct (single argument case) + template + decltype(eastl::declval().construct(eastl::declval(), eastl::declval()), eastl::true_type()) + has_construct_test(Alloc&& a, T* p, Arg0&& args); + + template + eastl::false_type has_construct_test(const Alloc& a, Pointer&& p, Arg0&& args); + + template + struct has_construct + : public eastl::integral_constant< bool, + eastl::is_same(), eastl::declval(), + eastl::declval())), + eastl::true_type>::value> + { + }; +#endif + + + // has_destroy + template + auto has_destroy_test(Alloc&& a, Pointer&& p) -> decltype(a.destroy(p), eastl::true_type()); + + template + auto has_destroy_test(const Alloc& a, Pointer&& p) -> eastl::false_type; + + template + struct has_destroy + : public eastl::integral_constant< bool, + is_same(), eastl::declval())), eastl::true_type>::value> + { + }; + + + // has_max_size + template + auto has_max_size_test(Alloc&& a) -> decltype(a.max_size(), eastl::true_type()); + + template + auto has_max_size_test(const volatile Alloc& a) -> eastl::false_type; + + template + struct has_max_size + : public eastl::integral_constant())), eastl::true_type>::value> + { + }; + + } // namespace Internal + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // allocator_traits + // + // C++11 Standard section 20.7.8 + // This Internal namespace holds the utility functions required for allocator_traits to do compile-time type + // inspection inorder to determine if needs to provide a default implementation or utilize the users allocator + // implementation. + // + // Reference: http://en.cppreference.com/w/cpp/memory/allocator_traits + // + // eastl::allocator_traits supplies a uniform interface to all allocator types. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // eastl::allocator_traits is not a standards conforming implementation. Enough of the standard was implemented to + // make the eastl::function implementation possible. We must revisit this implementation before rolling out its + // usage fully in eastl::containers. + // + // NOTE: We do not recommend users directly code against eastl::allocator_traits until we have completed a full standards comforming implementation. + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + template + struct allocator_traits + { + typedef Alloc allocator_type; + + typedef typename Internal::value_type::type value_type; + typedef typename Internal::pointer_type::type pointer; + typedef typename Internal::const_pointer::type const_pointer; + typedef typename Internal::void_pointer::type void_pointer; + typedef typename Internal::const_void_pointer::type const_void_pointer; + typedef typename Internal::alloc_traits_difference_type::type difference_type; + typedef typename Internal::size_type::type size_type; + + // + // TODO: for full standards compliance implement the following: + // + // typedef typename Internal::propagate_on_container_copy_assignment::type propagate_on_container_copy_assignment; + // typedef typename Internal::propagate_on_container_move_assignment::type propagate_on_container_move_assignment; + // typedef typename Internal::propagate_on_container_swap::type propagate_on_container_swap; + // template using rebind_alloc = Alloc::rebind::other | Alloc; + // template using rebind_traits = allocator_traits>; + // static allocator_type select_on_container_copy_construction(const allocator_type& a); + + static size_type internal_max_size(true_type, const allocator_type& a) { return a.max_size(); } + static size_type internal_max_size(false_type, const allocator_type&) { return (eastl::numeric_limits::max)(); } // additional parenthesis disables the windows max macro from expanding. + static size_type max_size(const allocator_type& a) EA_NOEXCEPT + { + return internal_max_size(Internal::has_max_size(), a); + } + + static pointer allocate(allocator_type& a, size_type n) { return static_cast(a.allocate(n)); } + + static pointer allocate(allocator_type& a, size_type n, const_void_pointer) + { + // return allocate(a, n, hint, Internal::has_allocate_hint()); + return allocate(a, n); + } + + static void deallocate(allocator_type& a, pointer p, size_type n) EA_NOEXCEPT { a.deallocate(p, n); } + + #ifndef EA_COMPILER_NO_VARIADIC_TEMPLATES + template + static void internal_construct(eastl::true_type, allocator_type& a, T* p, Args&&... args) + { + a.construct(p, eastl::forward(args)...); + } + + template + static void internal_construct(false_type, allocator_type&, T* p, Args&&... args) + { + ::new ((void*)p) T(eastl::forward(args)...); + } + + template + static void construct(allocator_type& a, T* p, Args&&... args) + { + internal_construct(Internal::has_construct(), a, p, eastl::forward(args)...); + } + #else // EA_COMPILER_NO_VARIADIC_TEMPLATES + template + static void construct(allocator_type& a, T* p) + { + ::new ((void*)p) T(); + } + template + static void construct(allocator_type& a, T* p, const A0& a0) + { + ::new ((void*)p) T(a0); + } + template + static void construct(allocator_type& a, T* p, const A0& a0, const A1& a1) + { + ::new ((void*)p) T(a0, a1); + } + template + static void construct(allocator_type& a, T* p, const A0& a0, const A1& a1, const A2& a2) + { + ::new ((void*)p) T(a0, a1, a2); + } + #endif // EA_COMPILER_NO_VARIADIC_TEMPLATES + + template + static void internal_destroy(eastl::true_type, allocator_type& a, T* p) { a.destroy(p); } + + template + static void internal_destroy(eastl::false_type, allocator_type&, T* p) { p->~T(); } + + template + static void destroy(allocator_type& a, T* p) + { + internal_destroy(Internal::has_destroy(), a, p); + } + }; +#endif // EASTL_FUNCTION_ENABLED +} // namespace eastl + diff --git a/libs/eastl/include/EASTL/internal/allocator_traits_fwd_decls.h b/libs/eastl/include/EASTL/internal/allocator_traits_fwd_decls.h new file mode 100644 index 0000000..d6283cf --- /dev/null +++ b/libs/eastl/include/EASTL/internal/allocator_traits_fwd_decls.h @@ -0,0 +1,40 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_ALLOCATOR_TRAITS_H +#define EASTL_INTERNAL_ALLOCATOR_TRAITS_H + + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include +#include + +namespace eastl +{ + template + struct allocator_traits; + +} // namespace eastl + +#endif // Header include guard + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/config.h b/libs/eastl/include/EASTL/internal/config.h new file mode 100644 index 0000000..f1704ef --- /dev/null +++ b/libs/eastl/include/EASTL/internal/config.h @@ -0,0 +1,1838 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_CONFIG_H +#define EASTL_INTERNAL_CONFIG_H + + +/////////////////////////////////////////////////////////////////////////////// +// ReadMe +// +// This is the EASTL configuration file. All configurable parameters of EASTL +// are controlled through this file. However, all the settings here can be +// manually overridden by the user. There are three ways for a user to override +// the settings in this file: +// +// - Simply edit this file. +// - Define EASTL_USER_CONFIG_HEADER. +// - Predefine individual defines (e.g. EASTL_ASSERT). +// +/////////////////////////////////////////////////////////////////////////////// + +// This is my addition, Spore uses an extra field +#define USE_CONTAINER_GARBAGE 1 + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_USER_CONFIG_HEADER +// +// This allows the user to define a header file to be #included before the +// EASTL config.h contents are compiled. A primary use of this is to override +// the contents of this config.h file. Note that all the settings below in +// this file are user-overridable. +// +// Example usage: +// #define EASTL_USER_CONFIG_HEADER "MyConfigOverrides.h" +// #include +// +/////////////////////////////////////////////////////////////////////////////// + +#ifdef EASTL_USER_CONFIG_HEADER + #include EASTL_USER_CONFIG_HEADER +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_EABASE_DISABLED +// +// The user can disable EABase usage and manually supply the configuration +// via defining EASTL_EABASE_DISABLED and defining the appropriate entities +// globally or via the above EASTL_USER_CONFIG_HEADER. +// +// Example usage: +// #define EASTL_EABASE_DISABLED +// #include +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_EABASE_DISABLED + #include +#endif +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +/////////////////////////////////////////////////////////////////////////////// +// VC++ bug fix. +/////////////////////////////////////////////////////////////////////////////// + +#if defined(_MSC_VER) && (_MSC_VER < 1500) + // VC8 (VS2005) has a bug whereby it generates a warning when malloc.h is + // #included by its headers instead of by yours. There is no practical + // solution but to pre-empt the #include of malloc.h with our own inclusion + // of it. The only other alternative is to disable the warning globally, + // which is something we try to avoid as much as possible. + #pragma warning(push, 0) + #include + #pragma warning(pop) +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_VERSION +// +// We more or less follow the conventional EA packaging approach to versioning +// here. A primary distinction here is that minor versions are defined as two +// digit entities (e.g. .03") instead of minimal digit entities ".3"). The logic +// here is that the value is a counter and not a floating point fraction. +// Note that the major version doesn't have leading zeros. +// +// Example version strings: +// "0.91.00" // Major version 0, minor version 91, patch version 0. +// "1.00.00" // Major version 1, minor and patch version 0. +// "3.10.02" // Major version 3, minor version 10, patch version 02. +// "12.03.01" // Major version 12, minor version 03, patch version +// +// Example usage: +// printf("EASTL version: %s", EASTL_VERSION); +// printf("EASTL version: %d.%d.%d", EASTL_VERSION_N / 10000 % 100, EASTL_VERSION_N / 100 % 100, EASTL_VERSION_N % 100); +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_VERSION + #define EASTL_VERSION "3.02.01" + #define EASTL_VERSION_N 30201 +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// EA_COMPILER_NO_STANDARD_CPP_LIBRARY +// +// Defined as 1 or undefined. +// Implements support for the definition of EA_COMPILER_NO_STANDARD_CPP_LIBRARY for the case +// of using EABase versions prior to the addition of its EA_COMPILER_NO_STANDARD_CPP_LIBRARY support. +// +#if !defined(EA_COMPILER_NO_STANDARD_CPP_LIBRARY) + #if defined(EA_PLATFORM_ANDROID) + // Disabled because EA's eaconfig/android_config/android_sdk packages currently + // don't support linking STL libraries. Perhaps we can figure out what linker arguments + // are needed for an app so we can manually specify them and then re-enable this code. + // + //#include + // + //#if (__ANDROID_API__ < 9) // Earlier versions of Android provide no std C++ STL implementation. + #define EA_COMPILER_NO_STANDARD_CPP_LIBRARY 1 + //#endif + #endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// EA_NOEXCEPT +// +// Defined as a macro. Provided here for backward compatibility with older +// EABase versions prior to 2.00.40 that don't yet define it themselves. +// +#if !defined(EA_NOEXCEPT) + #define EA_NOEXCEPT + #define EA_NOEXCEPT_IF(predicate) + #define EA_NOEXCEPT_EXPR(expression) false +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EA_CPP14_CONSTEXPR +// +// Defined as constexpr when a C++14 compiler is present. Defines it as nothing +// when using a C++11 compiler. +// C++14 relaxes the specification for constexpr such that it allows more +// kinds of expressions. Since a C++11 compiler doesn't allow this, we need +// to make a unique define for C++14 constexpr. This macro should be used only +// when you are using it with code that specfically requires C++14 constexpr +// functionality beyond the regular C++11 constexpr functionality. +// http://en.wikipedia.org/wiki/C%2B%2B14#Relaxed_constexpr_restrictions +// +#if !defined(EA_CPP14_CONSTEXPR) + // To do: Detect compilers that support C++14 constexpr. + // We do not define this as EA_CONSTEXPR for the case of pre-C++14 compilers, + // but rather we must define this as nothing. + #define EA_CPP14_CONSTEXPR +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL namespace +// +// We define this so that users that #include this config file can reference +// these namespaces without seeing any other files that happen to use them. +/////////////////////////////////////////////////////////////////////////////// + +/// EA Standard Template Library +namespace eastl +{ + // Intentionally empty. +} + + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_DEBUG +// +// Defined as an integer >= 0. Default is 1 for debug builds and 0 for +// release builds. This define is also a master switch for the default value +// of some other settings. +// +// Example usage: +// #if EASTL_DEBUG +// ... +// #endif +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_DEBUG + #if defined(EA_DEBUG) || defined(_DEBUG) + #define EASTL_DEBUG 1 + #else + #define EASTL_DEBUG 0 + #endif +#endif + +// Developer debug. Helps EASTL developers assert EASTL is coded correctly. +// Normally disabled for users since it validates internal things and not user things. +#ifndef EASTL_DEV_DEBUG + #define EASTL_DEV_DEBUG 0 +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_DEBUGPARAMS_LEVEL +// +// EASTL_DEBUGPARAMS_LEVEL controls what debug information is passed through to +// the allocator by default. +// This value may be defined by the user ... if not it will default to 1 for +// EA_DEBUG builds, otherwise 0. +// +// 0 - no debug information is passed through to allocator calls. +// 1 - 'name' is passed through to allocator calls. +// 2 - 'name', __FILE__, and __LINE__ are passed through to allocator calls. +// +// This parameter mirrors the equivalent parameter in the CoreAllocator package. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_DEBUGPARAMS_LEVEL + #if EASTL_DEBUG + #define EASTL_DEBUGPARAMS_LEVEL 2 + #else + #define EASTL_DEBUGPARAMS_LEVEL 0 + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_DLL +// +// Defined as 0 or 1. The default is dependent on the definition of EA_DLL. +// If EA_DLL is defined, then EASTL_DLL is 1, else EASTL_DLL is 0. +// EA_DLL is a define that controls DLL builds within the EAConfig build system. +// EASTL_DLL controls whether EASTL is built and used as a DLL. +// Normally you wouldn't do such a thing, but there are use cases for such +// a thing, particularly in the case of embedding C++ into C# applications. +// +#ifndef EASTL_DLL + #if defined(EA_DLL) + #define EASTL_DLL 1 + #else + #define EASTL_DLL 0 + #endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_API +// +// This is used to label functions as DLL exports under Microsoft platforms. +// If EA_DLL is defined, then the user is building EASTL as a DLL and EASTL's +// non-templated functions will be exported. EASTL template functions are not +// labelled as EASTL_API (and are thus not exported in a DLL build). This is +// because it's not possible (or at least unsafe) to implement inline templated +// functions in a DLL. +// +// Example usage of EASTL_API: +// EASTL_API int someVariable = 10; // Export someVariable in a DLL build. +// +// struct EASTL_API SomeClass{ // Export SomeClass and its member functions in a DLL build. +// EASTL_LOCAL void PrivateMethod(); // Not exported. +// }; +// +// EASTL_API void SomeFunction(); // Export SomeFunction in a DLL build. +// +// +#if defined(EA_DLL) && !defined(EASTL_DLL) + #define EASTL_DLL 1 +#endif + +#ifndef EASTL_API // If the build file hasn't already defined this to be dllexport... + #if EASTL_DLL + #if defined(_MSC_VER) + #define EASTL_API __declspec(dllimport) + #define EASTL_LOCAL + #elif defined(__CYGWIN__) + #define EASTL_API __attribute__((dllimport)) + #define EASTL_LOCAL + #elif (defined(__GNUC__) && (__GNUC__ >= 4)) + #define EASTL_API __attribute__ ((visibility("default"))) + #define EASTL_LOCAL __attribute__ ((visibility("hidden"))) + #else + #define EASTL_API + #define EASTL_LOCAL + #endif + #else + #define EASTL_API + #define EASTL_LOCAL + #endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_EASTDC_API +// +// This is used for importing EAStdC functions into EASTL, possibly via a DLL import. +// +#ifndef EASTL_EASTDC_API + #if EASTL_DLL + #if defined(_MSC_VER) + #define EASTL_EASTDC_API __declspec(dllimport) + #define EASTL_EASTDC_LOCAL + #elif defined(__CYGWIN__) + #define EASTL_EASTDC_API __attribute__((dllimport)) + #define EASTL_EASTDC_LOCAL + #elif (defined(__GNUC__) && (__GNUC__ >= 4)) + #define EASTL_EASTDC_API __attribute__ ((visibility("default"))) + #define EASTL_EASTDC_LOCAL __attribute__ ((visibility("hidden"))) + #else + #define EASTL_EASTDC_API + #define EASTL_EASTDC_LOCAL + #endif + #else + #define EASTL_EASTDC_API + #define EASTL_EASTDC_LOCAL + #endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_EASTDC_VSNPRINTF +// +// Defined as 0 or 1. By default it is 1. +// +// When enabled EASTL uses EAStdC's Vsnprintf function directly instead of +// having the user provide a global Vsnprintf8/16/32 function. The benefit +// of this is that it will allow EASTL to just link to EAStdC's Vsnprintf +// without the user doing anything. The downside is that any users who aren't +// already using EAStdC will either need to now depend on EAStdC or globally +// define this property to be 0 and simply provide functions that have the same +// names. See the usage of EASTL_EASTDC_VSNPRINTF in string.h for more info. +// +#if !defined(EASTL_EASTDC_VSNPRINTF) + #define EASTL_EASTDC_VSNPRINTF 1 +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_NAME_ENABLED / EASTL_NAME / EASTL_NAME_VAL +// +// Used to wrap debug string names. In a release build, the definition +// goes away. These are present to avoid release build compiler warnings +// and to make code simpler. +// +// Example usage of EASTL_NAME: +// // pName will defined away in a release build and thus prevent compiler warnings. +// void allocator::set_name(const char* EASTL_NAME(pName)) +// { +// #if EASTL_NAME_ENABLED +// mpName = pName; +// #endif +// } +// +// Example usage of EASTL_NAME_VAL: +// // "xxx" is defined to NULL in a release build. +// vector::vector(const allocator_type& allocator = allocator_type(EASTL_NAME_VAL("xxx"))); +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_NAME_ENABLED + //#define EASTL_NAME_ENABLED EASTL_DEBUG + #define EASTL_NAME_ENABLED 0 +#endif + +#ifndef EASTL_NAME + #if EASTL_NAME_ENABLED + #define EASTL_NAME(x) x + #define EASTL_NAME_VAL(x) x + #else + #define EASTL_NAME(x) + #define EASTL_NAME_VAL(x) ((const char*)NULL) + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_DEFAULT_NAME_PREFIX +// +// Defined as a string literal. Defaults to "EASTL". +// This define is used as the default name for EASTL where such a thing is +// referenced in EASTL. For example, if the user doesn't specify an allocator +// name for their deque, it is named "EASTL deque". However, you can override +// this to say "SuperBaseball deque" by changing EASTL_DEFAULT_NAME_PREFIX. +// +// Example usage (which is simply taken from how deque.h uses this define): +// #ifndef EASTL_DEQUE_DEFAULT_NAME +// #define EASTL_DEQUE_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " deque" +// #endif +// +#ifndef EASTL_DEFAULT_NAME_PREFIX + #define EASTL_DEFAULT_NAME_PREFIX "EASTL" +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_ASSERT_ENABLED +// +// Defined as 0 or non-zero. Default is same as EASTL_DEBUG. +// If EASTL_ASSERT_ENABLED is non-zero, then asserts will be executed via +// the assertion mechanism. +// +// Example usage: +// #if EASTL_ASSERT_ENABLED +// EASTL_ASSERT(v.size() > 17); +// #endif +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_ASSERT_ENABLED + #define EASTL_ASSERT_ENABLED EASTL_DEBUG +#endif + +// Developer assert. Helps EASTL developers assert EASTL is coded correctly. +// Normally disabled for users since it validates internal things and not user things. +#ifndef EASTL_DEV_ASSERT_ENABLED + #define EASTL_DEV_ASSERT_ENABLED EASTL_DEV_DEBUG +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_EMPTY_REFERENCE_ASSERT_ENABLED +// +// Defined as 0 or non-zero. Default is same as EASTL_ASSERT_ENABLED. +// This is like EASTL_ASSERT_ENABLED, except it is for empty container +// references. Sometime people like to be able to take a reference to +// the front of the container, but not use it if the container is empty. +// In practice it's often easier and more efficient to do this than to write +// extra code to check if the container is empty. +// +// Example usage: +// template +// inline typename vector::reference +// vector::front() +// { +// #if EASTL_ASSERT_ENABLED +// EASTL_ASSERT(mpEnd > mpBegin); +// #endif +// +// return *mpBegin; +// } +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + #define EASTL_EMPTY_REFERENCE_ASSERT_ENABLED EASTL_ASSERT_ENABLED +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// SetAssertionFailureFunction +// +// Allows the user to set a custom assertion failure mechanism. +// +// Example usage: +// void Assert(const char* pExpression, void* pContext); +// SetAssertionFailureFunction(Assert, this); +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_ASSERTION_FAILURE_DEFINED + #define EASTL_ASSERTION_FAILURE_DEFINED + + namespace eastl + { + typedef void (*EASTL_AssertionFailureFunction)(const char* pExpression, void* pContext); + EASTL_API void SetAssertionFailureFunction(EASTL_AssertionFailureFunction pFunction, void* pContext); + + // These are the internal default functions that implement asserts. + EASTL_API void AssertionFailure(const char* pExpression); + EASTL_API void AssertionFailureFunctionDefault(const char* pExpression, void* pContext); + } +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_ASSERT +// +// Assertion macro. Can be overridden by user with a different value. +// +// Example usage: +// EASTL_ASSERT(intVector.size() < 100); +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_ASSERT + #if EASTL_ASSERT_ENABLED + #define EASTL_ASSERT(expression) \ + EA_DISABLE_VC_WARNING(4127) \ + do { \ + EA_ANALYSIS_ASSUME(expression); \ + (void)((expression) || (eastl::AssertionFailure(#expression), 0)); \ + } while (0) \ + EA_RESTORE_VC_WARNING() + #else + #define EASTL_ASSERT(expression) + #endif +#endif + +// Developer assert. Helps EASTL developers assert EASTL is coded correctly. +// Normally disabled for users since it validates internal things and not user things. +#ifndef EASTL_DEV_ASSERT + #if EASTL_DEV_ASSERT_ENABLED + #define EASTL_DEV_ASSERT(expression) \ + EA_DISABLE_VC_WARNING(4127) \ + do { \ + EA_ANALYSIS_ASSUME(expression); \ + (void)((expression) || (eastl::AssertionFailure(#expression), 0)); \ + } while(0) \ + EA_RESTORE_VC_WARNING() + #else + #define EASTL_DEV_ASSERT(expression) + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_ASSERT_MSG +// +// Example usage: +// EASTL_ASSERT_MSG(false, "detected error condition!"); +// +/////////////////////////////////////////////////////////////////////////////// +#ifndef EASTL_ASSERT_MSG + #if EASTL_ASSERT_ENABLED + #define EASTL_ASSERT_MSG(expression, message) \ + EA_DISABLE_VC_WARNING(4127) \ + do { \ + EA_ANALYSIS_ASSUME(expression); \ + (void)((expression) || (eastl::AssertionFailure(message), 0)); \ + } while (0) \ + EA_RESTORE_VC_WARNING() + #else + #define EASTL_ASSERT_MSG(expression, message) + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_FAIL_MSG +// +// Failure macro. Can be overridden by user with a different value. +// +// Example usage: +// EASTL_FAIL("detected error condition!"); +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_FAIL_MSG + #if EASTL_ASSERT_ENABLED + #define EASTL_FAIL_MSG(message) (eastl::AssertionFailure(message)) + #else + #define EASTL_FAIL_MSG(message) + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_CT_ASSERT / EASTL_CT_ASSERT_NAMED +// +// EASTL_CT_ASSERT is a macro for compile time assertion checks, useful for +// validating *constant* expressions. The advantage over using EASTL_ASSERT +// is that errors are caught at compile time instead of runtime. +// +// Example usage: +// EASTL_CT_ASSERT(sizeof(uint32_t) == 4); +// +/////////////////////////////////////////////////////////////////////////////// + +#define EASTL_CT_ASSERT(expression) static_assert(expression, #expression) + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_CT_ASSERT_MSG +// +// EASTL_CT_ASSERT_MSG is a macro for compile time assertion checks, useful for +// validating *constant* expressions. The advantage over using EASTL_ASSERT +// is that errors are caught at compile time instead of runtime. +// The message must be a string literal. +// +// Example usage: +// EASTL_CT_ASSERT_MSG(sizeof(uint32_t) == 4, "The size of uint32_t must be 4."); +// +/////////////////////////////////////////////////////////////////////////////// + +#define EASTL_CT_ASSERT_MSG(expression, message) static_assert(expression, message) + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_DEBUG_BREAK / EASTL_DEBUG_BREAK_OVERRIDE +// +// This function causes an app to immediately stop under the debugger. +// It is implemented as a macro in order to allow stopping at the site +// of the call. +// +// EASTL_DEBUG_BREAK_OVERRIDE allows one to define EASTL_DEBUG_BREAK directly. +// This is useful in cases where you desire to disable EASTL_DEBUG_BREAK +// but do not wish to (or cannot) define a custom void function() to replace +// EASTL_DEBUG_BREAK callsites. +// +// Example usage: +// EASTL_DEBUG_BREAK(); +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_DEBUG_BREAK_OVERRIDE + #ifndef EASTL_DEBUG_BREAK + #if defined(_MSC_VER) && (_MSC_VER >= 1300) + #define EASTL_DEBUG_BREAK() __debugbreak() // This is a compiler intrinsic which will map to appropriate inlined asm for the platform. + #elif (defined(EA_PROCESSOR_ARM) && !defined(EA_PROCESSOR_ARM64)) && defined(__APPLE__) + #define EASTL_DEBUG_BREAK() asm("trap") + #elif defined(EA_PROCESSOR_ARM64) && defined(__APPLE__) + #include + #include + #define EASTL_DEBUG_BREAK() kill( getpid(), SIGINT ) + #elif defined(EA_PROCESSOR_ARM) && defined(__GNUC__) + #define EASTL_DEBUG_BREAK() asm("BKPT 10") // The 10 is arbitrary. It's just a unique id. + #elif defined(EA_PROCESSOR_ARM) && defined(__ARMCC_VERSION) + #define EASTL_DEBUG_BREAK() __breakpoint(10) + #elif defined(EA_PROCESSOR_POWERPC) // Generic PowerPC. + #define EASTL_DEBUG_BREAK() asm(".long 0") // This triggers an exception by executing opcode 0x00000000. + #elif (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) && defined(EA_ASM_STYLE_INTEL) + #define EASTL_DEBUG_BREAK() { __asm int 3 } + #elif (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) && (defined(EA_ASM_STYLE_ATT) || defined(__GNUC__)) + #define EASTL_DEBUG_BREAK() asm("int3") + #else + void EASTL_DEBUG_BREAK(); // User must define this externally. + #endif + #else + void EASTL_DEBUG_BREAK(); // User must define this externally. + #endif +#else + #ifndef EASTL_DEBUG_BREAK + #if EASTL_DEBUG_BREAK_OVERRIDE == 1 + // define an empty callable to satisfy the call site. + #define EASTL_DEBUG_BREAK ([]{}) + #else + #define EASTL_DEBUG_BREAK EASTL_DEBUG_BREAK_OVERRIDE + #endif + #else + #error EASTL_DEBUG_BREAK is already defined yet you would like to override it. Please ensure no other headers are already defining EASTL_DEBUG_BREAK before this header (config.h) is included + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_ALLOCATOR_COPY_ENABLED +// +// Defined as 0 or 1. Default is 0 (disabled) until some future date. +// If enabled (1) then container operator= copies the allocator from the +// source container. It ideally should be set to enabled but for backwards +// compatibility with older versions of EASTL it is currently set to 0. +// Regardless of whether this value is 0 or 1, this container copy constructs +// or copy assigns allocators. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_ALLOCATOR_COPY_ENABLED + #define EASTL_ALLOCATOR_COPY_ENABLED 0 +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_FIXED_SIZE_TRACKING_ENABLED +// +// Defined as an integer >= 0. Default is same as EASTL_DEBUG. +// If EASTL_FIXED_SIZE_TRACKING_ENABLED is enabled, then fixed +// containers in debug builds track the max count of objects +// that have been in the container. This allows for the tuning +// of fixed container sizes to their minimum required size. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_FIXED_SIZE_TRACKING_ENABLED + #define EASTL_FIXED_SIZE_TRACKING_ENABLED EASTL_DEBUG +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_RTTI_ENABLED +// +// Defined as 0 or 1. Default is 1 if RTTI is supported by the compiler. +// This define exists so that we can use some dynamic_cast operations in the +// code without warning. dynamic_cast is only used if the specifically refers +// to it; EASTL won't do dynamic_cast behind your back. +// +// Example usage: +// #if EASTL_RTTI_ENABLED +// pChildClass = dynamic_cast(pParentClass); +// #endif +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_RTTI_ENABLED + // The VC++ default Standard Library (Dinkumware) disables major parts of RTTI + // (e.g. type_info) if exceptions are disabled, even if RTTI itself is enabled. + // _HAS_EXCEPTIONS is defined by Dinkumware to 0 or 1 (disabled or enabled). + #if defined(EA_COMPILER_NO_RTTI) || (defined(_MSC_VER) && defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && !(defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS)) + #define EASTL_RTTI_ENABLED 0 + #else + #define EASTL_RTTI_ENABLED 1 + #endif +#endif + + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_EXCEPTIONS_ENABLED +// +// Defined as 0 or 1. Default is to follow what the compiler settings are. +// The user can predefine EASTL_EXCEPTIONS_ENABLED to 0 or 1; however, if the +// compiler is set to disable exceptions then EASTL_EXCEPTIONS_ENABLED is +// forced to a value of 0 regardless of the user predefine. +// +// Note that we do not enable EASTL exceptions by default if the compiler +// has exceptions enabled. To enable EASTL_EXCEPTIONS_ENABLED you need to +// manually set it to 1. +// +/////////////////////////////////////////////////////////////////////////////// + +#if !defined(EASTL_EXCEPTIONS_ENABLED) || ((EASTL_EXCEPTIONS_ENABLED == 1) && defined(EA_COMPILER_NO_EXCEPTIONS)) + #define EASTL_EXCEPTIONS_ENABLED 0 +#endif + + + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_STRING_OPT_XXXX +// +// Enables some options / optimizations options that cause the string class +// to behave slightly different from the C++ standard basic_string. These are +// options whereby you can improve performance by avoiding operations that +// in practice may never occur for you. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_STRING_OPT_CHAR_INIT + // Defined as 0 or 1. Default is 1. + // Defines if newly created characters are initialized to 0 or left + // as random values. + // The C++ string standard is to initialize chars to 0. + #define EASTL_STRING_OPT_CHAR_INIT 1 +#endif + +#ifndef EASTL_STRING_OPT_EXPLICIT_CTORS + // Defined as 0 or 1. Default is 0. + // Defines if we should implement explicity in constructors where the C++ + // standard string does not. The advantage of enabling explicit constructors + // is that you can do this: string s = "hello"; in addition to string s("hello"); + // The disadvantage of enabling explicity constructors is that there can be + // silent conversions done which impede performance if the user isn't paying + // attention. + // C++ standard string ctors are not explicit. + #define EASTL_STRING_OPT_EXPLICIT_CTORS 0 +#endif + +#ifndef EASTL_STRING_OPT_LENGTH_ERRORS + // Defined as 0 or 1. Default is equal to EASTL_EXCEPTIONS_ENABLED. + // Defines if we check for string values going beyond kMaxSize + // (a very large value) and throw exections if so. + // C++ standard strings are expected to do such checks. + #define EASTL_STRING_OPT_LENGTH_ERRORS EASTL_EXCEPTIONS_ENABLED +#endif + +#ifndef EASTL_STRING_OPT_RANGE_ERRORS + // Defined as 0 or 1. Default is equal to EASTL_EXCEPTIONS_ENABLED. + // Defines if we check for out-of-bounds references to string + // positions and throw exceptions if so. Well-behaved code shouldn't + // refence out-of-bounds positions and so shouldn't need these checks. + // C++ standard strings are expected to do such range checks. + #define EASTL_STRING_OPT_RANGE_ERRORS EASTL_EXCEPTIONS_ENABLED +#endif + +#ifndef EASTL_STRING_OPT_ARGUMENT_ERRORS + // Defined as 0 or 1. Default is 0. + // Defines if we check for NULL ptr arguments passed to string + // functions by the user and throw exceptions if so. Well-behaved code + // shouldn't pass bad arguments and so shouldn't need these checks. + // Also, some users believe that strings should check for NULL pointers + // in all their arguments and do no-ops if so. This is very debatable. + // C++ standard strings are not required to check for such argument errors. + #define EASTL_STRING_OPT_ARGUMENT_ERRORS 0 +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_ABSTRACT_STRING_ENABLED +// +// Defined as 0 or 1. Default is 0 until abstract string is fully tested. +// Defines whether the proposed replacement for the string module is enabled. +// See bonus/abstract_string.h for more information. +// +#ifndef EASTL_ABSTRACT_STRING_ENABLED + #define EASTL_ABSTRACT_STRING_ENABLED 0 +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_BITSET_SIZE_T +// +// Defined as 0 or 1. Default is 1. +// Controls whether bitset uses size_t or eastl_size_t. +// +#ifndef EASTL_BITSET_SIZE_T + #define EASTL_BITSET_SIZE_T 1 +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_INT128_SUPPORTED +// +// Defined as 0 or 1. +// +#ifndef EASTL_INT128_SUPPORTED + #if defined(EA_COMPILER_INTMAX_SIZE) && (EA_COMPILER_INTMAX_SIZE >= 16) // If the compiler supports int128_t (recent versions of GCC do)... + #define EASTL_INT128_SUPPORTED 1 + #else + #define EASTL_INT128_SUPPORTED 0 + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_DEFAULT_ALLOCATOR_ALIGNED_ALLOCATIONS_SUPPORTED +// +// Defined as 0 or 1. +// Tells if you can use the default EASTL allocator to do aligned allocations, +// which for most uses tells if you can store aligned objects in containers +// that use default allocators. It turns out that when built as a DLL for +// some platforms, EASTL doesn't have a way to do aligned allocations, as it +// doesn't have a heap that supports it. There is a way to work around this +// with dynamically defined allocators, but that's currently a to-do. +// +#ifndef EASTL_DEFAULT_ALLOCATOR_ALIGNED_ALLOCATIONS_SUPPORTED + #if EASTL_DLL + #define EASTL_DEFAULT_ALLOCATOR_ALIGNED_ALLOCATIONS_SUPPORTED 0 + #else + #define EASTL_DEFAULT_ALLOCATOR_ALIGNED_ALLOCATIONS_SUPPORTED 1 + #endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_INT128_DEFINED +// +// Defined as 0 or 1. +// Specifies whether eastl_int128_t/eastl_uint128_t have been typedef'd yet. +// +#ifndef EASTL_INT128_DEFINED + #if EASTL_INT128_SUPPORTED + #define EASTL_INT128_DEFINED 1 + + #if defined(__GNUC__) + typedef __int128_t eastl_int128_t; + typedef __uint128_t eastl_uint128_t; + #else + typedef int128_t eastl_int128_t; // The EAStdC package defines an EA::StdC::int128_t and uint128_t type, + typedef uint128_t eastl_uint128_t; // though they are currently within the EA::StdC namespace. + #endif + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_BITSET_WORD_TYPE_DEFAULT / EASTL_BITSET_WORD_SIZE_DEFAULT +// +// Defined as an integral power of two type, usually uint32_t or uint64_t. +// Specifies the word type that bitset should use internally to implement +// storage. By default this is the platform register word size, but there +// may be reasons to use a different value. +// +// Defines the integral data type used by bitset by default. +// You can override this default on a bitset-by-bitset case by supplying a +// custom bitset WordType template parameter. +// +// The C++ standard specifies that the std::bitset word type be unsigned long, +// but that isn't necessarily the most efficient data type for the given platform. +// We can follow the standard and be potentially less efficient or we can do what +// is more efficient but less like the C++ std::bitset. +// +#if !defined(EASTL_BITSET_WORD_TYPE_DEFAULT) + #if defined(EASTL_BITSET_WORD_SIZE) // EASTL_BITSET_WORD_SIZE is deprecated, but we temporarily support the ability for the user to specify it. Use EASTL_BITSET_WORD_TYPE_DEFAULT instead. + #if (EASTL_BITSET_WORD_SIZE == 4) + #define EASTL_BITSET_WORD_TYPE_DEFAULT uint32_t + #define EASTL_BITSET_WORD_SIZE_DEFAULT 4 + #else + #define EASTL_BITSET_WORD_TYPE_DEFAULT uint64_t + #define EASTL_BITSET_WORD_SIZE_DEFAULT 8 + #endif + #elif (EA_PLATFORM_WORD_SIZE == 16) // EA_PLATFORM_WORD_SIZE is defined in EABase. + #define EASTL_BITSET_WORD_TYPE_DEFAULT uint128_t + #define EASTL_BITSET_WORD_SIZE_DEFAULT 16 + #elif (EA_PLATFORM_WORD_SIZE == 8) + #define EASTL_BITSET_WORD_TYPE_DEFAULT uint64_t + #define EASTL_BITSET_WORD_SIZE_DEFAULT 8 + #elif (EA_PLATFORM_WORD_SIZE == 4) + #define EASTL_BITSET_WORD_TYPE_DEFAULT uint32_t + #define EASTL_BITSET_WORD_SIZE_DEFAULT 4 + #else + #define EASTL_BITSET_WORD_TYPE_DEFAULT uint16_t + #define EASTL_BITSET_WORD_SIZE_DEFAULT 2 + #endif +#endif + + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_LIST_SIZE_CACHE +// +// Defined as 0 or 1. Default is 1. Changed from 0 in version 1.16.01. +// If defined as 1, the list and slist containers (and possibly any additional +// containers as well) keep a member mSize (or similar) variable which allows +// the size() member function to execute in constant time (a.k.a. O(1)). +// There are debates on both sides as to whether it is better to have this +// cached value or not, as having it entails some cost (memory and code). +// To consider: Make list size caching an optional template parameter. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_LIST_SIZE_CACHE + //#define EASTL_LIST_SIZE_CACHE 1 + // Spore doesn't use it + #define EASTL_LIST_SIZE_CACHE 0 +#endif + +#ifndef EASTL_SLIST_SIZE_CACHE + #define EASTL_SLIST_SIZE_CACHE 1 +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_MAX_STACK_USAGE +// +// Defined as an integer greater than zero. Default is 4000. +// There are some places in EASTL where temporary objects are put on the +// stack. A common example of this is in the implementation of container +// swap functions whereby a temporary copy of the container is made. +// There is a problem, however, if the size of the item created on the stack +// is very large. This can happen with fixed-size containers, for example. +// The EASTL_MAX_STACK_USAGE define specifies the maximum amount of memory +// (in bytes) that the given platform/compiler will safely allow on the stack. +// Platforms such as Windows will generally allow larger values than embedded +// systems or console machines, but it is usually a good idea to stick with +// a max usage value that is portable across all platforms, lest the user be +// surprised when something breaks as it is ported to another platform. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_MAX_STACK_USAGE + #define EASTL_MAX_STACK_USAGE 4000 +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_VA_COPY_ENABLED +// +// Defined as 0 or 1. Default is 1 for compilers that need it, 0 for others. +// Some compilers on some platforms implement va_list whereby its contents +// are destroyed upon usage, even if passed by value to another function. +// With these compilers you can use va_copy to save and restore a va_list. +// Known compiler/platforms that destroy va_list contents upon usage include: +// CodeWarrior on PowerPC +// GCC on x86-64 +// However, va_copy is part of the C99 standard and not part of earlier C and +// C++ standards. So not all compilers support it. VC++ doesn't support va_copy, +// but it turns out that VC++ doesn't usually need it on the platforms it supports, +// and va_copy can usually be implemented via memcpy(va_list, va_list) with VC++. +// +// Example usage: +// void Function(va_list arguments) +// { +// #if EASTL_VA_COPY_ENABLED +// va_list argumentsCopy; +// va_copy(argumentsCopy, arguments); +// #endif +// +// #if EASTL_VA_COPY_ENABLED +// va_end(argumentsCopy); +// #endif +// } +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_VA_COPY_ENABLED + #if ((defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__)) && (!defined(__i386__) || defined(__x86_64__)) && !defined(__ppc__) && !defined(__PPC__) && !defined(__PPC64__) + #define EASTL_VA_COPY_ENABLED 1 + #else + #define EASTL_VA_COPY_ENABLED 0 + #endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_OPERATOR_EQUALS_OTHER_ENABLED +// +// Defined as 0 or 1. Default is 0 until such day that it's deemeed safe. +// When enabled, enables operator= for other char types, e.g. for code +// like this: +// eastl::string8 s8; +// eastl::string16 s16; +// s8 = s16; +// This option is considered experimental, and may exist as such for an +// indefinite amount of time. +// +#if !defined(EASTL_OPERATOR_EQUALS_OTHER_ENABLED) + #define EASTL_OPERATOR_EQUALS_OTHER_ENABLED 0 +#endif +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_LIST_PROXY_ENABLED +// +#if !defined(EASTL_LIST_PROXY_ENABLED) + // GCC with -fstrict-aliasing has bugs (or undocumented functionality in their + // __may_alias__ implementation. The compiler gets confused about function signatures. + // VC8 (1400) doesn't need the proxy because it has built-in smart debugging capabilities. + #if defined(EASTL_DEBUG) && !defined(__GNUC__) && (!defined(_MSC_VER) || (_MSC_VER < 1400)) + #define EASTL_LIST_PROXY_ENABLED 1 + #define EASTL_LIST_PROXY_MAY_ALIAS EASTL_MAY_ALIAS + #else + #define EASTL_LIST_PROXY_ENABLED 0 + #define EASTL_LIST_PROXY_MAY_ALIAS + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_STD_ITERATOR_CATEGORY_ENABLED +// +// Defined as 0 or 1. Default is 0. +// If defined as non-zero, EASTL iterator categories (iterator.h's input_iterator_tag, +// forward_iterator_tag, etc.) are defined to be those from std C++ in the std +// namespace. The reason for wanting to enable such a feature is that it allows +// EASTL containers and algorithms to work with std STL containes and algorithms. +// The default value was changed from 1 to 0 in EASL 1.13.03, January 11, 2012. +// The reason for the change was that almost nobody was taking advantage of it and +// it was slowing down compile times for some compilers quite a bit due to them +// having a lot of headers behind . +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_STD_ITERATOR_CATEGORY_ENABLED + #define EASTL_STD_ITERATOR_CATEGORY_ENABLED 0 +#endif + +#if EASTL_STD_ITERATOR_CATEGORY_ENABLED + #define EASTL_ITC_NS std +#else + #define EASTL_ITC_NS eastl +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_VALIDATION_ENABLED +// +// Defined as an integer >= 0. Default is to be equal to EASTL_DEBUG. +// If nonzero, then a certain amount of automatic runtime validation is done. +// Runtime validation is not considered the same thing as asserting that user +// input values are valid. Validation refers to internal consistency checking +// of the validity of containers and their iterators. Validation checking is +// something that often involves significantly more than basic assertion +// checking, and it may sometimes be desirable to disable it. +// This macro would generally be used internally by EASTL. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_VALIDATION_ENABLED + #define EASTL_VALIDATION_ENABLED EASTL_DEBUG +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_VALIDATE_COMPARE +// +// Defined as EASTL_ASSERT or defined away. Default is EASTL_ASSERT if EASTL_VALIDATION_ENABLED is enabled. +// This is used to validate user-supplied comparison functions, particularly for sorting purposes. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_VALIDATE_COMPARE_ENABLED + #define EASTL_VALIDATE_COMPARE_ENABLED EASTL_VALIDATION_ENABLED +#endif + +#if EASTL_VALIDATE_COMPARE_ENABLED + #define EASTL_VALIDATE_COMPARE EASTL_ASSERT +#else + #define EASTL_VALIDATE_COMPARE(expression) +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_VALIDATE_INTRUSIVE_LIST +// +// Defined as an integral value >= 0. Controls the amount of automatic validation +// done by intrusive_list. A value of 0 means no automatic validation is done. +// As of this writing, EASTL_VALIDATE_INTRUSIVE_LIST defaults to 0, as it makes +// the intrusive_list_node become a non-POD, which may be an issue for some code. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_VALIDATE_INTRUSIVE_LIST + #define EASTL_VALIDATE_INTRUSIVE_LIST 0 +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_FORCE_INLINE +// +// Defined as a "force inline" expression or defined away. +// You generally don't need to use forced inlining with the Microsoft and +// Metrowerks compilers, but you may need it with the GCC compiler (any version). +// +// Example usage: +// template +// EASTL_FORCE_INLINE typename vector::size_type +// vector::size() const +// { return mpEnd - mpBegin; } +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_FORCE_INLINE + #define EASTL_FORCE_INLINE EA_FORCE_INLINE +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_MAY_ALIAS +// +// Defined as a macro that wraps the GCC may_alias attribute. This attribute +// has no significance for VC++ because VC++ doesn't support the concept of +// strict aliasing. Users should avoid writing code that breaks strict +// aliasing rules; EASTL_MAY_ALIAS is for cases with no alternative. +// +// Example usage: +// uint32_t value EASTL_MAY_ALIAS; +// +// Example usage: +// typedef uint32_t EASTL_MAY_ALIAS value_type; +// value_type value; +// +#if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 303) && !defined(EA_COMPILER_RVCT) + #define EASTL_MAY_ALIAS __attribute__((__may_alias__)) +#else + #define EASTL_MAY_ALIAS +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_LIKELY / EASTL_UNLIKELY +// +// Defined as a macro which gives a hint to the compiler for branch +// prediction. GCC gives you the ability to manually give a hint to +// the compiler about the result of a comparison, though it's often +// best to compile shipping code with profiling feedback under both +// GCC (-fprofile-arcs) and VC++ (/LTCG:PGO, etc.). However, there +// are times when you feel very sure that a boolean expression will +// usually evaluate to either true or false and can help the compiler +// by using an explicity directive... +// +// Example usage: +// if(EASTL_LIKELY(a == 0)) // Tell the compiler that a will usually equal 0. +// { ... } +// +// Example usage: +// if(EASTL_UNLIKELY(a == 0)) // Tell the compiler that a will usually not equal 0. +// { ... } +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_LIKELY + #if defined(__GNUC__) && (__GNUC__ >= 3) + #define EASTL_LIKELY(x) __builtin_expect(!!(x), true) + #define EASTL_UNLIKELY(x) __builtin_expect(!!(x), false) + #else + #define EASTL_LIKELY(x) (x) + #define EASTL_UNLIKELY(x) (x) + #endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_STD_TYPE_TRAITS_AVAILABLE +// +// Defined as 0 or 1; default is based on auto-detection. +// Specifies whether Standard C++11 support exists. +// Sometimes the auto-detection below fails to work properly and the +// user needs to override it. Does not define whether the compiler provides +// built-in compiler type trait support (e.g. __is_abstract()), as some +// compilers will EASTL_STD_TYPE_TRAITS_AVAILABLE = 0, but have built +// in type trait support. +// +#ifndef EASTL_STD_TYPE_TRAITS_AVAILABLE + /* Disabled because we don't currently need it. + #if defined(_MSC_VER) && (_MSC_VER >= 1500) // VS2008 or later + #pragma warning(push, 0) + #include + #pragma warning(pop) + #if ((defined(_HAS_TR1) && _HAS_TR1) || _MSC_VER >= 1700) // VS2012 (1700) and later has built-in type traits support. + #define EASTL_STD_TYPE_TRAITS_AVAILABLE 1 + #include + #else + #define EASTL_STD_TYPE_TRAITS_AVAILABLE 0 + #endif + + #elif defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003) && !defined(__GCCXML__)) && !defined(EA_COMPILER_NO_STANDARD_CPP_LIBRARY) + #include // This will define __GLIBCXX__ if using GNU's libstdc++ and _LIBCPP_VERSION if using clang's libc++. + + #if defined(EA_COMPILER_CLANG) && !defined(EA_PLATFORM_APPLE) // As of v3.0.0, Apple's clang doesn't support type traits. + // http://clang.llvm.org/docs/LanguageExtensions.html#checking_type_traits + // Clang has some built-in compiler trait support. This support doesn't currently + // directly cover all our type_traits, though the C++ Standard Library that's used + // with clang could fill that in. + #define EASTL_STD_TYPE_TRAITS_AVAILABLE 1 + #endif + + #if !defined(EASTL_STD_TYPE_TRAITS_AVAILABLE) + #if defined(_LIBCPP_VERSION) // This is defined by clang's libc++. + #include + + #elif defined(__GLIBCXX__) && (__GLIBCXX__ >= 20090124) // It's not clear if this is the oldest version that has type traits; probably it isn't. + #define EASTL_STD_TYPE_TRAITS_AVAILABLE 1 + + #if defined(__GXX_EXPERIMENTAL_CXX0X__) // To do: Update this test to include conforming C++11 implementations. + #include + #else + #include + #endif + #else + #define EASTL_STD_TYPE_TRAITS_AVAILABLE 0 + #endif + #endif + + #elif defined(__MSL_CPP__) && (__MSL_CPP__ >= 0x8000) // CodeWarrior compiler. + #define EASTL_STD_TYPE_TRAITS_AVAILABLE 0 + // To do: Implement support for this (via modifying the EASTL type + // traits headers, as CodeWarrior provides this. + #else + #define EASTL_STD_TYPE_TRAITS_AVAILABLE 0 + #endif + */ +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE +// +// Defined as 0 or 1; default is based on auto-detection. +// Specifies whether the compiler provides built-in compiler type trait support +// (e.g. __is_abstract()). Does not specify any details about which traits +// are available or what their standards-compliance is. Nevertheless this is a +// useful macro identifier for our type traits implementation. +// +#ifndef EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE + #if defined(_MSC_VER) && (_MSC_VER >= 1500) // VS2008 or later + #pragma warning(push, 0) + #include + #pragma warning(pop) + #if ((defined(_HAS_TR1) && _HAS_TR1) || _MSC_VER >= 1700) // VS2012 (1700) and later has built-in type traits support. + #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 1 + #else + #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 0 + #endif + #elif defined(EA_COMPILER_CLANG) && defined(__APPLE__) && defined(_CXXCONFIG) // Apple clang but with GCC's libstdc++. + #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 0 + #elif defined(EA_COMPILER_CLANG) + #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 1 + #elif defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003) && !defined(__GCCXML__) + #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 1 + #elif defined(__MSL_CPP__) && (__MSL_CPP__ >= 0x8000) // CodeWarrior compiler. + #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 1 + #else + #define EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE 0 + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_RESET_ENABLED +// +// Defined as 0 or 1; default is 1 for the time being. +// The reset_lose_memory function works the same as reset, as described below. +// +// Specifies whether the container reset functionality is enabled. If enabled +// then ::reset forgets its memory, otherwise it acts as the clear +// function. The reset function is potentially dangerous, as it (by design) +// causes containers to not free their memory. +// This option has no applicability to the bitset::reset function, as bitset +// isn't really a container. Also it has no applicability to the smart pointer +// wrappers (e.g. intrusive_ptr). +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_RESET_ENABLED + #define EASTL_RESET_ENABLED 0 +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_MINMAX_ENABLED +// +// Defined as 0 or 1; default is 1. +// Specifies whether the min and max algorithms are available. +// It may be useful to disable the min and max algorithems because sometimes +// #defines for min and max exist which would collide with EASTL min and max. +// Note that there are already alternative versions of min and max in EASTL +// with the min_alt and max_alt functions. You can use these without colliding +// with min/max macros that may exist. +// +/////////////////////////////////////////////////////////////////////////////// +#ifndef EASTL_MINMAX_ENABLED + #define EASTL_MINMAX_ENABLED 1 +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_NOMINMAX +// +// Defined as 0 or 1; default is 1. +// MSVC++ has #defines for min/max which collide with the min/max algorithm +// declarations. If EASTL_NOMINMAX is defined as 1, then we undefine min and +// max if they are #defined by an external library. This allows our min and +// max definitions in algorithm.h to work as expected. An alternative to +// the enabling of EASTL_NOMINMAX is to #define NOMINMAX in your project +// settings if you are compiling for Windows. +// Note that this does not control the availability of the EASTL min and max +// algorithms; the EASTL_MINMAX_ENABLED configuration parameter does that. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_NOMINMAX + #define EASTL_NOMINMAX 1 +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_STD_CPP_ONLY +// +// Defined as 0 or 1; default is 0. +// Disables the use of compiler language extensions. We use compiler language +// extensions only in the case that they provide some benefit that can't be +// had any other practical way. But sometimes the compiler is set to disable +// language extensions or sometimes one compiler's preprocesor is used to generate +// code for another compiler, and so it's necessary to disable language extension usage. +// +// Example usage: +// #if defined(_MSC_VER) && !EASTL_STD_CPP_ONLY +// enum : size_type { npos = container_type::npos }; // Microsoft extension which results in significantly smaller debug symbols. +// #else +// static const size_type npos = container_type::npos; +// #endif +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_STD_CPP_ONLY + #define EASTL_STD_CPP_ONLY 0 +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_NO_RVALUE_REFERENCES +// +// Defined as 0 or 1. +// This is the same as EABase EA_COMPILER_NO_RVALUE_REFERENCES except that it +// follows the convention of being always defined, as 0 or 1. +/////////////////////////////////////////////////////////////////////////////// +#if !defined(EASTL_NO_RVALUE_REFERENCES) + #if defined(EA_COMPILER_NO_RVALUE_REFERENCES) + #define EASTL_NO_RVALUE_REFERENCES 1 + #else + #define EASTL_NO_RVALUE_REFERENCES 0 + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_MOVE_SEMANTICS_ENABLED +// +// Defined as 0 or 1. +// If enabled then C++11-like functionality with rvalue references and move +// operations is enabled. +/////////////////////////////////////////////////////////////////////////////// +#if !defined(EASTL_MOVE_SEMANTICS_ENABLED) + #if EASTL_NO_RVALUE_REFERENCES // If the compiler doesn't support rvalue references or EASTL is configured to disable them... + #define EASTL_MOVE_SEMANTICS_ENABLED 0 + #else + #define EASTL_MOVE_SEMANTICS_ENABLED 1 + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_VARIADIC_TEMPLATES_ENABLED +// +// Defined as 0 or 1. +// If enabled then C++11-like functionality with variadic templates is enabled. +/////////////////////////////////////////////////////////////////////////////// +#if !defined(EASTL_VARIADIC_TEMPLATES_ENABLED) + #if defined(EA_COMPILER_NO_VARIADIC_TEMPLATES) // If the compiler doesn't support variadic templates + #define EASTL_VARIADIC_TEMPLATES_ENABLED 0 + #else + #define EASTL_VARIADIC_TEMPLATES_ENABLED 1 + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_VARIABLE_TEMPLATES_ENABLED +// +// Defined as 0 or 1. +// If enabled then C++11-like functionality with variable templates is enabled. +/////////////////////////////////////////////////////////////////////////////// +#if !defined(EASTL_VARIABLE_TEMPLATES_ENABLED) + #if((EABASE_VERSION_N < 20605) || defined(EA_COMPILER_NO_VARIABLE_TEMPLATES)) + #define EASTL_VARIABLE_TEMPLATES_ENABLED 0 + #else + #define EASTL_VARIABLE_TEMPLATES_ENABLED 1 + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_HAVE_CPP11_TYPE_TRAITS +// +// Defined as 0 or 1. +// This is the same as EABase EA_HAVE_CPP11_TYPE_TRAITS except that it +// follows the convention of being always defined, as 0 or 1. Note that this +// identifies if the Standard Library has C++11 type traits and not if EASTL +// has its equivalents to C++11 type traits. +/////////////////////////////////////////////////////////////////////////////// +#if !defined(EASTL_HAVE_CPP11_TYPE_TRAITS) + // To do: Change this to use the EABase implementation once we have a few months of testing + // of this and we are sure it works right. Do this at some point after ~January 2014. + #if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 540) // Dinkumware. VS2012+ + #define EASTL_HAVE_CPP11_TYPE_TRAITS 1 + #elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007) // Prior versions of libstdc++ have incomplete support for C++11 type traits. + #define EASTL_HAVE_CPP11_TYPE_TRAITS 1 + #elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1) + #define EASTL_HAVE_CPP11_TYPE_TRAITS 1 + #else + #define EASTL_HAVE_CPP11_TYPE_TRAITS 0 + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EA_COMPILER_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS undef +// +// We need revise this macro to be undefined in some cases, in case the user +// isn't using an updated EABase. +/////////////////////////////////////////////////////////////////////////////// +#if defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 403) // It may in fact be supported by 4.01 or 4.02 but we don't have compilers to test with. + #if defined(EA_COMPILER_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS) + #undef EA_COMPILER_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_NO_RANGE_BASED_FOR_LOOP +// +// Defined as 0 or 1. +// This is the same as EABase EA_COMPILER_NO_RANGE_BASED_FOR_LOOP except that it +// follows the convention of being always defined, as 0 or 1. +/////////////////////////////////////////////////////////////////////////////// +#if !defined(EASTL_NO_RANGE_BASED_FOR_LOOP) + #if defined(EA_COMPILER_NO_RANGE_BASED_FOR_LOOP) + #define EASTL_NO_RANGE_BASED_FOR_LOOP 1 + #else + #define EASTL_NO_RANGE_BASED_FOR_LOOP 0 + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_ALIGN_OF +// +// Determines the alignment of a type. +// +// Example usage: +// size_t alignment = EASTL_ALIGN_OF(int); +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_ALIGN_OF + #if defined(_MSC_VER) && (_MSC_VER < 1700) + // Workaround for this VS 2010 compiler bug: https://connect.microsoft.com/VisualStudio/feedback/details/682695 + #define EASTL_ALIGN_OF(...) ( (sizeof(__VA_ARGS__)*0) + (__alignof(__VA_ARGS__)) ) + #elif !defined(__GNUC__) || (__GNUC__ >= 3) // GCC 2.x doesn't do __alignof correctly all the time. + #define EASTL_ALIGN_OF __alignof + #else + #define EASTL_ALIGN_OF(type) ((size_t)offsetof(struct{ char c; type m; }, m)) + #endif +#endif + + + + +/////////////////////////////////////////////////////////////////////////////// +// eastl_size_t +// +// Defined as an unsigned integer type, usually either size_t or uint32_t. +// Defaults to size_t to match std STL unless the user specifies to use +// uint32_t explicitly via tje EASTL_SIZE_T_32BIT define +// +// Example usage: +// eastl_size_t n = intVector.size(); +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_SIZE_T_32BIT // Defines whether EASTL_SIZE_T uses uint32_t/int32_t as opposed to size_t/ssize_t. + #define EASTL_SIZE_T_32BIT 1 // This makes a difference on 64 bit platforms because they use a 64 bit size_t. +#endif // By default we do the same thing as std STL and use size_t. + +#ifndef EASTL_SIZE_T + #if (EASTL_SIZE_T_32BIT == 0) || (EA_PLATFORM_WORD_SIZE == 4) + #include + #define EASTL_SIZE_T size_t + #define EASTL_SSIZE_T intptr_t + #else + #define EASTL_SIZE_T uint32_t + #define EASTL_SSIZE_T int32_t + #endif +#endif + +typedef EASTL_SIZE_T eastl_size_t; // Same concept as std::size_t. +typedef EASTL_SSIZE_T eastl_ssize_t; // Signed version of eastl_size_t. Concept is similar to Posix's ssize_t. + + + + +/////////////////////////////////////////////////////////////////////////////// +// AddRef / Release +// +// AddRef and Release are used for "intrusive" reference counting. By the term +// "intrusive", we mean that the reference count is maintained by the object +// and not by the user of the object. Given that an object implements referencing +// counting, the user of the object needs to be able to increment and decrement +// that reference count. We do that via the venerable AddRef and Release functions +// which the object must supply. These defines here allow us to specify the name +// of the functions. They could just as well be defined to addref and delref or +// IncRef and DecRef. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTLAddRef + #define EASTLAddRef AddRef +#endif + +#ifndef EASTLRelease + #define EASTLRelease Release +#endif + + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_ALLOCATOR_EXPLICIT_ENABLED +// +// Defined as 0 or 1. Default is 0 for now but ideally would be changed to +// 1 some day. It's 0 because setting it to 1 breaks some existing code. +// This option enables the allocator ctor to be explicit, which avoids +// some undesirable silent conversions, especially with the string class. +// +// Example usage: +// class allocator +// { +// public: +// EASTL_ALLOCATOR_EXPLICIT allocator(const char* pName); +// }; +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_ALLOCATOR_EXPLICIT_ENABLED + #define EASTL_ALLOCATOR_EXPLICIT_ENABLED 0 +#endif + +#if EASTL_ALLOCATOR_EXPLICIT_ENABLED + #define EASTL_ALLOCATOR_EXPLICIT explicit +#else + #define EASTL_ALLOCATOR_EXPLICIT +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_ALLOCATOR_MIN_ALIGNMENT +// +// Defined as an integral power-of-2 that's >= 1. +// Identifies the minimum alignment that EASTL should assume its allocators +// use. There is code within EASTL that decides whether to do a Malloc or +// MallocAligned call and it's typically better if it can use the Malloc call. +// But this requires knowing what the minimum possible alignment is. +#if !defined(EASTL_ALLOCATOR_MIN_ALIGNMENT) + #define EASTL_ALLOCATOR_MIN_ALIGNMENT (EA_PLATFORM_PTR_SIZE * 2) +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_SYSTEM_ALLOCATOR_MIN_ALIGNMENT +// +// Identifies the minimum alignment that EASTL should assume system allocations +// from malloc and new will have. +#if !defined(EASTL_SYSTEM_ALLOCATOR_MIN_ALIGNMENT) + #if defined(EA_PLATFORM_MICROSOFT) || defined(EA_PLATFORM_APPLE) + #define EASTL_SYSTEM_ALLOCATOR_MIN_ALIGNMENT 16 + #else + #define EASTL_SYSTEM_ALLOCATOR_MIN_ALIGNMENT (EA_PLATFORM_PTR_SIZE * 2) + #endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL allocator +// +// The EASTL allocator system allows you to redefine how memory is allocated +// via some defines that are set up here. In the container code, memory is +// allocated via macros which expand to whatever the user has them set to +// expand to. Given that there are multiple allocator systems available, +// this system allows you to configure it to use whatever system you want, +// provided your system meets the requirements of this library. +// The requirements are: +// +// - Must be constructable via a const char* (name) parameter. +// Some uses of allocators won't require this, however. +// - Allocate a block of memory of size n and debug name string. +// - Allocate a block of memory of size n, debug name string, +// alignment a, and offset o. +// - Free memory allocated via either of the allocation functions above. +// - Provide a default allocator instance which can be used if the user +// doesn't provide a specific one. +// +/////////////////////////////////////////////////////////////////////////////// + +// namespace eastl +// { +// class allocator +// { +// allocator(const char* pName = NULL); +// +// void* allocate(size_t n, int flags = 0); +// void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0); +// void deallocate(void* p, size_t n); +// +// const char* get_name() const; +// void set_name(const char* pName); +// }; +// +// allocator* GetDefaultAllocator(); // This is used for anonymous allocations. +// } + +#ifndef EASTLAlloc // To consider: Instead of calling through pAllocator, just go directly to operator new, since that's what allocator does. + #define EASTLAlloc(allocator, n) (allocator).allocate(n); +#endif + +#ifndef EASTLAllocFlags // To consider: Instead of calling through pAllocator, just go directly to operator new, since that's what allocator does. + #define EASTLAllocFlags(allocator, n, flags) (allocator).allocate(n, flags); +#endif + +#ifndef EASTLAllocAligned + #define EASTLAllocAligned(allocator, n, alignment, offset) (allocator).allocate((n), (alignment), (offset)) +#endif + +#ifndef EASTLAllocAlignedFlags + #define EASTLAllocAlignedFlags(allocator, n, alignment, offset, flags) (allocator).allocate((n), (alignment), (offset), (flags)) +#endif + +#ifndef EASTLFree + #define EASTLFree(allocator, p, size) (allocator).deallocate((void*)(p), (size)) // Important to cast to void* as p may be non-const. +#endif + +#ifndef EASTLAllocatorType + #define EASTLAllocatorType eastl::allocator +#endif + +#ifndef EASTLDummyAllocatorType + #define EASTLDummyAllocatorType eastl::dummy_allocator +#endif + +#ifndef EASTLAllocatorDefault + // EASTLAllocatorDefault returns the default allocator instance. This is not a global + // allocator which implements all container allocations but is the allocator that is + // used when EASTL needs to allocate memory internally. There are very few cases where + // EASTL allocates memory internally, and in each of these it is for a sensible reason + // that is documented to behave as such. + #define EASTLAllocatorDefault eastl::GetDefaultAllocator +#endif + + +/// EASTL_ALLOCATOR_DEFAULT_NAME +/// +/// Defines a default allocator name in the absence of a user-provided name. +/// +#ifndef EASTL_ALLOCATOR_DEFAULT_NAME + #define EASTL_ALLOCATOR_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX // Unless the user overrides something, this is "EASTL". +#endif + +/// EASTL_USE_FORWARD_WORKAROUND +/// +/// This is to workaround a compiler bug that we found in VS2013. Update 1 did not fix it. +/// This should be fixed in a future release of VS2013 http://accentuable4.rssing.com/browser.php?indx=3511740&item=15696 +/// +#ifndef EASTL_USE_FORWARD_WORKAROUND + #if defined(_MSC_FULL_VER) && _MSC_FULL_VER == 180021005 || (defined(__EDG_VERSION__) && (__EDG_VERSION__ < 405))// VS2013 initial release + #define EASTL_USE_FORWARD_WORKAROUND 1 + #else + #define EASTL_USE_FORWARD_WORKAROUND 0 + #endif +#endif + +/// EASTL_TUPLE_ENABLED +/// EASTL tuple implementation depends on variadic template support +#if EASTL_VARIADIC_TEMPLATES_ENABLED && !defined(EA_COMPILER_NO_TEMPLATE_ALIASES) + #define EASTL_TUPLE_ENABLED 1 +#else + #define EASTL_TUPLE_ENABLED 0 +#endif + +/// EA_ONCE +/// +/// This is a fix for the EA_ONCE define that's broken in EABase versions prior to 2.00.40 +/// +#ifndef EA_ONCE + #define EA_ONCE() +#endif + + +/// EASTL_FUNCTION_ENABLED +/// +#ifndef EASTL_FUNCTION_ENABLED + #if defined(EA_COMPILER_CPP11_ENABLED) + #define EASTL_FUNCTION_ENABLED 1 + #else + #define EASTL_FUNCTION_ENABLED 0 + #endif +#endif + + +/// EASTL_USER_LITERALS_ENABLED +#ifndef EASTL_USER_LITERALS_ENABLED + #define EASTL_USER_LITERALS_ENABLED 0 +#endif + + +/// EASTL_INLINE_NAMESPACES_ENABLED +#ifndef EASTL_INLINE_NAMESPACES_ENABLED + #define EASTL_INLINE_NAMESPACES_ENABLED 0 +#endif + + +/// EASTL_CORE_ALLOCATOR_ENABLED +#ifndef EASTL_CORE_ALLOCATOR_ENABLED + #define EASTL_CORE_ALLOCATOR_ENABLED 0 +#endif + +/// EASTL_OPENSOURCE +/// This is enabled when EASTL is building built in an "open source" mode. Which is a mode that eliminates code +/// dependencies on other technologies that have not been released publically. +/// EASTL_OPENSOURCE = 0, is the default. +/// EASTL_OPENSOURCE = 1, utilizes technologies that not publically available. +/// +#ifndef EASTL_OPENSOURCE + #define EASTL_OPENSOURCE 0 +#endif + + +/// EASTL_OPTIONAL_ENABLED +#if defined(EA_COMPILER_MSVC_2012) + #define EASTL_OPTIONAL_ENABLED 0 +#elif defined(EA_COMPILER_MSVC_2013) + #define EASTL_OPTIONAL_ENABLED 0 +#elif defined(EA_COMPILER_MSVC_2015) + #define EASTL_OPTIONAL_ENABLED 1 +#elif EASTL_VARIADIC_TEMPLATES_ENABLED && !defined(EA_COMPILER_NO_TEMPLATE_ALIASES) && !defined(EA_COMPILER_NO_DEFAULTED_FUNCTIONS) && defined(EA_COMPILER_CPP11_ENABLED) + #define EASTL_OPTIONAL_ENABLED 1 +#else + #define EASTL_OPTIONAL_ENABLED 0 +#endif + +#endif // Header include guard + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/copy_help.h b/libs/eastl/include/EASTL/internal/copy_help.h new file mode 100644 index 0000000..70ac158 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/copy_help.h @@ -0,0 +1,212 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_COPY_HELP_H +#define EASTL_INTERNAL_COPY_HELP_H + + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include +#include +#include +#include // memcpy, memcmp, memmove + + +namespace eastl +{ + /// move / move_n / move_backward + /// copy / copy_n / copy_backward + /// + /// We want to optimize move, move_n, move_backward, copy, copy_backward, copy_n to do memmove operations + /// when possible. + /// + /// We could possibly use memcpy, though it has stricter overlap requirements than the move and copy + /// algorithms and would require a runtime if/else to choose it over memmove. In particular, memcpy + /// allows no range overlap at all, whereas move/copy allow output end overlap and move_backward/copy_backward + /// allow output begin overlap. Despite this it might be useful to use memcpy for any platforms where + /// memcpy is significantly faster than memmove, and since in most cases the copy/move operation in fact + /// doesn't target overlapping memory and so memcpy would be usable. + /// + /// We can use memmove/memcpy if the following hold true: + /// InputIterator and OutputIterator are of the same type. + /// InputIterator and OutputIterator are of type contiguous_iterator_tag or simply are pointers (the two are virtually synonymous). + /// is_trivially_copyable::value is true. i.e. the constructor T(const T& t) (or T(T&& t) if present) can be replaced by memmove(this, &t, sizeof(T)) + /// + /// copy normally differs from move, but there is a case where copy is the same as move: when copy is + /// used with a move_iterator. We handle that case here by detecting that copy is being done with a + /// move_iterator and redirect it to move (which can take advantage of memmove/memcpy). + /// + /// The generic_iterator class is typically used for wrapping raw memory pointers so they can act like + /// formal iterators. Since pointers provide an opportunity for memmove/memcpy operations, we can + /// detect a generic iterator and use it's wrapped type as a pointer if it happens to be one. + + // Implementation moving copying both trivial and non-trivial data via a lesser iterator than random-access. + template + struct move_and_copy_helper + { + template + static OutputIterator move_or_copy(InputIterator first, InputIterator last, OutputIterator result) + { + for(; first != last; ++result, ++first) + *result = *first; + return result; + } + }; + + // Specialization for copying non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const. + // This specialization converts the random access InputIterator last-first to an integral type. There's simple way for us to take advantage of a random access output iterator, + // as the range is specified by the input instead of the output, and distance(first, last) for a non-random-access iterator is potentially slow. + template <> + struct move_and_copy_helper + { + template + static OutputIterator move_or_copy(InputIterator first, InputIterator last, OutputIterator result) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + + for(difference_type n = (last - first); n > 0; --n, ++first, ++result) + *result = *first; + + return result; + } + }; + + // Specialization for moving non-trivial data via a lesser iterator than random-access. + template + struct move_and_copy_helper + { + template + static OutputIterator move_or_copy(InputIterator first, InputIterator last, OutputIterator result) + { + for(; first != last; ++result, ++first) + *result = eastl::move(*first); + return result; + } + }; + + // Specialization for moving non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const. + template <> + struct move_and_copy_helper + { + template + static OutputIterator move_or_copy(InputIterator first, InputIterator last, OutputIterator result) + { + typedef typename eastl::iterator_traits::difference_type difference_type; + + for(difference_type n = (last - first); n > 0; --n, ++first, ++result) + *result = eastl::move(*first); + + return result; + } + }; + + // Specialization for when we can use memmove/memcpy. See the notes above for what conditions allow this. + template + struct move_and_copy_helper + { + template + static T* move_or_copy(const T* first, const T* last, T* result) + { + // We could use memcpy here if there's no range overlap, but memcpy is rarely much faster than memmove. + return (T*)memmove(result, first, (size_t)((uintptr_t)last - (uintptr_t)first)) + (last - first); + } + }; + + + + template + inline OutputIterator move_and_copy_chooser(InputIterator first, InputIterator last, OutputIterator result) + { + typedef typename eastl::iterator_traits::iterator_category IIC; + typedef typename eastl::iterator_traits::iterator_category OIC; + typedef typename eastl::iterator_traits::value_type value_type_input; + typedef typename eastl::iterator_traits::value_type value_type_output; + + const bool canBeMemmoved = eastl::is_trivially_copyable::value && + eastl::is_same::value && + (eastl::is_pointer::value || eastl::is_same::value) && + (eastl::is_pointer::value || eastl::is_same::value); + + return eastl::move_and_copy_helper::move_or_copy(first, last, result); // Need to chose based on the input iterator tag and not the output iterator tag, because containers accept input ranges of iterator types different than self. + } + + + // We have a second layer of unwrap_iterator calls because the original iterator might be something like move_iterator > (i.e. doubly-wrapped). + template + inline OutputIterator move_and_copy_unwrapper(InputIterator first, InputIterator last, OutputIterator result) + { + return OutputIterator(eastl::move_and_copy_chooser(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), eastl::unwrap_iterator(result))); // Have to convert to OutputIterator because result.base() could be a T* + } + + + /// move + /// + /// After this operation the elements in the moved-from range will still contain valid values of the + /// appropriate type, but not necessarily the same values as before the move. + /// Returns the end of the result range. + /// Note: When moving between containers, the dest range must be valid; this function doesn't resize containers. + /// Note: if result is within [first, last), move_backward must be used instead of move. + /// + /// Example usage: + /// eastl::move(myArray.begin(), myArray.end(), myDestArray.begin()); + /// + /// Reference implementation: + /// template + /// OutputIterator move(InputIterator first, InputIterator last, OutputIterator result) + /// { + /// while(first != last) + /// *result++ = eastl::move(*first++); + /// return result; + /// } + + template + inline OutputIterator move(InputIterator first, InputIterator last, OutputIterator result) + { + return eastl::move_and_copy_unwrapper(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), result); + } + + + /// copy + /// + /// Effects: Copies elements in the range [first, last) into the range [result, result + (last - first)) + /// starting from first and proceeding to last. For each nonnegative integer n < (last - first), + /// performs *(result + n) = *(first + n). + /// + /// Returns: result + (last - first). That is, returns the end of the result. Note that this + /// is different from how memmove/memcpy work, as they return the beginning of the result. + /// + /// Requires: result shall not be in the range [first, last). But the end of the result range + /// may in fact be within the input rante. + /// + /// Complexity: Exactly 'last - first' assignments. + /// + template + inline OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result) + { + const bool isMove = eastl::is_move_iterator::value; EA_UNUSED(isMove); + + return eastl::move_and_copy_unwrapper(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), result); + } +} // namespace eastl + +#endif // Header include guard + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/enable_shared.h b/libs/eastl/include/EASTL/internal/enable_shared.h new file mode 100644 index 0000000..60e9b15 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/enable_shared.h @@ -0,0 +1,77 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_ENABLE_SHARED_H +#define EASTL_INTERNAL_ENABLE_SHARED_H + + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +namespace eastl +{ + + /// enable_shared_from_this + /// + /// This is a helper mixin class that allows you to make any class + /// export a shared_ptr instance that is associated with the class + /// instance. Any class that inherits from this class gets two functions: + /// shared_ptr shared_from_this(); + /// shared_ptr shared_from_this() const; + /// If you call shared_from_this, you get back a shared_ptr that + /// refers to the class. A second call to shared_from_this returns + /// another shared_ptr that is shared with the first one. + /// + /// The trick that happens which is not so obvious here (and which is + /// not mentioned at all in the Boost documentation of their version + /// of this) is that the shared_ptr constructor detects that the + /// class has an enable_shared_from_this mixin and sets up this system + /// automatically for the user. This is done with template tricks. + /// + /// For some additional explanation, see the Boost documentation for + /// their description of their version of enable_shared_from_this. + /// + template + class enable_shared_from_this + { + public: + shared_ptr shared_from_this() + { return shared_ptr(mWeakPtr); } + + shared_ptr shared_from_this() const + { return shared_ptr(mWeakPtr); } + + public: // This is public because the alternative fails on some compilers that we need to support. + mutable weak_ptr mWeakPtr; + + protected: + template friend class shared_ptr; + + EA_CONSTEXPR enable_shared_from_this() EA_NOEXCEPT + { } + + enable_shared_from_this(const enable_shared_from_this&) EA_NOEXCEPT + { } + + enable_shared_from_this& operator=(const enable_shared_from_this&) EA_NOEXCEPT + { return *this; } + + ~enable_shared_from_this() + { } + + }; // enable_shared_from_this + +} // namespace eastl + + +#endif // Header include guard + + + + + + diff --git a/libs/eastl/include/EASTL/internal/fill_help.h b/libs/eastl/include/EASTL/internal/fill_help.h new file mode 100644 index 0000000..86a0e5b --- /dev/null +++ b/libs/eastl/include/EASTL/internal/fill_help.h @@ -0,0 +1,484 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_FILL_HELP_H +#define EASTL_INTERNAL_FILL_HELP_H + + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include + +namespace eastl +{ + // fill + // + // We implement some fill helper functions in order to allow us to optimize it + // where possible. + // + template + struct fill_imp + { + template + static void do_fill(ForwardIterator first, ForwardIterator last, const T& value) + { + // The C++ standard doesn't specify whether we need to create a temporary + // or not, but all std STL implementations are written like what we have here. + for(; first != last; ++first) + *first = value; + } + }; + + template <> + struct fill_imp + { + template + static void do_fill(ForwardIterator first, ForwardIterator last, const T& value) + { + typedef typename eastl::iterator_traits::value_type value_type; + // We create a temp and fill from that because value might alias to the + // destination range and so the compiler would be forced into generating + // less efficient code. + for(const T temp = value; first != last; ++first) + { + EA_UNUSED(temp); + *first = static_cast(temp); + } + } + }; + + /// fill + /// + /// fill is like memset in that it assigns a single value repeatedly to a + /// destination range. It allows for any type of iterator (not just an array) + /// and the source value can be any type, not just a byte. + /// Note that the source value (which is a reference) can come from within + /// the destination range. + /// + /// Effects: Assigns value through all the iterators in the range [first, last). + /// + /// Complexity: Exactly 'last - first' assignments. + /// + /// Note: The C++ standard doesn't specify anything about the value parameter + /// coming from within the first-last range. All std STL implementations act + /// as if the standard specifies that value must not come from within this range. + /// + template + inline void fill(ForwardIterator first, ForwardIterator last, const T& value) + { + eastl::fill_imp< is_scalar::value >::do_fill(first, last, value); + + // Possibly better implementation, as it will deal with small PODs as well as scalars: + // bEasyCopy is true if the type has a trivial constructor (e.g. is a POD) and if + // it is small. Thus any built-in type or any small user-defined struct will qualify. + //const bool bEasyCopy = eastl::type_and::value, + // eastl::integral_constant::value; + //eastl::fill_imp::do_fill(first, last, value); + + } + + #if(defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) + #if defined(EA_PROCESSOR_X86_64) + template + inline void fill(uint64_t* first, uint64_t* last, Value c) + { + uintptr_t count = (uintptr_t)(last - first); + uint64_t value = (uint64_t)(c); + + __asm__ __volatile__ ("cld\n\t" + "rep stosq\n\t" + : "+c" (count), "+D" (first), "=m" (first) + : "a" (value) + : "cc" ); + } + + + template + inline void fill(int64_t* first, int64_t* last, Value c) + { + uintptr_t count = (uintptr_t)(last - first); + int64_t value = (int64_t)(c); + + __asm__ __volatile__ ("cld\n\t" + "rep stosq\n\t" + : "+c" (count), "+D" (first), "=m" (first) + : "a" (value) + : "cc" ); + } + #endif + + template + inline void fill(uint32_t* first, uint32_t* last, Value c) + { + uintptr_t count = (uintptr_t)(last - first); + uint32_t value = (uint32_t)(c); + + __asm__ __volatile__ ("cld\n\t" + "rep stosl\n\t" + : "+c" (count), "+D" (first), "=m" (first) + : "a" (value) + : "cc" ); + } + + + template + inline void fill(int32_t* first, int32_t* last, Value c) + { + uintptr_t count = (uintptr_t)(last - first); + int32_t value = (int32_t)(c); + + __asm__ __volatile__ ("cld\n\t" + "rep stosl\n\t" + : "+c" (count), "+D" (first), "=m" (first) + : "a" (value) + : "cc" ); + } + + + template + inline void fill(uint16_t* first, uint16_t* last, Value c) + { + uintptr_t count = (uintptr_t)(last - first); + uint16_t value = (uint16_t)(c); + + __asm__ __volatile__ ("cld\n\t" + "rep stosw\n\t" + : "+c" (count), "+D" (first), "=m" (first) + : "a" (value) + : "cc" ); + } + + + template + inline void fill(int16_t* first, int16_t* last, Value c) + { + uintptr_t count = (uintptr_t)(last - first); + int16_t value = (int16_t)(c); + + __asm__ __volatile__ ("cld\n\t" + "rep stosw\n\t" + : "+c" (count), "+D" (first), "=m" (first) + : "a" (value) + : "cc" ); + } + + #elif defined(EA_COMPILER_MICROSOFT) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) + #if defined(EA_PROCESSOR_X86_64) + template + inline void fill(uint64_t* first, uint64_t* last, Value c) + { + __stosq(first, (uint64_t)c, (size_t)(last - first)); + } + + template + inline void fill(int64_t* first, int64_t* last, Value c) + { + __stosq((uint64_t*)first, (uint64_t)c, (size_t)(last - first)); + } + #endif + + template + inline void fill(uint32_t* first, uint32_t* last, Value c) + { + __stosd((unsigned long*)first, (unsigned long)c, (size_t)(last - first)); + } + + template + inline void fill(int32_t* first, int32_t* last, Value c) + { + __stosd((unsigned long*)first, (unsigned long)c, (size_t)(last - first)); + } + + template + inline void fill(uint16_t* first, uint16_t* last, Value c) + { + __stosw(first, (uint16_t)c, (size_t)(last - first)); + } + + template + inline void fill(int16_t* first, int16_t* last, Value c) + { + __stosw((uint16_t*)first, (uint16_t)c, (size_t)(last - first)); + } + #endif + + + inline void fill(char* first, char* last, const char& c) // It's debateable whether we should use 'char& c' or 'char c' here. + { + memset(first, (unsigned char)c, (size_t)(last - first)); + } + + inline void fill(char* first, char* last, const int c) // This is used for cases like 'fill(first, last, 0)'. + { + memset(first, (unsigned char)c, (size_t)(last - first)); + } + + inline void fill(unsigned char* first, unsigned char* last, const unsigned char& c) + { + memset(first, (unsigned char)c, (size_t)(last - first)); + } + + inline void fill(unsigned char* first, unsigned char* last, const int c) + { + memset(first, (unsigned char)c, (size_t)(last - first)); + } + + inline void fill(signed char* first, signed char* last, const signed char& c) + { + memset(first, (unsigned char)c, (size_t)(last - first)); + } + + inline void fill(signed char* first, signed char* last, const int c) + { + memset(first, (unsigned char)c, (size_t)(last - first)); + } + + #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__ICL) // ICL = Intel compiler + inline void fill(bool* first, bool* last, const bool& b) + { + memset(first, (char)b, (size_t)(last - first)); + } + #endif + + + + + // fill_n + // + // We implement some fill helper functions in order to allow us to optimize it + // where possible. + // + template + struct fill_n_imp + { + template + static OutputIterator do_fill(OutputIterator first, Size n, const T& value) + { + for(; n-- > 0; ++first) + *first = value; + return first; + } + }; + + template <> + struct fill_n_imp + { + template + static OutputIterator do_fill(OutputIterator first, Size n, const T& value) + { + typedef typename eastl::iterator_traits::value_type value_type; + + // We create a temp and fill from that because value might alias to + // the destination range and so the compiler would be forced into + // generating less efficient code. + for(const T temp = value; n-- > 0; ++first) + *first = static_cast(temp); + return first; + } + }; + + /// fill_n + /// + /// The fill_n function is very much like memset in that a copies a source value + /// n times into a destination range. The source value may come from within + /// the destination range. + /// + /// Effects: Assigns value through all the iterators in the range [first, first + n). + /// + /// Complexity: Exactly n assignments. + /// + template + OutputIterator fill_n(OutputIterator first, Size n, const T& value) + { + #ifdef _MSC_VER // VC++ up to and including VC8 blow up when you pass a 64 bit scalar to the do_fill function. + return eastl::fill_n_imp< is_scalar::value && (sizeof(T) <= sizeof(uint32_t)) >::do_fill(first, n, value); + #else + return eastl::fill_n_imp< is_scalar::value >::do_fill(first, n, value); + #endif + } + + template + inline char* fill_n(char* first, Size n, const char& c) + { + return (char*)memset(first, (char)c, (size_t)n) + n; + } + + template + inline unsigned char* fill_n(unsigned char* first, Size n, const unsigned char& c) + { + return (unsigned char*)memset(first, (unsigned char)c, (size_t)n) + n; + } + + template + inline signed char* fill_n(signed char* first, Size n, const signed char& c) + { + return (signed char*)memset(first, (signed char)c, n) + (size_t)n; + } + + #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__ICL) // ICL = Intel compiler + template + inline bool* fill_n(bool* first, Size n, const bool& b) + { + return (bool*)memset(first, (char)b, n) + (size_t)n; + } + #endif + + #if(defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) + #if defined(EA_PROCESSOR_X86_64) + template + inline uint64_t* fill_n(uint64_t* first, Size n, Value c) + { + uintptr_t count = (uintptr_t)(n); + uint64_t value = (uint64_t)(c); + + __asm__ __volatile__ ("cld\n\t" + "rep stosq\n\t" + : "+c" (count), "+D" (first), "=m" (first) + : "a" (value) + : "cc" ); + return first; // first is updated by the code above. + } + + + template + inline int64_t* fill_n(int64_t* first, Size n, Value c) + { + uintptr_t count = (uintptr_t)(n); + int64_t value = (int64_t)(c); + + __asm__ __volatile__ ("cld\n\t" + "rep stosq\n\t" + : "+c" (count), "+D" (first), "=m" (first) + : "a" (value) + : "cc" ); + return first; // first is updated by the code above. + } + #endif + + template + inline uint32_t* fill_n(uint32_t* first, Size n, Value c) + { + uintptr_t count = (uintptr_t)(n); + uint32_t value = (uint32_t)(c); + + __asm__ __volatile__ ("cld\n\t" + "rep stosl\n\t" + : "+c" (count), "+D" (first), "=m" (first) + : "a" (value) + : "cc" ); + return first; // first is updated by the code above. + } + + + template + inline int32_t* fill_n(int32_t* first, Size n, Value c) + { + uintptr_t count = (uintptr_t)(n); + int32_t value = (int32_t)(c); + + __asm__ __volatile__ ("cld\n\t" + "rep stosl\n\t" + : "+c" (count), "+D" (first), "=m" (first) + : "a" (value) + : "cc" ); + return first; // first is updated by the code above. + } + + + template + inline uint16_t* fill_n(uint16_t* first, Size n, Value c) + { + uintptr_t count = (uintptr_t)(n); + uint16_t value = (uint16_t)(c); + + __asm__ __volatile__ ("cld\n\t" + "rep stosw\n\t" + : "+c" (count), "+D" (first), "=m" (first) + : "a" (value) + : "cc" ); + return first; // first is updated by the code above. + } + + + template + inline int16_t* fill_n(int16_t* first, Size n, Value c) + { + uintptr_t count = (uintptr_t)(n); + int16_t value = (int16_t)(c); + + __asm__ __volatile__ ("cld\n\t" + "rep stosw\n\t" + : "+c" (count), "+D" (first), "=m" (first) + : "a" (value) + : "cc" ); + return first; // first is updated by the code above. + } + + #elif defined(EA_COMPILER_MICROSOFT) && (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) + #if defined(EA_PROCESSOR_X86_64) + template + inline uint64_t* fill_n(uint64_t* first, Size n, Value c) + { + __stosq(first, (uint64_t)c, (size_t)n); + return first + n; + } + + template + inline int64_t* fill_n(int64_t* first, Size n, Value c) + { + __stosq((uint64_t*)first, (uint64_t)c, (size_t)n); + return first + n; + } + #endif + + template + inline uint32_t* fill_n(uint32_t* first, Size n, Value c) + { + __stosd((unsigned long*)first, (unsigned long)c, (size_t)n); + return first + n; + } + + template + inline int32_t* fill_n(int32_t* first, Size n, Value c) + { + __stosd((unsigned long*)first, (unsigned long)c, (size_t)n); + return first + n; + } + + template + inline uint16_t* fill_n(uint16_t* first, Size n, Value c) + { + __stosw(first, (uint16_t)c, (size_t)n); + return first + n; + } + + template + inline int16_t* fill_n(int16_t* first, Size n, Value c) + { + __stosw((uint16_t*)first, (uint16_t)c, (size_t)n); + return first + n; + } + #endif + +} // namespace eastl + +#endif // Header include guard + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/fixed_pool.h b/libs/eastl/include/EASTL/internal/fixed_pool.h new file mode 100644 index 0000000..b8f8dc1 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/fixed_pool.h @@ -0,0 +1,1635 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements the following +// aligned_buffer +// fixed_pool_base +// fixed_pool +// fixed_pool_with_overflow +// fixed_hashtable_allocator +// fixed_vector_allocator +// fixed_swap +// +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_FIXED_POOL_H +#define EASTL_INTERNAL_FIXED_POOL_H + + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + #pragma warning(push, 0) + #include + #pragma warning(pop) +#else + #include +#endif + +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4275) // non dll-interface class used as base for DLL-interface classkey 'identifier' +#endif + + +namespace eastl +{ + + /// EASTL_FIXED_POOL_DEFAULT_NAME + /// + /// Defines a default allocator name in the absence of a user-provided name. + /// + #ifndef EASTL_FIXED_POOL_DEFAULT_NAME + #define EASTL_FIXED_POOL_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_pool" // Unless the user overrides something, this is "EASTL fixed_pool". + #endif + + + + /////////////////////////////////////////////////////////////////////////// + // aligned_buffer + /////////////////////////////////////////////////////////////////////////// + + /// aligned_buffer + /// + /// This is useful for creating a buffer of the same size and alignment + /// of a given struct or class. This is useful for creating memory pools + /// that support both size and alignment requirements of stored objects + /// but without wasting space in over-allocating. + /// + /// Note that we implement this via struct specializations, as some + /// compilers such as VC++ do not support specification of alignments + /// in any way other than via an integral constant. + /// + /// Example usage: + /// struct Widget{ }; // This class has a given size and alignment. + /// + /// Declare a char buffer of equal size and alignment to Widget. + /// aligned_buffer mWidgetBuffer; + /// + /// Declare an array this time. + /// aligned_buffer mWidgetArray[15]; + /// + typedef char EASTL_MAY_ALIAS aligned_buffer_char; + + template + struct aligned_buffer { aligned_buffer_char buffer[size]; }; + + template + struct aligned_buffer { EA_PREFIX_ALIGN(2) aligned_buffer_char buffer[size] EA_POSTFIX_ALIGN(2); }; + + template + struct aligned_buffer { EA_PREFIX_ALIGN(4) aligned_buffer_char buffer[size] EA_POSTFIX_ALIGN(4); }; + + template + struct aligned_buffer { EA_PREFIX_ALIGN(8) aligned_buffer_char buffer[size] EA_POSTFIX_ALIGN(8); }; + + template + struct aligned_buffer { EA_PREFIX_ALIGN(16) aligned_buffer_char buffer[size] EA_POSTFIX_ALIGN(16); }; + + template + struct aligned_buffer { EA_PREFIX_ALIGN(32) aligned_buffer_char buffer[size] EA_POSTFIX_ALIGN(32); }; + + template + struct aligned_buffer { EA_PREFIX_ALIGN(64) aligned_buffer_char buffer[size] EA_POSTFIX_ALIGN(64); }; + + template + struct aligned_buffer { EA_PREFIX_ALIGN(128) aligned_buffer_char buffer[size] EA_POSTFIX_ALIGN(128); }; + + template + struct aligned_buffer { EA_PREFIX_ALIGN(256) aligned_buffer_char buffer[size] EA_POSTFIX_ALIGN(256); }; + + template + struct aligned_buffer { EA_PREFIX_ALIGN(512) aligned_buffer_char buffer[size] EA_POSTFIX_ALIGN(512); }; + + template + struct aligned_buffer { EA_PREFIX_ALIGN(1024) aligned_buffer_char buffer[size] EA_POSTFIX_ALIGN(1024); }; + + template + struct aligned_buffer { EA_PREFIX_ALIGN(2048) aligned_buffer_char buffer[size] EA_POSTFIX_ALIGN(2048); }; + + template + struct aligned_buffer { EA_PREFIX_ALIGN(4096) aligned_buffer_char buffer[size] EA_POSTFIX_ALIGN(4096); }; + + + + + /////////////////////////////////////////////////////////////////////////// + // fixed_pool_base + /////////////////////////////////////////////////////////////////////////// + + /// fixed_pool_base + /// + /// This is a base class for the implementation of fixed-size pools. + /// In particular, the fixed_pool and fixed_pool_with_overflow classes + /// are based on fixed_pool_base. + /// + struct fixed_pool_base + { + public: + /// fixed_pool_base + /// + fixed_pool_base(void* pMemory = NULL) + : mpHead((Link*)pMemory) + , mpNext((Link*)pMemory) + , mpCapacity((Link*)pMemory) + , mnNodeSize(0) // This is normally set in the init function. + { + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + mnCurrentSize = 0; + mnPeakSize = 0; + #endif + } + + + /// fixed_pool_base + /// + // Disabled because the default is sufficient. While it normally makes no sense to deep copy + // this data, our usage of this class is such that this is OK and wanted. + // + // fixed_pool_base(const fixed_pool_base& x) + // { + // } + + + /// operator= + /// + fixed_pool_base& operator=(const fixed_pool_base&) + { + // By design we do nothing. We don't attempt to deep-copy member data. + return *this; + } + + + /// init + /// + /// Initializes a fixed_pool with a given set of parameters. + /// You cannot call this function twice else the resulting + /// behaviour will be undefined. You can only call this function + /// after constructing the fixed_pool with the default constructor. + /// + EASTL_API void init(void* pMemory, size_t memorySize, size_t nodeSize, + size_t alignment, size_t alignmentOffset = 0); + + + /// peak_size + /// + /// Returns the maximum number of outstanding allocations there have been + /// at any one time. This represents a high water mark for the allocation count. + /// + size_t peak_size() const + { + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + return mnPeakSize; + #else + return 0; + #endif + } + + + /// can_allocate + /// + /// Returns true if there are any free links. + /// + bool can_allocate() const + { + return (mpHead != NULL) || (mpNext != mpCapacity); + } + + public: + /// Link + /// Implements a singly-linked list. + struct Link + { + Link* mpNext; + }; + + Link* mpHead; + Link* mpNext; + Link* mpCapacity; + size_t mnNodeSize; + + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + uint32_t mnCurrentSize; /// Current number of allocated nodes. + uint32_t mnPeakSize; /// Max number of allocated nodes at any one time. + #endif + + }; // fixed_pool_base + + + + + + /////////////////////////////////////////////////////////////////////////// + // fixed_pool + /////////////////////////////////////////////////////////////////////////// + + /// fixed_pool + /// + /// Implements a simple fixed pool allocator for use by fixed-size containers. + /// This is not a generic eastl allocator which can be plugged into an arbitrary + /// eastl container, as it simplifies some functions are arguments for the + /// purpose of efficiency. + /// + class EASTL_API fixed_pool : public fixed_pool_base + { + public: + /// fixed_pool + /// + /// Default constructor. User usually will want to call init() after + /// constructing via this constructor. The pMemory argument is for the + /// purposes of temporarily storing a pointer to the buffer to be used. + /// Even though init may have a pMemory argument, this arg is useful + /// for temporary storage, as per copy construction. + /// + fixed_pool(void* pMemory = NULL) + : fixed_pool_base(pMemory) + { + } + + + /// fixed_pool + /// + /// Constructs a fixed_pool with a given set of parameters. + /// + fixed_pool(void* pMemory, size_t memorySize, size_t nodeSize, + size_t alignment, size_t alignmentOffset = 0) + { + init(pMemory, memorySize, nodeSize, alignment, alignmentOffset); + } + + + /// fixed_pool + /// + // Disabled because the default is sufficient. While it normally makes no sense to deep copy + // this data, our usage of this class is such that this is OK and wanted. + // + // fixed_pool(const fixed_pool& x) + // { + // } + + + /// operator= + /// + fixed_pool& operator=(const fixed_pool&) + { + // By design we do nothing. We don't attempt to deep-copy member data. + return *this; + } + + + /// allocate + /// + /// Allocates a new object of the size specified upon class initialization. + /// Returns NULL if there is no more memory. + /// + void* allocate() + { + Link* pLink = mpHead; + + if(pLink) // If we have space... + { + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + if(++mnCurrentSize > mnPeakSize) + mnPeakSize = mnCurrentSize; + #endif + + mpHead = pLink->mpNext; + return pLink; + } + else + { + // If there's no free node in the free list, just + // allocate another from the reserved memory area + + if(mpNext != mpCapacity) + { + pLink = mpNext; + + mpNext = reinterpret_cast(reinterpret_cast(mpNext) + mnNodeSize); + + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + if(++mnCurrentSize > mnPeakSize) + mnPeakSize = mnCurrentSize; + #endif + + return pLink; + } + + return NULL; + } + } + + void* allocate(size_t /*alignment*/, size_t /*offset*/) + { + return allocate(); + } + + /// deallocate + /// + /// Frees the given object which was allocated by allocate(). + /// If the given node was not allocated by allocate() then the behaviour + /// is undefined. + /// + void deallocate(void* p) + { + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + --mnCurrentSize; + #endif + + ((Link*)p)->mpNext = mpHead; + mpHead = ((Link*)p); + } + + + using fixed_pool_base::can_allocate; + + + const char* get_name() const + { + return EASTL_FIXED_POOL_DEFAULT_NAME; + } + + + void set_name(const char*) + { + // Nothing to do. We don't allocate memory. + } + + }; // fixed_pool + + + + + + /////////////////////////////////////////////////////////////////////////// + // fixed_pool_with_overflow + /////////////////////////////////////////////////////////////////////////// + + /// fixed_pool_with_overflow + /// + template + class fixed_pool_with_overflow : public fixed_pool_base + { + public: + typedef OverflowAllocator overflow_allocator_type; + + + fixed_pool_with_overflow(void* pMemory = NULL) + : fixed_pool_base(pMemory), + mOverflowAllocator(EASTL_FIXED_POOL_DEFAULT_NAME) + { + // Leave mpPoolBegin, mpPoolEnd uninitialized. + } + + + fixed_pool_with_overflow(void* pMemory, const overflow_allocator_type& allocator) + : fixed_pool_base(pMemory), + mOverflowAllocator(allocator) + { + // Leave mpPoolBegin, mpPoolEnd uninitialized. + } + + + fixed_pool_with_overflow(void* pMemory, size_t memorySize, size_t nodeSize, + size_t alignment, size_t alignmentOffset = 0) + : mOverflowAllocator(EASTL_FIXED_POOL_DEFAULT_NAME) + { + fixed_pool_base::init(pMemory, memorySize, nodeSize, alignment, alignmentOffset); + + mpPoolBegin = pMemory; + } + + + fixed_pool_with_overflow(void* pMemory, size_t memorySize, size_t nodeSize, + size_t alignment, size_t alignmentOffset, + const overflow_allocator_type& allocator) + : mOverflowAllocator(allocator) + { + fixed_pool_base::init(pMemory, memorySize, nodeSize, alignment, alignmentOffset); + + mpPoolBegin = pMemory; + } + + + // Disabled because the default is sufficient. While it normally makes no sense to deep copy + // this data, our usage of this class is such that this is OK and wanted. + // + //fixed_pool_with_overflow(const fixed_pool_with_overflow& x) + //{ + // ... + //} + + + fixed_pool_with_overflow& operator=(const fixed_pool_with_overflow& x) + { + #if EASTL_ALLOCATOR_COPY_ENABLED + mOverflowAllocator = x.mOverflowAllocator; + #else + (void)x; + #endif + + return *this; + } + + + void init(void* pMemory, size_t memorySize, size_t nodeSize, + size_t alignment, size_t alignmentOffset = 0) + { + fixed_pool_base::init(pMemory, memorySize, nodeSize, alignment, alignmentOffset); + + mpPoolBegin = pMemory; + } + + + void* allocate() + { + void* p = NULL; + Link* pLink = mpHead; + + if(pLink) + { + // Unlink from chain + p = pLink; + mpHead = pLink->mpNext; + } + else + { + // If there's no free node in the free list, just + // allocate another from the reserved memory area + + if(mpNext != mpCapacity) + { + p = pLink = mpNext; + mpNext = reinterpret_cast(reinterpret_cast(mpNext) + mnNodeSize); + } + else + p = mOverflowAllocator.allocate(mnNodeSize); + } + + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + if(p && (++mnCurrentSize > mnPeakSize)) + mnPeakSize = mnCurrentSize; + #endif + + return p; + } + + + void* allocate(size_t alignment, size_t alignmentOffset) + { + void* p = NULL; + Link* pLink = mpHead; + + if (pLink) + { + // Unlink from chain + p = pLink; + mpHead = pLink->mpNext; + } + else + { + // If there's no free node in the free list, just + // allocate another from the reserved memory area + + if (mpNext != mpCapacity) + { + p = pLink = mpNext; + mpNext = reinterpret_cast(reinterpret_cast(mpNext)+mnNodeSize); + } + else + { + p = allocate_memory(mOverflowAllocator, mnNodeSize, alignment, alignmentOffset); + EASTL_ASSERT_MSG(p != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + } + + } + + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + if (p && (++mnCurrentSize > mnPeakSize)) + mnPeakSize = mnCurrentSize; + #endif + + return p; + } + + void deallocate(void* p) + { + #if EASTL_FIXED_SIZE_TRACKING_ENABLED + --mnCurrentSize; + #endif + + if((p >= mpPoolBegin) && (p < mpCapacity)) + { + ((Link*)p)->mpNext = mpHead; + mpHead = ((Link*)p); + } + else + mOverflowAllocator.deallocate(p, (size_t)mnNodeSize); + } + + + using fixed_pool_base::can_allocate; + + + const char* get_name() const + { + return mOverflowAllocator.get_name(); + } + + + void set_name(const char* pName) + { + mOverflowAllocator.set_name(pName); + } + + + const overflow_allocator_type& get_overflow_allocator() const + { + return mOverflowAllocator; + } + + + overflow_allocator_type& get_overflow_allocator() + { + return mOverflowAllocator; + } + + + void set_overflow_allocator(const overflow_allocator_type& overflowAllocator) + { + mOverflowAllocator = overflowAllocator; + } + public: + OverflowAllocator mOverflowAllocator; + void* mpPoolBegin; // Ideally we wouldn't need this member variable. he problem is that the information about the pool buffer and object size is stored in the owning container and we can't have access to it without increasing the amount of code we need and by templating more code. It may turn out that simply storing data here is smaller in the end. + + }; // fixed_pool_with_overflow + + + + + + /////////////////////////////////////////////////////////////////////////// + // fixed_node_allocator + /////////////////////////////////////////////////////////////////////////// + + /// fixed_node_allocator + /// + /// Note: This class was previously named fixed_node_pool, but was changed because this name + /// was inconsistent with the other allocators here which ended with _allocator. + /// + /// Implements a fixed_pool with a given node count, alignment, and alignment offset. + /// fixed_node_allocator is like fixed_pool except it is templated on the node type instead + /// of being a generic allocator. All it does is pass allocations through to + /// the fixed_pool base. This functionality is separate from fixed_pool because there + /// are other uses for fixed_pool. + /// + /// We template on kNodeSize instead of node_type because the former allows for the + /// two different node_types of the same size to use the same template implementation. + /// + /// Template parameters: + /// nodeSize The size of the object to allocate. + /// nodeCount The number of objects the pool contains. + /// nodeAlignment The alignment of the objects to allocate. + /// nodeAlignmentOffset The alignment offset of the objects to allocate. + /// bEnableOverflow Whether or not we should use the overflow heap if our object pool is exhausted. + /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. + /// + template + class fixed_node_allocator + { + public: + typedef typename type_select, fixed_pool>::type pool_type; + typedef fixed_node_allocator this_type; + typedef OverflowAllocator overflow_allocator_type; + + enum + { + kNodeSize = nodeSize, + kNodeCount = nodeCount, + kNodesSize = nodeCount * nodeSize, // Note that the kBufferSize calculation assumes that the compiler sets sizeof(T) to be a multiple alignof(T), and so sizeof(T) is always >= alignof(T). + kBufferSize = kNodesSize + ((nodeAlignment > 1) ? nodeSize-1 : 0) + nodeAlignmentOffset, + kNodeAlignment = nodeAlignment, + kNodeAlignmentOffset = nodeAlignmentOffset + }; + + public: + pool_type mPool; + + public: + //fixed_node_allocator(const char* pName) + //{ + // mPool.set_name(pName); + //} + + + fixed_node_allocator(void* pNodeBuffer) + : mPool(pNodeBuffer, kNodesSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset) + { + } + + + fixed_node_allocator(void* pNodeBuffer, const overflow_allocator_type& allocator) + : mPool(pNodeBuffer, kNodesSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset, allocator) + { + } + + + /// fixed_node_allocator + /// + /// Note that we are copying x.mpHead to our own fixed_pool. This at first may seem + /// broken, as fixed pools cannot take over ownership of other fixed pools' memory. + /// However, we declare that this copy ctor can only ever be safely called when + /// the user has intentionally pre-seeded the source with the destination pointer. + /// This is somewhat playing with fire, but it allows us to get around chicken-and-egg + /// problems with containers being their own allocators, without incurring any memory + /// costs or extra code costs. There's another reason for this: we very strongly want + /// to avoid full copying of instances of fixed_pool around, especially via the stack. + /// Larger pools won't even be able to fit on many machine's stacks. So this solution + /// is also a mechanism to prevent that situation from existing and being used. + /// Perhaps some day we'll find a more elegant yet costless way around this. + /// + fixed_node_allocator(const this_type& x) + : mPool(x.mPool.mpNext, kNodesSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset, x.mPool.mOverflowAllocator) + { + } + + + this_type& operator=(const this_type& x) + { + mPool = x.mPool; + return *this; + } + + + void* allocate(size_t n, int /*flags*/ = 0) + { + (void)n; + EASTL_ASSERT(n == kNodeSize); + return mPool.allocate(); + } + + + void* allocate(size_t n, size_t alignment, size_t offset, int /*flags*/ = 0) + { + (void)n; + EASTL_ASSERT(n == kNodeSize); + return mPool.allocate(alignment, offset); + } + + + void deallocate(void* p, size_t) + { + mPool.deallocate(p); + } + + + /// can_allocate + /// + /// Returns true if there are any free links. + /// + bool can_allocate() const + { + return mPool.can_allocate(); + } + + + /// reset + /// + /// This function unilaterally resets the fixed pool back to a newly initialized + /// state. This is useful for using in tandem with container reset functionality. + /// + void reset(void* pNodeBuffer) + { + mPool.init(pNodeBuffer, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset); + } + + + const char* get_name() const + { + return mPool.get_name(); + } + + + void set_name(const char* pName) + { + mPool.set_name(pName); + } + + + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT + { + return mPool.mOverflowAllocator; + } + + + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT + { + return mPool.mOverflowAllocator; + } + + + void set_overflow_allocator(const overflow_allocator_type& allocator) + { + mPool.mOverflowAllocator = allocator; + } + + + void copy_overflow_allocator(const this_type& x) // This function exists so we can write generic code that works for allocators that do and don't have overflow allocators. + { + mPool.mOverflowAllocator = x.mPool.mOverflowAllocator; + } + + }; // fixed_node_allocator + + + // This is a near copy of the code above, with the only difference being + // the 'false' bEnableOverflow template parameter, the pool_type and this_type typedefs, + // and the get_overflow_allocator / set_overflow_allocator functions. + template + class fixed_node_allocator + { + public: + typedef fixed_pool pool_type; + typedef fixed_node_allocator this_type; + typedef OverflowAllocator overflow_allocator_type; + + enum + { + kNodeSize = nodeSize, + kNodeCount = nodeCount, + kNodesSize = nodeCount * nodeSize, // Note that the kBufferSize calculation assumes that the compiler sets sizeof(T) to be a multiple alignof(T), and so sizeof(T) is always >= alignof(T). + kBufferSize = kNodesSize + ((nodeAlignment > 1) ? nodeSize-1 : 0) + nodeAlignmentOffset, + kNodeAlignment = nodeAlignment, + kNodeAlignmentOffset = nodeAlignmentOffset + }; + + public: + pool_type mPool; + + public: + fixed_node_allocator(void* pNodeBuffer) + : mPool(pNodeBuffer, kNodesSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset) + { + } + + + fixed_node_allocator(void* pNodeBuffer, const overflow_allocator_type& /*allocator*/) // allocator is unused because bEnableOverflow is false in this specialization. + : mPool(pNodeBuffer, kNodesSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset) + { + } + + + /// fixed_node_allocator + /// + /// Note that we are copying x.mpHead to our own fixed_pool. This at first may seem + /// broken, as fixed pools cannot take over ownership of other fixed pools' memory. + /// However, we declare that this copy ctor can only ever be safely called when + /// the user has intentionally pre-seeded the source with the destination pointer. + /// This is somewhat playing with fire, but it allows us to get around chicken-and-egg + /// problems with containers being their own allocators, without incurring any memory + /// costs or extra code costs. There's another reason for this: we very strongly want + /// to avoid full copying of instances of fixed_pool around, especially via the stack. + /// Larger pools won't even be able to fit on many machine's stacks. So this solution + /// is also a mechanism to prevent that situation from existing and being used. + /// Perhaps some day we'll find a more elegant yet costless way around this. + /// + fixed_node_allocator(const this_type& x) // No need to copy the overflow allocator, because bEnableOverflow is false in this specialization. + : mPool(x.mPool.mpNext, kNodesSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset) + { + } + + + this_type& operator=(const this_type& x) + { + mPool = x.mPool; + return *this; + } + + + void* allocate(size_t n, int /*flags*/ = 0) + { + (void)n; + EASTL_ASSERT(n == kNodeSize); + return mPool.allocate(); + } + + + void* allocate(size_t n, size_t alignment, size_t offset, int /*flags*/ = 0) + { + (void)n; + EASTL_ASSERT(n == kNodeSize); + return mPool.allocate(alignment, offset); + } + + + void deallocate(void* p, size_t) + { + mPool.deallocate(p); + } + + + bool can_allocate() const + { + return mPool.can_allocate(); + } + + + void reset(void* pNodeBuffer) + { + mPool.init(pNodeBuffer, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset); + } + + + const char* get_name() const + { + return mPool.get_name(); + } + + + void set_name(const char* pName) + { + mPool.set_name(pName); + } + + + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT + { + EASTL_ASSERT(false); + overflow_allocator_type* pNULL = NULL; + return *pNULL; // This is not pretty, but it should never execute. This is here only to allow this to compile. + } + + + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT + { + EASTL_ASSERT(false); + overflow_allocator_type* pNULL = NULL; + return *pNULL; // This is not pretty, but it should never execute. This is here only to allow this to compile. + } + + + void set_overflow_allocator(const overflow_allocator_type& /*allocator*/) + { + // We don't have an overflow allocator. + EASTL_ASSERT(false); + } + + + void copy_overflow_allocator(const this_type&) // This function exists so we can write generic code that works for allocators that do and don't have overflow allocators. + { + // We don't have an overflow allocator. + } + + }; // fixed_node_allocator + + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const fixed_node_allocator& a, + const fixed_node_allocator& b) + { + return (&a == &b); // They are only equal if they are the same object. + } + + + template + inline bool operator!=(const fixed_node_allocator& a, + const fixed_node_allocator& b) + { + return (&a != &b); // They are only equal if they are the same object. + } + + + + + + + /////////////////////////////////////////////////////////////////////////// + // fixed_hashtable_allocator + /////////////////////////////////////////////////////////////////////////// + + /// fixed_hashtable_allocator + /// + /// Provides a base class for fixed hashtable allocations. + /// To consider: Have this inherit from fixed_node_allocator. + /// + /// Template parameters: + /// bucketCount The fixed number of hashtable buckets to provide. + /// nodeCount The number of objects the pool contains. + /// nodeAlignment The alignment of the objects to allocate. + /// nodeAlignmentOffset The alignment offset of the objects to allocate. + /// bEnableOverflow Whether or not we should use the overflow heap if our object pool is exhausted. + /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. + /// + template + class fixed_hashtable_allocator + { + public: + typedef typename type_select, fixed_pool>::type pool_type; + typedef fixed_hashtable_allocator this_type; + typedef OverflowAllocator overflow_allocator_type; + + enum + { + kBucketCount = bucketCount + 1, // '+1' because the hash table needs a null terminating bucket. + kBucketsSize = bucketCount * sizeof(void*), + kNodeSize = nodeSize, + kNodeCount = nodeCount, + kNodesSize = nodeCount * nodeSize, // Note that the kBufferSize calculation assumes that the compiler sets sizeof(T) to be a multiple alignof(T), and so sizeof(T) is always >= alignof(T). + kBufferSize = kNodesSize + ((nodeAlignment > 1) ? nodeSize-1 : 0) + nodeAlignmentOffset, // Don't need to include kBucketsSize in this calculation, as fixed_hash_xxx containers have a separate buffer for buckets. + kNodeAlignment = nodeAlignment, + kNodeAlignmentOffset = nodeAlignmentOffset, + kAllocFlagBuckets = 0x00400000 // Flag to allocator which indicates that we are allocating buckets and not nodes. + }; + + protected: + pool_type mPool; + void* mpBucketBuffer; + + public: + // Disabled because it causes compile conflicts. + //fixed_hashtable_allocator(const char* pName) + //{ + // mPool.set_name(pName); + //} + + fixed_hashtable_allocator(void* pNodeBuffer) + : mPool(pNodeBuffer, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset), + mpBucketBuffer(NULL) + { + // EASTL_ASSERT(false); // As it stands now, this is not supposed to be called. + } + + + fixed_hashtable_allocator(void* pNodeBuffer, const overflow_allocator_type& allocator) + : mPool(pNodeBuffer, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset, allocator), + mpBucketBuffer(NULL) + { + // EASTL_ASSERT(false); // As it stands now, this is not supposed to be called. + } + + + fixed_hashtable_allocator(void* pNodeBuffer, void* pBucketBuffer) + : mPool(pNodeBuffer, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset), + mpBucketBuffer(pBucketBuffer) + { + } + + + fixed_hashtable_allocator(void* pNodeBuffer, void* pBucketBuffer, const overflow_allocator_type& allocator) + : mPool(pNodeBuffer, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset, allocator), + mpBucketBuffer(pBucketBuffer) + { + } + + + /// fixed_hashtable_allocator + /// + /// Note that we are copying x.mpHead and mpBucketBuffer to our own fixed_pool. + /// See the discussion above in fixed_node_allocator for important information about this. + /// + fixed_hashtable_allocator(const this_type& x) + : mPool(x.mPool.mpHead, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset, x.mPool.mOverflowAllocator), + mpBucketBuffer(x.mpBucketBuffer) + { + } + + + fixed_hashtable_allocator& operator=(const fixed_hashtable_allocator& x) + { + mPool = x.mPool; + return *this; + } + + + void* allocate(size_t n, int flags = 0) + { + // We expect that the caller uses kAllocFlagBuckets when it wants us to allocate buckets instead of nodes. + EASTL_CT_ASSERT(kAllocFlagBuckets == 0x00400000); // Currently we expect this to be so, because the hashtable has a copy of this enum. + + if((flags & kAllocFlagBuckets) == 0) // If we are allocating nodes and (probably) not buckets... + { + EASTL_ASSERT(n == kNodeSize); EA_UNUSED(n); + return mPool.allocate(); + } + + // If bucket size no longer fits within local buffer... + if ((flags & kAllocFlagBuckets) == kAllocFlagBuckets && (n > kBucketsSize)) + return get_overflow_allocator().allocate(n); + + EASTL_ASSERT(n <= kBucketsSize); + return mpBucketBuffer; + } + + + void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0) + { + // We expect that the caller uses kAllocFlagBuckets when it wants us to allocate buckets instead of nodes. + if ((flags & kAllocFlagBuckets) == 0) // If we are allocating nodes and (probably) not buckets... + { + EASTL_ASSERT(n == kNodeSize); EA_UNUSED(n); + return mPool.allocate(alignment, offset); + } + + // If bucket size no longer fits within local buffer... + if ((flags & kAllocFlagBuckets) == kAllocFlagBuckets && (n > kBucketsSize)) + return get_overflow_allocator().allocate(n, alignment, offset); + + EASTL_ASSERT(n <= kBucketsSize); + return mpBucketBuffer; + } + + + void deallocate(void* p, size_t) + { + if(p != mpBucketBuffer) // If we are freeing a node and not buckets... + mPool.deallocate(p); + } + + + bool can_allocate() const + { + return mPool.can_allocate(); + } + + + void reset(void* pNodeBuffer) + { + // No need to modify mpBucketBuffer, as that is constant. + mPool.init(pNodeBuffer, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset); + } + + + const char* get_name() const + { + return mPool.get_name(); + } + + + void set_name(const char* pName) + { + mPool.set_name(pName); + } + + + const overflow_allocator_type& get_overflow_allocator() const + { + return mPool.mOverflowAllocator; + } + + + overflow_allocator_type& get_overflow_allocator() + { + return mPool.mOverflowAllocator; + } + + + void set_overflow_allocator(const overflow_allocator_type& allocator) + { + mPool.mOverflowAllocator = allocator; + } + + + void copy_overflow_allocator(const this_type& x) // This function exists so we can write generic code that works for allocators that do and don't have overflow allocators. + { + mPool.mOverflowAllocator = x.mPool.mOverflowAllocator; + } + + }; // fixed_hashtable_allocator + + + // This is a near copy of the code above, with the only difference being + // the 'false' bEnableOverflow template parameter, the pool_type and this_type typedefs, + // and the get_overflow_allocator / set_overflow_allocator functions. + template + class fixed_hashtable_allocator + { + public: + typedef fixed_pool pool_type; + typedef fixed_hashtable_allocator this_type; + typedef OverflowAllocator overflow_allocator_type; + + enum + { + kBucketCount = bucketCount + 1, // '+1' because the hash table needs a null terminating bucket. + kBucketsSize = bucketCount * sizeof(void*), + kNodeSize = nodeSize, + kNodeCount = nodeCount, + kNodesSize = nodeCount * nodeSize, // Note that the kBufferSize calculation assumes that the compiler sets sizeof(T) to be a multiple alignof(T), and so sizeof(T) is always >= alignof(T). + kBufferSize = kNodesSize + ((nodeAlignment > 1) ? nodeSize-1 : 0) + nodeAlignmentOffset, // Don't need to include kBucketsSize in this calculation, as fixed_hash_xxx containers have a separate buffer for buckets. + kNodeAlignment = nodeAlignment, + kNodeAlignmentOffset = nodeAlignmentOffset, + kAllocFlagBuckets = 0x00400000 // Flag to allocator which indicates that we are allocating buckets and not nodes. + }; + + protected: + pool_type mPool; + void* mpBucketBuffer; + + public: + // Disabled because it causes compile conflicts. + //fixed_hashtable_allocator(const char* pName) + //{ + // mPool.set_name(pName); + //} + + fixed_hashtable_allocator(void* pNodeBuffer) + : mPool(pNodeBuffer, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset), + mpBucketBuffer(NULL) + { + // EASTL_ASSERT(false); // As it stands now, this is not supposed to be called. + } + + fixed_hashtable_allocator(void* pNodeBuffer, const overflow_allocator_type& /*allocator*/) // allocator is unused because bEnableOverflow is false in this specialization. + : mPool(pNodeBuffer, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset), + mpBucketBuffer(NULL) + { + // EASTL_ASSERT(false); // As it stands now, this is not supposed to be called. + } + + + fixed_hashtable_allocator(void* pNodeBuffer, void* pBucketBuffer) + : mPool(pNodeBuffer, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset), + mpBucketBuffer(pBucketBuffer) + { + } + + + fixed_hashtable_allocator(void* pNodeBuffer, void* pBucketBuffer, const overflow_allocator_type& /*allocator*/) // allocator is unused because bEnableOverflow is false in this specialization. + : mPool(pNodeBuffer, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset), + mpBucketBuffer(pBucketBuffer) + { + } + + + /// fixed_hashtable_allocator + /// + /// Note that we are copying x.mpHead and mpBucketBuffer to our own fixed_pool. + /// See the discussion above in fixed_node_allocator for important information about this. + /// + fixed_hashtable_allocator(const this_type& x) // No need to copy the overflow allocator, because bEnableOverflow is false in this specialization. + : mPool(x.mPool.mpHead, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset), + mpBucketBuffer(x.mpBucketBuffer) + { + } + + + fixed_hashtable_allocator& operator=(const fixed_hashtable_allocator& x) + { + mPool = x.mPool; + return *this; + } + + + void* allocate(size_t n, int flags = 0) + { + // We expect that the caller uses kAllocFlagBuckets when it wants us to allocate buckets instead of nodes. + EASTL_CT_ASSERT(kAllocFlagBuckets == 0x00400000); // Currently we expect this to be so, because the hashtable has a copy of this enum. + if((flags & kAllocFlagBuckets) == 0) // If we are allocating nodes and (probably) not buckets... + { + EASTL_ASSERT(n == kNodeSize); (void)n; // Make unused var warning go away. + return mPool.allocate(); + } + + // Don't allow hashtable buckets to overflow in this case. + EASTL_ASSERT(n <= kBucketsSize); + return mpBucketBuffer; + } + + + void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0) + { + // We expect that the caller uses kAllocFlagBuckets when it wants us to allocate buckets instead of nodes. + if((flags & kAllocFlagBuckets) == 0) // If we are allocating nodes and (probably) not buckets... + { + EASTL_ASSERT(n == kNodeSize); (void)n; // Make unused var warning go away. + return mPool.allocate(alignment, offset); + } + + // Don't allow hashtable buckets to overflow in this case. + EASTL_ASSERT(n <= kBucketsSize); + return mpBucketBuffer; + } + + + void deallocate(void* p, size_t) + { + if(p != mpBucketBuffer) // If we are freeing a node and not buckets... + mPool.deallocate(p); + } + + + bool can_allocate() const + { + return mPool.can_allocate(); + } + + + void reset(void* pNodeBuffer) + { + // No need to modify mpBucketBuffer, as that is constant. + mPool.init(pNodeBuffer, kBufferSize, kNodeSize, kNodeAlignment, kNodeAlignmentOffset); + } + + + const char* get_name() const + { + return mPool.get_name(); + } + + + void set_name(const char* pName) + { + mPool.set_name(pName); + } + + + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT + { + EASTL_ASSERT(false); + overflow_allocator_type* pNULL = NULL; + return *pNULL; // This is not pretty, but it should never execute. This is here only to allow this to compile. + } + + + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT + { + EASTL_ASSERT(false); + overflow_allocator_type* pNULL = NULL; + return *pNULL; // This is not pretty, but it should never execute. This is here only to allow this to compile. + } + + void set_overflow_allocator(const overflow_allocator_type& /*allocator*/) + { + // We don't have an overflow allocator. + EASTL_ASSERT(false); + } + + void copy_overflow_allocator(const this_type&) // This function exists so we can write generic code that works for allocators that do and don't have overflow allocators. + { + // We don't have an overflow allocator. + } + + }; // fixed_hashtable_allocator + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const fixed_hashtable_allocator& a, + const fixed_hashtable_allocator& b) + { + return (&a == &b); // They are only equal if they are the same object. + } + + + template + inline bool operator!=(const fixed_hashtable_allocator& a, + const fixed_hashtable_allocator& b) + { + return (&a != &b); // They are only equal if they are the same object. + } + + + + + + + /////////////////////////////////////////////////////////////////////////// + // fixed_vector_allocator + /////////////////////////////////////////////////////////////////////////// + + /// fixed_vector_allocator + /// + /// Template parameters: + /// nodeSize The size of individual objects. + /// nodeCount The number of objects the pool contains. + /// nodeAlignment The alignment of the objects to allocate. + /// nodeAlignmentOffset The alignment offset of the objects to allocate. + /// bEnableOverflow Whether or not we should use the overflow heap if our object pool is exhausted. + /// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap. + /// + template + class fixed_vector_allocator + { + public: + typedef fixed_vector_allocator this_type; + typedef OverflowAllocator overflow_allocator_type; + + enum + { + kNodeSize = nodeSize, + kNodeCount = nodeCount, + kNodesSize = nodeCount * nodeSize, // Note that the kBufferSize calculation assumes that the compiler sets sizeof(T) to be a multiple alignof(T), and so sizeof(T) is always >= alignof(T). + kBufferSize = kNodesSize + ((nodeAlignment > 1) ? nodeSize-1 : 0) + nodeAlignmentOffset, + kNodeAlignment = nodeAlignment, + kNodeAlignmentOffset = nodeAlignmentOffset + }; + + public: + overflow_allocator_type mOverflowAllocator; + void* mpPoolBegin; // To consider: Find some way to make this data unnecessary, without increasing template proliferation. + + public: + // Disabled because it causes compile conflicts. + //fixed_vector_allocator(const char* pName = NULL) + //{ + // mOverflowAllocator.set_name(pName); + //} + + fixed_vector_allocator(void* pNodeBuffer) + : mpPoolBegin(pNodeBuffer) + { + } + + fixed_vector_allocator(void* pNodeBuffer, const overflow_allocator_type& allocator) + : mOverflowAllocator(allocator), mpPoolBegin(pNodeBuffer) + { + } + + // Disabled because the default is sufficient. + //fixed_vector_allocator(const fixed_vector_allocator& x) + //{ + // mpPoolBegin = x.mpPoolBegin; + // mOverflowAllocator = x.mOverflowAllocator; + //} + + fixed_vector_allocator& operator=(const fixed_vector_allocator& x) + { + // We leave our mpPoolBegin variable alone. + + #if EASTL_ALLOCATOR_COPY_ENABLED + mOverflowAllocator = x.mOverflowAllocator; + #else + (void)x; + #endif + + return *this; + } + + void* allocate(size_t n, int flags = 0) + { + return mOverflowAllocator.allocate(n, flags); + } + + void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0) + { + return mOverflowAllocator.allocate(n, alignment, offset, flags); + } + + void deallocate(void* p, size_t n) + { + if(p != mpPoolBegin) + mOverflowAllocator.deallocate(p, n); // Can't do this to our own allocation. + } + + const char* get_name() const + { + return mOverflowAllocator.get_name(); + } + + void set_name(const char* pName) + { + mOverflowAllocator.set_name(pName); + } + + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT + { + return mOverflowAllocator; + } + + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT + { + return mOverflowAllocator; + } + + void set_overflow_allocator(const overflow_allocator_type& allocator) + { + mOverflowAllocator = allocator; + } + + void copy_overflow_allocator(const this_type& x) // This function exists so we can write generic code that works for allocators that do and don't have overflow allocators. + { + mOverflowAllocator = x.mOverflowAllocator; + } + + }; // fixed_vector_allocator + + + template + class fixed_vector_allocator + { + public: + typedef fixed_vector_allocator this_type; + typedef OverflowAllocator overflow_allocator_type; + + enum + { + kNodeSize = nodeSize, + kNodeCount = nodeCount, + kNodesSize = nodeCount * nodeSize, // Note that the kBufferSize calculation assumes that the compiler sets sizeof(T) to be a multiple alignof(T), and so sizeof(T) is always >= alignof(T). + kBufferSize = kNodesSize + ((nodeAlignment > 1) ? nodeSize-1 : 0) + nodeAlignmentOffset, + kNodeAlignment = nodeAlignment, + kNodeAlignmentOffset = nodeAlignmentOffset + }; + + // Disabled because it causes compile conflicts. + //fixed_vector_allocator(const char* = NULL) // This char* parameter is present so that this class can be like the other version. + //{ + //} + + fixed_vector_allocator(void* /*pNodeBuffer*/) + { + } + + fixed_vector_allocator(void* /*pNodeBuffer*/, const overflow_allocator_type& /*allocator*/) // allocator is unused because bEnableOverflow is false in this specialization. + { + } + + /// fixed_vector_allocator + /// + // Disabled because there is nothing to do. No member data. And the default for this is sufficient. + // fixed_vector_allocator(const fixed_vector_allocator&) + // { + // } + + // Disabled because there is nothing to do. No member data. + //fixed_vector_allocator& operator=(const fixed_vector_allocator& x) + //{ + // return *this; + //} + + void* allocate(size_t /*n*/, int /*flags*/ = 0) + { + EASTL_ASSERT(false); // A fixed_vector should not reallocate, else the user has exhausted its space. + return NULL; + } + + void* allocate(size_t /*n*/, size_t /*alignment*/, size_t /*offset*/, int /*flags*/ = 0) + { + EASTL_ASSERT(false); + return NULL; + } + + void deallocate(void* /*p*/, size_t /*n*/) + { + } + + const char* get_name() const + { + return EASTL_FIXED_POOL_DEFAULT_NAME; + } + + void set_name(const char* /*pName*/) + { + } + + const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT + { + EASTL_ASSERT(false); + overflow_allocator_type* pNULL = NULL; + return *pNULL; // This is not pretty, but it should never execute. This is here only to allow this to compile. + } + + overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT + { + EASTL_ASSERT(false); + overflow_allocator_type* pNULL = NULL; + return *pNULL; // This is not pretty, but it should never execute. This is here only to allow this to compile. + } + + void set_overflow_allocator(const overflow_allocator_type& /*allocator*/) + { + // We don't have an overflow allocator. + EASTL_ASSERT(false); + } + + void copy_overflow_allocator(const this_type&) // This function exists so we can write generic code that works for allocators that do and don't have overflow allocators. + { + // We don't have an overflow allocator. + } + + }; // fixed_vector_allocator + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const fixed_vector_allocator& a, + const fixed_vector_allocator& b) + { + return (&a == &b); // They are only equal if they are the same object. + } + + + template + inline bool operator!=(const fixed_vector_allocator& a, + const fixed_vector_allocator& b) + { + return (&a != &b); // They are only equal if they are the same object. + } + + + + + + /////////////////////////////////////////////////////////////////////////// + // fixed_swap + /////////////////////////////////////////////////////////////////////////// + + /// fixed_swap + /// + /// This function implements a swap suitable for fixed containers. + /// This is an issue because the size of fixed containers can be very + /// large, due to their having the container buffer within themselves. + /// Note that we are referring to sizeof(container) and not the total + /// sum of memory allocated by the container from the heap. + /// + /// + /// This implementation switches at compile time whether or not the + /// temporary is allocated on the stack or the heap as some compilers + /// will allocate the (large) stack frame regardless of which code + /// path is picked. + template + class fixed_swap_impl + { + public: + static void swap(Container& a, Container& b); + }; + + + template + class fixed_swap_impl + { + public: + static void swap(Container& a, Container& b) + { + const Container temp(a); // Can't use global swap because that could + a = b; // itself call this swap function in return. + b = temp; + } + }; + + + template + class fixed_swap_impl + { + public: + static void swap(Container& a, Container& b) + { + EASTLAllocatorType allocator(*EASTLAllocatorDefault(), EASTL_TEMP_DEFAULT_NAME); + void* const pMemory = allocator.allocate(sizeof(a)); + + if(pMemory) + { + Container* const pTemp = ::new(pMemory) Container(a); + a = b; + b = *pTemp; + + pTemp->~Container(); + allocator.deallocate(pMemory, sizeof(a)); + } + } + }; + + + template + void fixed_swap(Container& a, Container& b) + { + return fixed_swap_impl= EASTL_MAX_STACK_USAGE>::swap(a, b); + } + + + +} // namespace eastl + + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + + +#endif // Header include guard + diff --git a/libs/eastl/include/EASTL/internal/function.h b/libs/eastl/include/EASTL/internal/function.h new file mode 100644 index 0000000..a9e2112 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/function.h @@ -0,0 +1,1352 @@ +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + */ +// despite that it would be nice if you give credit to Malte Skarupke + + +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file has been approved by EA Legal. +// http://easites.ea.com/legal/ViewRequest.aspx?List=0142a10f-ee60-4187-a2cf-766be908dd39&ID=1917&Source=http%3A%2F%2Feasites%2Eea%2Ecom%2Flegal%2FLists%2FOpenSourceDealSheet%2FRequests%2Easpx +// +// Original code has been modified in the following ways: +// * Support compilers missing variadic template support +// * Does not assume eastl::allocator are templated with the Functor type. Instead requests raw bytes from eastl::allocator and caches functor types itself in function_table. +// * Minor changes to support older console versions GCC compiler. +// +/////////////////////////////////////////////////////////////////////////////// + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#ifndef EASTL_INTERNAL_FUNCTION_H +#define EASTL_INTERNAL_FUNCTION_H + +#include +#include +#include +#include +#include +#include +#include +#include + +// RTTI currently disabled. User can re-enable via the define below but note this code path isn't tested. +#define FUNC_NO_RTTI + +#define FUNC_TEMPLATE_NOEXCEPT(FUNCTOR, ALLOCATOR) EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR((detail::is_inplace_allocated::value))) + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// This workaround exists because on MSVC the "is_nothrow_move_constructible" type trait does not function as +// expected. It incorrectly flags the coping/moving of a pointer to the callable as being able to throw an exception. +// We can remove this workaround when the "is_nothrow_move_constructible" type trait functions for all Microsoft +// platforms and we being testing it again in EASTLs unit tests. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#if defined(EA_PLATFORM_MICROSOFT) + #define EASTL_INTERNAL_FUNCTION_ARE_TYPETRAITS_FUNCTIONAL 0 +#else + #define EASTL_INTERNAL_FUNCTION_ARE_TYPETRAITS_FUNCTIONAL 1 +#endif + +namespace eastl +{ + /// EASTL_FUNCTION_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_VECTOR_DEFAULT_NAME + #define EASTL_FUNCTION_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " function" // Unless the user overrides something, this is "EASTL function". + #endif + + + /// EASTL_VECTOR_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_VECTOR_DEFAULT_ALLOCATOR + #define EASTL_FUNCTION_DEFAULT_ALLOCATOR allocator_type(EASTL_FUNCTION_DEFAULT_NAME) + #endif + + +template +struct force_function_heap_allocation + : public eastl::false_type {}; + +template +class function; + +namespace detail +{ + struct total_storage_type; + struct function_table; + + struct functor_storage_type + { + protected: + size_t padding_first; + size_t padding_second; + }; + + struct allocator_storage_type + { + void* first; + void* second; + }; + + struct empty_struct { }; + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // type_trait that determines if functor and allocator can fit into the eastl::function local buffer + // + template + struct is_inplace_allocated + { + static const bool value + // so that Callable fits + = sizeof(Callable) <= sizeof(functor_storage_type) + // so that Allocator fits + && sizeof(Allocator) <= sizeof(allocator_storage_type) + // so that it will be aligned + && eastl::alignment_of::value % eastl::alignment_of::value == 0 +#if EASTL_INTERNAL_FUNCTION_ARE_TYPETRAITS_FUNCTIONAL + // so that we can offer noexcept move + && eastl::is_nothrow_move_constructible::value +#endif + // so that the user can override it + && !force_function_heap_allocation::value; + }; + + // todo: provide a manual override macro that allows users to set the value of this trait for this specific type. + + template + T to_functor(T && func) + { + return EASTL_FORWARD(T, func); + } + +#if EASTL_VARIADIC_TEMPLATES_ENABLED + template + auto to_functor(Result (Class::*func)(Arguments...)) -> decltype(eastl::mem_fn(func)) + { + return eastl::mem_fn(func); + } + template + auto to_functor(Result (Class::*func)(Arguments...) const) -> decltype(eastl::mem_fn(func)) + { + return eastl::mem_fn(func); + } +#else + // no argument case + template + auto to_functor(Result (Class::*func)()) -> decltype(eastl::mem_fn(func)) + { + return eastl::mem_fn(func); + } + template + auto to_functor(Result (Class::*func)() const) -> decltype(eastl::mem_fn(func)) + { + return eastl::mem_fn(func); + } + + // single argument case + template + auto to_functor(Result (Class::*func)(Argument0)) -> decltype(eastl::mem_fn(func)) + { + return eastl::mem_fn(func); + } + template + auto to_functor(Result (Class::*func)(Argument0) const) -> decltype(eastl::mem_fn(func)) + { + return eastl::mem_fn(func); + } +#endif + + template + struct functor_type + { + typedef decltype(to_functor(eastl::declval())) type; + }; + + template + bool is_null(const T&) + { + return false; + } + +#if EASTL_VARIADIC_TEMPLATES_ENABLED + template + bool is_null(Result (* const & function_pointer)(Arguments...)) + { + return function_pointer == nullptr; + } + template + bool is_null(Result (Class::* const & function_pointer)(Arguments...)) + { + return function_pointer == nullptr; + } + template + bool is_null(Result (Class::* const & function_pointer)(Arguments...) const) + { + return function_pointer == nullptr; + } +#else + // no argument case + template + bool is_null(Result (* const & function_pointer)()) + { + return function_pointer == nullptr; + } + template + bool is_null(Result (Class::* const & function_pointer)()) + { + return function_pointer == nullptr; + } + template + bool is_null(Result (Class::* const & function_pointer)() const) + { + return function_pointer == nullptr; + } + + // single argument case + template + bool is_null(Result (* const & function_pointer)(Argument0)) + { + return function_pointer == nullptr; + } + template + bool is_null(Result (Class::* const & function_pointer)(Argument0)) + { + return function_pointer == nullptr; + } + template + bool is_null(Result (Class::* const & function_pointer)(Argument0) const) + { + return function_pointer == nullptr; + } +#endif + + template + struct is_valid_function_argument + { + static const bool value = false; + }; + +#if EASTL_VARIADIC_TEMPLATES_ENABLED + template + struct is_valid_function_argument, Result (Arguments...)> + { + static const bool value = false; + }; +#else + // no argument case + template + struct is_valid_function_argument, Result()> + { + static const bool value = false; + }; + + // single argument case + template + struct is_valid_function_argument, Result (Argument0)> + { + static const bool value = false; + }; +#endif + + +#if EASTL_VARIADIC_TEMPLATES_ENABLED + template + struct is_valid_function_argument + { + #if defined(_MSC_VER) || defined(EA_PLATFORM_OSX) + // as of january 2013 visual studio doesn't support the SFINAE below + static const bool value = true; + #else + template + static decltype(to_functor(eastl::declval())(eastl::declval()...)) check(U*); + template + static empty_struct check(...); + + static const bool value = eastl::is_convertible(nullptr)), Result>::value; + #endif + }; +#else + // no argument case + template + struct is_valid_function_argument + { + #if defined(_MSC_VER) || defined(EA_PLATFORM_OSX) + // as of january 2013 visual studio doesn't support the SFINAE below + static const bool value = true; + #else + template + static decltype(to_functor(eastl::declval())()) check(U*); + template + static empty_struct check(...); + + static const bool value = eastl::is_convertible(nullptr)), Result>::value; + #endif + }; + + // single argument case + template + struct is_valid_function_argument + { + #if defined(_MSC_VER) || defined(EA_PLATFORM_OSX) + // as of january 2013 visual studio doesn't support the SFINAE below + static const bool value = true; + #else + template + static decltype(to_functor(eastl::declval())(eastl::declval())) check(U*); + template + static empty_struct check(...); + + static const bool value = eastl::is_convertible(nullptr)), Result>::value; + #endif + }; +#endif + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // eastl::function local storage for the user provided functor and allocator types. + // + typedef const function_table* function_table_storage_type; + struct total_storage_type + { + allocator_storage_type allocator_storage; + functor_storage_type functor; + function_table_storage_type function_table; + }; + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Allocator and Functor fit into local buffers of eastl::function (ie. total_storage_type) + // + template + struct function_table_inplace_specialization + { +#if EASTL_VARIADIC_TEMPLATES_ENABLED + template + EA_FORCE_INLINE static Result call(const functor_storage_type & storage, Arguments... arguments) + { + // do not call get_functor_ref because I want this function to be fast in debug when nothing gets inlined + return const_cast(reinterpret_cast(storage))(EASTL_FORWARD(Arguments, arguments)...); + } +#else + // no argument case + template + EA_FORCE_INLINE static Result call(const functor_storage_type & storage) + { + // do not call get_functor_ref because I want this function to be fast + // in debug when nothing gets inlined + return const_cast(reinterpret_cast(storage))(); + } + + // single argument case + template + EA_FORCE_INLINE static Result call(const functor_storage_type & storage, Argument0 argument0) + { + // do not call get_functor_ref because I want this function to be fast + // in debug when nothing gets inlined + return const_cast(reinterpret_cast(storage))(EASTL_FORWARD(Argument0, argument0)); + } +#endif + + // functor accessors + static void store_functor(total_storage_type & storage, T to_store) + { + new (&get_functor_ref(storage)) T(EASTL_FORWARD(T, to_store)); + } + static void move_functor(total_storage_type & lhs, total_storage_type && rhs) EA_NOEXCEPT + { + new (&get_functor_ref(lhs)) T(EASTL_MOVE(get_functor_ref(rhs))); + } + static void destroy_functor(Allocator &, total_storage_type & storage) EA_NOEXCEPT + { + get_functor_ref(storage).~T(); + } + static T & get_functor_ref(const total_storage_type & storage) EA_NOEXCEPT + { + return const_cast(reinterpret_cast(storage.functor)); + } + + // allocator accessors + static void store_allocator(total_storage_type& storage, Allocator&& allocator) + { + new (&storage.allocator_storage) Allocator(EASTL_MOVE(allocator)); + } + + static void move_allocator(total_storage_type& lhs, total_storage_type&& rhs) EA_NOEXCEPT + { + new (&lhs.allocator_storage) Allocator(EASTL_MOVE((get_allocator(rhs)))); + } + + static Allocator& get_allocator(const total_storage_type& storage) EA_NOEXCEPT + { + return const_cast(reinterpret_cast(storage.allocator_storage)); + } + + static void destroy_allocator(total_storage_type& storage) EA_NOEXCEPT + { + get_allocator(storage).~Allocator(); + } + }; + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Allocator and Functor must be allocated on the heap + // + template + struct function_table_inplace_specialization::value>::type> + { + typedef T Functor; + typedef T* FunctorPointer; + + +#if EASTL_VARIADIC_TEMPLATES_ENABLED + template + EA_FORCE_INLINE static Result call(const functor_storage_type & storage, Arguments... arguments) + { + // do not call get_functor_ptr_ref because I want this function to be fast in debug when nothing gets inlined + return (*reinterpret_cast(storage))(EASTL_FORWARD(Arguments, arguments)...); + } +#else + // no argument case + template + EA_FORCE_INLINE static Result call(const functor_storage_type & storage) + { + // do not call get_functor_ptr_ref because I want this function to be fast in debug when nothing gets inlined + return (*reinterpret_cast(storage))(); + } + + // single argument case + template + EA_FORCE_INLINE static Result call(const functor_storage_type & storage, Argument0 argument0) + { + // do not call get_functor_ptr_ref because I want this function to be fast in debug when nothing gets inlined + return (*reinterpret_cast(storage))(EASTL_FORWARD(Argument0, argument0)); + } +#endif + + // functor accessors + // + static void store_functor(total_storage_type & self, T to_store) + { + static_assert(sizeof(FunctorPointer) <= sizeof(self.functor), "The allocator's pointer type is too big"); + + Allocator& allocator = get_allocator(self); + FunctorPointer* ptr = new (&get_functor_ptr_ref(self)) FunctorPointer(reinterpret_cast(eastl::allocator_traits::allocate(allocator, sizeof(Functor)))); + eastl::allocator_traits::construct(allocator, *ptr, EASTL_FORWARD(T, to_store)); + } + + static void move_functor(total_storage_type & lhs, total_storage_type && rhs) EA_NOEXCEPT + { +#if EASTL_INTERNAL_FUNCTION_ARE_TYPETRAITS_FUNCTIONAL + static_assert(eastl::is_nothrow_move_constructible::value, "we can't offer a noexcept swap if the pointer type is not nothrow move constructible"); +#endif + new (&get_functor_ptr_ref(lhs)) FunctorPointer(EASTL_MOVE(get_functor_ptr_ref(rhs))); + // this next assignment makes the destroy function easier + get_functor_ptr_ref(rhs) = nullptr; + } + + static void destroy_functor(Allocator & allocator, total_storage_type & storage) EA_NOEXCEPT + { + FunctorPointer& pointer = get_functor_ptr_ref(storage); + if (!pointer) return; + eastl::allocator_traits::destroy(allocator, pointer); + eastl::allocator_traits::deallocate(allocator, reinterpret_cast::pointer>(pointer), sizeof(Functor)); + } + + static Functor& get_functor_ref(const total_storage_type & storage) EA_NOEXCEPT + { + return *get_functor_ptr_ref(storage); + } + + static FunctorPointer& get_functor_ptr_ref(total_storage_type & storage) EA_NOEXCEPT + { + return const_cast(reinterpret_cast(storage.functor)); + } + + static const FunctorPointer& get_functor_ptr_ref(const total_storage_type & storage) EA_NOEXCEPT + { + return const_cast(reinterpret_cast(storage.functor)); + } + + + // allocator accessors + // + static void store_allocator(total_storage_type& storage, Allocator&& allocator) + { + auto pMem = eastl::allocator_traits::allocate(allocator, sizeof(Allocator)); + storage.allocator_storage.first = reinterpret_cast(pMem); + eastl::allocator_traits::construct(allocator, (Allocator*)storage.allocator_storage.first, allocator); + } + + static Allocator& get_allocator(const total_storage_type& storage) EA_NOEXCEPT + { + return *const_cast(reinterpret_cast(storage.allocator_storage)); + } + + static void move_allocator(total_storage_type& lhs, total_storage_type&& rhs) EA_NOEXCEPT + { + lhs.allocator_storage.first = rhs.allocator_storage.first; + } + + static void destroy_allocator(total_storage_type& storage) EA_NOEXCEPT + { + auto& allocator = get_allocator(storage); + Allocator local_allocator(allocator); + eastl::allocator_traits::deallocate(local_allocator, reinterpret_cast::pointer>(&allocator), sizeof(Allocator)); + eastl::allocator_traits::destroy(local_allocator, reinterpret_cast::pointer>(&allocator)); + } + }; + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // get_default_function_table + // + template + static const function_table& get_default_function_table(); + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // init_function_table + // + template + static void init_function_table(total_storage_type& storage) + { + storage.function_table = &get_default_function_table(); + } + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // this struct acts as a vtable. it is an optimization to prevent + // code-bloat from rtti. see the documentation of boost::function + struct function_table + { + typedef void (*call_move_and_destroy_t)(total_storage_type& lhs, total_storage_type&& rhs); + typedef void (*call_copy_t)(total_storage_type& lhs, const total_storage_type& rhs); + typedef void (*call_copy_functor_only_t)(total_storage_type& lhs, const total_storage_type& rhs); + typedef void (*call_destroy_t)(total_storage_type& function_table); +#ifndef FUNC_NO_RTTI + typedef const std::type_info& (*call_type_id_t)(); + typedef void* (*call_target_t)(const total_storage_type& function_table, const std::type_info& type); +#endif + + // call move/copy callbacks + call_move_and_destroy_t call_move_and_destroy; + call_copy_t call_copy; + call_copy_functor_only_t call_copy_functor_only; + call_destroy_t call_destroy; +#ifndef FUNC_NO_RTTI + call_type_id_t call_type_id; + call_target_t call_target; +#endif + + template + inline static EA_CONSTEXPR function_table create_default_function_table() + { + return function_table(&templated_call_move_and_destroy + , &templated_call_copy + , &templated_call_copy_functor_only + , &templated_call_destroy + #ifndef FUNC_NO_RTTI + , &templated_call_type_id, + , &templated_call_target + #endif + ); + } + + // function_table constructor + EA_CONSTEXPR function_table(call_move_and_destroy_t cmad, + call_copy_t cc, + call_copy_functor_only_t ccfo, + call_destroy_t cd +#ifndef FUNC_NO_RTTI + call_type_id_t cti, + call_target_t ct +#endif + ) + : call_move_and_destroy(cmad) + , call_copy(cc) + , call_copy_functor_only(ccfo) + , call_destroy(cd) +#ifndef FUNC_NO_RTTI + , call_type_id(cti) + , call_target(ct) +#endif + { + } + + template + static void templated_call_move_and_destroy(total_storage_type & lhs, total_storage_type && rhs) + { + typedef function_table_inplace_specialization specialization; + specialization::move_functor(lhs, EASTL_MOVE(rhs)); + specialization::destroy_functor(specialization::get_allocator(rhs), rhs); + init_function_table(lhs); + specialization::move_allocator(lhs, EASTL_MOVE(rhs)); + } + + template + static void templated_call_copy(total_storage_type & lhs, const total_storage_type & rhs) + { + typedef function_table_inplace_specialization specialization; + init_function_table(lhs); + specialization::store_allocator(lhs, Allocator(specialization::get_allocator(rhs))); + specialization::store_functor(lhs, specialization::get_functor_ref(rhs)); + } + + template + static void templated_call_destroy(total_storage_type & self) + { + typedef function_table_inplace_specialization specialization; + specialization::destroy_functor(specialization::get_allocator(self), self); + specialization::destroy_allocator(self); + } + + template + static void templated_call_copy_functor_only(total_storage_type & lhs, const total_storage_type & rhs) + { + typedef function_table_inplace_specialization specialization; + specialization::store_functor(lhs, specialization::get_functor_ref(rhs)); + } + +#ifndef FUNC_NO_RTTI + template + static const std::type_info & templated_call_type_id() + { + return typeid(T); + } + template + static void * templated_call_target(const total_storage_type & self, const std::type_info & type) + { + typedef function_table_inplace_specialization specialization; + if (type == typeid(T)) + return &specialization::get_functor_ref(self); + else + return nullptr; + } +#endif + }; + template + inline static const function_table& get_default_function_table() + { + static const function_table default_function_table = function_table::create_default_function_table(); + return default_function_table; + } + +#if EASTL_VARIADIC_TEMPLATES_ENABLED + template + struct typedeffer + { + typedef Result result_type; + }; +#else + template + struct typedeffer + { + typedef Result result_type; + }; +#endif + +} + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// eastl::function +// +#if EASTL_VARIADIC_TEMPLATES_ENABLED +template +class function + : public detail::typedeffer +{ +public: + function() EA_NOEXCEPT + { + initialize_empty(); + } + function(std::nullptr_t) EA_NOEXCEPT + { + initialize_empty(); + } + function(function && other) EA_NOEXCEPT + { + initialize_empty(); + swap(other); + } + function(const function & other) + : call(other.call) + { + other.storage.function_table->call_copy(storage, other.storage); + } + + template + function(T functor, + typename eastl::enable_if::value, detail::empty_struct>::type = detail::empty_struct()) FUNC_TEMPLATE_NOEXCEPT(T, EASTLAllocatorType) + { + if (detail::is_null(functor)) + { + initialize_empty(); + } + else + { + initialize(detail::to_functor(EASTL_FORWARD(T, functor)), EASTLAllocatorType()); + } + } + + template + function(eastl::allocator_arg_t, const Allocator &) + { + // ignore the allocator because I don't allocate + initialize_empty(); + } + + template + function(eastl::allocator_arg_t, const Allocator &, std::nullptr_t) + { + // ignore the allocator because I don't allocate + initialize_empty(); + } + + template + function(eastl::allocator_arg_t, const Allocator & allocator, T functor, + typename eastl::enable_if::value, detail::empty_struct>::type = detail::empty_struct()) + FUNC_TEMPLATE_NOEXCEPT(T, Allocator) + { + if (detail::is_null(functor)) + { + initialize_empty(); + } + else + { + initialize(detail::to_functor(EASTL_FORWARD(T, functor)), Allocator(allocator)); + } + } + + template + function(eastl::allocator_arg_t, const Allocator& allocator, const function& other) + : call(other.call) + { + typedef typename eastl::allocator_traits::template rebind_alloc MyAllocator; + + // first try to see if the allocator matches the target type + detail::function_table_storage_type function_table_for_allocator = &detail::get_default_function_table::value_type, Allocator>(); + if (other.storage.function_table == function_table_for_allocator) + { + detail::init_function_table::value_type, Allocator>(storage); + detail::function_table_inplace_specialization::value_type, Allocator>::store_allocator(storage, Allocator(allocator)); + function_table_for_allocator->call_copy_functor_only(storage, other.storage); + } + // if it does not, try to see if the target contains my type. this + // breaks the recursion of the last case. otherwise repeated copies + // would allocate more and more memory + else + { + detail::function_table_storage_type function_table_for_function = &detail::get_default_function_table(); + if (other.storage.function_table == function_table_for_function) + { + detail::init_function_table(storage); + detail::function_table_inplace_specialization::store_allocator(storage, MyAllocator(allocator)); + function_table_for_function->call_copy_functor_only(storage, other.storage); + } + else + { + // else store the other function as my target + initialize(other, MyAllocator(allocator)); + } + } + } + template + function(eastl::allocator_arg_t, const Allocator&, function&& other) EA_NOEXCEPT + { + // ignore the allocator because I don't allocate + initialize_empty(); + swap(other); + } + + function & operator=(function other) EA_NOEXCEPT + { + swap(other); + return *this; + } + + ~function() EA_NOEXCEPT + { + storage.function_table->call_destroy(storage); + } + + Result operator()(Arguments... arguments) const + { + return call(storage.functor, EASTL_FORWARD(Arguments, arguments)...); + } + + template + void assign(T && functor, const Allocator & allocator) FUNC_TEMPLATE_NOEXCEPT(T, Allocator) + { + function(eastl::allocator_arg, allocator, functor).swap(*this); + } + + void swap(function & other) EA_NOEXCEPT + { + detail::total_storage_type temp_storage; + other.storage.function_table->call_move_and_destroy(temp_storage, EASTL_MOVE(other.storage)); + storage.function_table->call_move_and_destroy(other.storage, EASTL_MOVE(storage)); + temp_storage.function_table->call_move_and_destroy(storage, EASTL_MOVE(temp_storage)); + + eastl::swap(call, other.call); + } + + +#ifndef FUNC_NO_RTTI + const std::type_info & target_type() const EA_NOEXCEPT + { + return storage.function_table->call_type_id(); + } + template + T * target() EA_NOEXCEPT + { + return static_cast(storage.function_table->call_target(storage, typeid(T))); + } + template + const T * target() const EA_NOEXCEPT + { + return static_cast(storage.function_table->call_target(storage, typeid(T))); + } +#endif + + operator bool() const EA_NOEXCEPT + { + return call != nullptr; + } + +private: + detail::total_storage_type storage; + Result (*call)(const detail::functor_storage_type &, Arguments...); + + template + void initialize(T functor, Allocator && allocator) + { + call = &detail::function_table_inplace_specialization::template call; + detail::init_function_table(storage); + detail::function_table_inplace_specialization::store_allocator(storage, EASTL_FORWARD(Allocator, allocator)); + detail::function_table_inplace_specialization::store_functor(storage, EASTL_FORWARD(T, functor)); + } + + typedef Result(*Empty_Function_Type)(Arguments...); + + void initialize_empty() EA_NOEXCEPT + { + typedef EASTLAllocatorType Allocator; + static_assert(detail::is_inplace_allocated::value, "The empty function should benefit from small functor optimization"); + + detail::init_function_table(storage); + detail::function_table_inplace_specialization::store_allocator(storage, Allocator()); + detail::function_table_inplace_specialization::store_functor(storage, nullptr); + call = nullptr; + } +}; + +#else // EASTL_VARIADIC_TEMPLATES_ENABLED + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Manually defined overloads for platforms without variadic template support +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// eastl::function +// no argument case +// +template +class function + : public detail::typedeffer +{ +public: + function() EA_NOEXCEPT + { + initialize_empty(); + } + + function(std::nullptr_t) EA_NOEXCEPT + { + initialize_empty(); + } + + function(function && other) EA_NOEXCEPT + { + initialize_empty(); + swap(other); + } + + function(const function & other) + : call(other.call) + { + other.storage.function_table->call_copy(storage, other.storage); + } + + template + function(T functor, + typename eastl::enable_if::value, detail::empty_struct>::type = detail::empty_struct()) FUNC_TEMPLATE_NOEXCEPT(T, EASTLAllocatorType) + { + if (detail::is_null(functor)) + { + initialize_empty(); + } + else + { + initialize(detail::to_functor(EASTL_FORWARD(T, functor)), EASTLAllocatorType()); + } + } + + template + function(eastl::allocator_arg_t, const Allocator &) + { + // ignore the allocator because I don't allocate + initialize_empty(); + } + + template + function(eastl::allocator_arg_t, const Allocator &, std::nullptr_t) + { + // ignore the allocator because I don't allocate + initialize_empty(); + } + + + template + function(eastl::allocator_arg_t, const Allocator & allocator, T functor, + typename eastl::enable_if::value, detail::empty_struct>::type = detail::empty_struct()) + FUNC_TEMPLATE_NOEXCEPT(T, Allocator) + { + if (detail::is_null(functor)) + { + initialize_empty(); + } + else + { + initialize(detail::to_functor(EASTL_FORWARD(T, functor)), Allocator(allocator)); + } + } + + template + function(eastl::allocator_arg_t, const Allocator & allocator, const function & other) + : call(other.call) + { + typedef typename eastl::allocator_traits::template rebind_alloc MyAllocator; + + // first try to see if the allocator matches the target type + detail::function_table_storage_type function_table_for_allocator = &detail::get_default_function_table::value_type, Allocator>(); + if (other.storage.function_table == function_table_for_allocator) + { + detail::init_function_table::value_type, Allocator>(storage); + detail::function_table_inplace_specialization::store_allocator(storage, Allocator(allocator)); + function_table_for_allocator->call_copy_functor_only(storage, other.storage); + } + // if it does not, try to see if the target contains my type. this + // breaks the recursion of the last case. otherwise repeated copies + // would allocate more and more memory + else + { + detail::function_table_storage_type function_table_for_function = &detail::get_default_function_table(); + if (other.storage.function_table == function_table_for_function) + { + detail::init_function_table(storage); + detail::function_table_inplace_specialization::store_allocator(storage, MyAllocator(allocator)); + function_table_for_function->call_copy_functor_only(storage, other.storage); + } + else + { + // else store the other function as my target + initialize(other, MyAllocator(allocator)); + } + } + } + + template + function(eastl::allocator_arg_t, const Allocator &, function && other) EA_NOEXCEPT + { + // ignore the allocator because I don't allocate + initialize_empty(); + swap(other); + } + + function & operator=(function other) EA_NOEXCEPT + { + swap(other); + return *this; + } + + ~function() EA_NOEXCEPT + { + storage.function_table->call_destroy(storage); + } + + Result operator()() const + { + return call(storage.functor); + } + + template + void assign(T && functor, const Allocator & allocator) FUNC_TEMPLATE_NOEXCEPT(T, Allocator) + { + function(eastl::allocator_arg, allocator, functor).swap(*this); + } + + void swap(function & other) EA_NOEXCEPT + { + detail::total_storage_type temp_storage; + other.storage.function_table->call_move_and_destroy(temp_storage, EASTL_MOVE(other.storage)); + storage.function_table->call_move_and_destroy(other.storage, EASTL_MOVE(storage)); + temp_storage.function_table->call_move_and_destroy(storage, EASTL_MOVE(temp_storage)); + + eastl::swap(call, other.call); + } + +#ifndef FUNC_NO_RTTI + const std::type_info & target_type() const EA_NOEXCEPT + { + return storage.function_table->call_type_id(); + } + template + T * target() EA_NOEXCEPT + { + return static_cast(storage.function_table->call_target(storage, typeid(T))); + } + template + const T * target() const EA_NOEXCEPT + { + return static_cast(storage.function_table->call_target(storage, typeid(T))); + } +#endif + + operator bool() const EA_NOEXCEPT + { + return call != nullptr; + } + +private: + detail::total_storage_type storage; + Result (*call)(const detail::functor_storage_type&); + + template + void initialize(T functor, Allocator && allocator) + { + call = &detail::function_table_inplace_specialization::template call; + detail::init_function_table(storage); + detail::function_table_inplace_specialization::store_allocator(storage, EASTL_FORWARD(Allocator, allocator)); + detail::function_table_inplace_specialization::store_functor(storage, EASTL_FORWARD(T, functor)); + } + + typedef Result(*Empty_Function_Type)(); + + void initialize_empty() EA_NOEXCEPT + { + typedef EASTLAllocatorType Allocator; + static_assert(detail::is_inplace_allocated::value, "The empty function should benefit from small functor optimization"); + + detail::init_function_table(storage); + detail::function_table_inplace_specialization::store_allocator(storage, Allocator()); + detail::function_table_inplace_specialization::store_functor(storage, nullptr); + call = nullptr; + } +}; + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// eastl::function +// single argument case +// +template +class function + : public detail::typedeffer +{ +public: + function() EA_NOEXCEPT + { + initialize_empty(); + } + + function(std::nullptr_t) EA_NOEXCEPT + { + initialize_empty(); + } + + function(function && other) EA_NOEXCEPT + { + initialize_empty(); + swap(other); + } + + function(const function & other) + : call(other.call) + { + other.storage.function_table->call_copy(storage, other.storage); + } + + template + function(T functor, + typename eastl::enable_if::value, detail::empty_struct>::type = detail::empty_struct()) FUNC_TEMPLATE_NOEXCEPT(T, EASTLAllocatorType) + { + if (detail::is_null(functor)) + { + initialize_empty(); + } + else + { + initialize(detail::to_functor(EASTL_FORWARD(T, functor)), EASTLAllocatorType()); + } + } + + template + function(eastl::allocator_arg_t, const Allocator &) + { + // ignore the allocator because I don't allocate + initialize_empty(); + } + + template + function(eastl::allocator_arg_t, const Allocator &, std::nullptr_t) + { + // ignore the allocator because I don't allocate + initialize_empty(); + } + + + template + function(eastl::allocator_arg_t, const Allocator & allocator, T functor, + typename eastl::enable_if::value, detail::empty_struct>::type = detail::empty_struct()) + FUNC_TEMPLATE_NOEXCEPT(T, Allocator) + { + if (detail::is_null(functor)) + { + initialize_empty(); + } + else + { + initialize(detail::to_functor(EASTL_FORWARD(T, functor)), Allocator(allocator)); + } + } + + template + function(eastl::allocator_arg_t, const Allocator & allocator, const function & other) + : call(other.call) + { + typedef typename eastl::allocator_traits::template rebind_alloc MyAllocator; + + // first try to see if the allocator matches the target type + detail::function_table_storage_type function_table_for_allocator = &detail::get_default_function_table::value_type, Allocator>(); + if (other.storage.function_table == function_table_for_allocator) + { + detail::init_function_table::value_type, Allocator>(storage); + detail::function_table_inplace_specialization::store_allocator(storage, Allocator(allocator)); + function_table_for_allocator->call_copy_functor_only(storage, other.storage); + } + // if it does not, try to see if the target contains my type. this + // breaks the recursion of the last case. otherwise repeated copies + // would allocate more and more memory + else + { + detail::function_table_storage_type function_table_for_function = &detail::get_default_function_table(); + if (other.storage.function_table == function_table_for_function) + { + detail::init_function_table(storage); + detail::function_table_inplace_specialization::store_allocator(storage, MyAllocator(allocator)); + function_table_for_function->call_copy_functor_only(storage, other.storage); + } + else + { + // else store the other function as my target + initialize(other, MyAllocator(allocator)); + } + } + } + + template + function(eastl::allocator_arg_t, const Allocator &, function && other) EA_NOEXCEPT + { + // ignore the allocator because I don't allocate + initialize_empty(); + swap(other); + } + + function & operator=(function other) EA_NOEXCEPT + { + swap(other); + return *this; + } + + ~function() EA_NOEXCEPT + { + storage.function_table->call_destroy(storage); + } + + Result operator()(Argument0 argument0) const + { + return call(storage.functor, EASTL_FORWARD(Argument0, argument0)); + } + + template + void assign(T && functor, const Allocator & allocator) FUNC_TEMPLATE_NOEXCEPT(T, Allocator) + { + function(eastl::allocator_arg, allocator, functor).swap(*this); + } + + void swap(function & other) EA_NOEXCEPT + { + detail::total_storage_type temp_storage; + other.storage.function_table->call_move_and_destroy(temp_storage, EASTL_MOVE(other.storage)); + storage.function_table->call_move_and_destroy(other.storage, EASTL_MOVE(storage)); + temp_storage.function_table->call_move_and_destroy(storage, EASTL_MOVE(temp_storage)); + + eastl::swap(call, other.call); + } + +#ifndef FUNC_NO_RTTI + const std::type_info & target_type() const EA_NOEXCEPT + { + return storage.function_table->call_type_id(); + } + template + T * target() EA_NOEXCEPT + { + return static_cast(storage.function_table->call_target(storage, typeid(T))); + } + template + const T * target() const EA_NOEXCEPT + { + return static_cast(storage.function_table->call_target(storage, typeid(T))); + } +#endif + + operator bool() const EA_NOEXCEPT + { + return call != nullptr; + } + +private: + detail::total_storage_type storage; + Result (*call)(const detail::functor_storage_type &, Argument0); + + template + void initialize(T functor, Allocator && allocator) + { + call = &detail::function_table_inplace_specialization::template call; + detail::init_function_table(storage); + detail::function_table_inplace_specialization::store_allocator(storage, EASTL_FORWARD(Allocator, allocator)); + detail::function_table_inplace_specialization::store_functor(storage, EASTL_FORWARD(T, functor)); + } + + typedef Result(*Empty_Function_Type)(Argument0); + + void initialize_empty() EA_NOEXCEPT + { + typedef EASTLAllocatorType Allocator; + static_assert(detail::is_inplace_allocated::value, "The empty function should benefit from small functor optimization"); + + detail::init_function_table(storage); + detail::function_table_inplace_specialization::store_allocator(storage, Allocator()); + detail::function_table_inplace_specialization::store_functor(storage, nullptr); + call = nullptr; + } +}; + +#endif // EASTL_VARIADIC_TEMPLATES_ENABLED + +template +bool operator==(std::nullptr_t, const function & rhs) EA_NOEXCEPT +{ + return !rhs; +} +template +bool operator==(const function & lhs, std::nullptr_t) EA_NOEXCEPT +{ + return !lhs; +} +template +bool operator!=(std::nullptr_t, const function & rhs) EA_NOEXCEPT +{ + return rhs; +} +template +bool operator!=(const function & lhs, std::nullptr_t) EA_NOEXCEPT +{ + return lhs; +} + +template +void swap(function & lhs, function & rhs) +{ + lhs.swap(rhs); +} + +} // end namespace func + + +// +// This type trait is used by std::scoped_allocator_adaptor and may be used by custom allocators to determine whether the +// object being constructed is itself capable of using an allocator (e.g. is a container), in which case an allocator +// should be passed to its constructor. +// reference: http://en.cppreference.com/w/cpp/memory/uses_allocator +// namespace eastl +// { +// uncomment if we ever implemented scoped_allocator_adaptor. +// +// #if EASTL_VARIADIC_TEMPLATES_ENABLED +// template +// struct uses_allocator, Allocator> + // : public eastl::true_type +// { +// }; +// #else +// // single argument case +// template +// struct uses_allocator, Allocator> + // : public eastl::true_type +// { +// }; +// #endif +// } + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FUNC_TEMPLATE_NOEXCEPT +#undef FUNC_NO_RTTI + +#endif // EASTL_INTERNAL_FUNCTION_H diff --git a/libs/eastl/include/EASTL/internal/functional_base.h b/libs/eastl/include/EASTL/internal/functional_base.h new file mode 100644 index 0000000..f4a7b6d --- /dev/null +++ b/libs/eastl/include/EASTL/internal/functional_base.h @@ -0,0 +1,240 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_FUNCTIONAL_BASE_H +#define EASTL_INTERNAL_FUNCTIONAL_BASE_H + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include + +namespace eastl +{ + // foward declaration for swap + template + inline void swap(T& a, T& b) EA_NOEXCEPT_IF(eastl::is_nothrow_move_constructible::value && + eastl::is_nothrow_move_assignable::value); + + /// allocator_arg_t + /// + /// allocator_arg_t is an empty class type used to disambiguate the overloads of + /// constructors and member functions of allocator-aware objects, including tuple, + /// function, promise, and packaged_task. + /// http://en.cppreference.com/w/cpp/memory/allocator_arg_t + /// + struct allocator_arg_t + {}; + + + /// allocator_arg + /// + /// allocator_arg is a constant of type allocator_arg_t used to disambiguate, at call site, + /// the overloads of the constructors and member functions of allocator-aware objects, + /// such as tuple, function, promise, and packaged_task. + /// http://en.cppreference.com/w/cpp/memory/allocator_arg + /// + #if !defined(EA_COMPILER_NO_CONSTEXPR) + EA_CONSTEXPR allocator_arg_t allocator_arg = allocator_arg_t(); + #endif + + + template + struct unary_function + { + typedef Argument argument_type; + typedef Result result_type; + }; + + + template + struct binary_function + { + typedef Argument1 first_argument_type; + typedef Argument2 second_argument_type; + typedef Result result_type; + }; + + + /// less + template + struct less : public binary_function + { + EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const + { return a < b; } + }; + + // http://en.cppreference.com/w/cpp/utility/functional/less_void + template <> + struct less + { + template + EA_CPP14_CONSTEXPR auto operator()(A&& a, B&& b) const + -> decltype(eastl::forward(a) < eastl::forward(b)) + { return eastl::forward(a) < eastl::forward(b); } + }; + + + /// reference_wrapper + /// + /// This is currently a placeholder and isn't complete yet. + /// reference_wrapper is a class that emulates a C++ reference while adding some flexibility. + /// + template + class reference_wrapper + { + public: + typedef T type; + + reference_wrapper(T&) EA_NOEXCEPT; + #if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) + reference_wrapper(T&&) = delete; + #endif + reference_wrapper(const reference_wrapper& x) EA_NOEXCEPT; + + reference_wrapper& operator=(const reference_wrapper& x) EA_NOEXCEPT; + + operator T& () const EA_NOEXCEPT; + T& get() const EA_NOEXCEPT; + + #if EASTL_VARIADIC_TEMPLATES_ENABLED + template + typename eastl::result_of::type operator() (ArgTypes&&...) const; + #endif + }; + + + // reference_wrapper-specific utilties + template + reference_wrapper ref(T& t) EA_NOEXCEPT; + + #if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) + template + void ref(const T&&) = delete; + #endif + + template + reference_wrapper ref(reference_wrappert) EA_NOEXCEPT; + + template + reference_wrapper cref(const T& t) EA_NOEXCEPT; + + #if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) + template + void cref(const T&&) = delete; + #endif + + template + reference_wrapper cref(reference_wrapper t) EA_NOEXCEPT; + + + // reference_wrapper-specific type traits + template + struct is_reference_wrapper_helper + : public eastl::false_type {}; + + template + struct is_reference_wrapper_helper > + : public eastl::true_type {}; + + template + struct is_reference_wrapper + : public eastl::is_reference_wrapper_helper::type> {}; + + + // Helper which adds a reference to a type when given a reference_wrapper of that type. + template + struct remove_reference_wrapper + { typedef T type; }; + + template + struct remove_reference_wrapper< eastl::reference_wrapper > + { typedef T& type; }; + + template + struct remove_reference_wrapper< const eastl::reference_wrapper > + { typedef T& type; }; + + + /////////////////////////////////////////////////////////////////////// + // bind + /////////////////////////////////////////////////////////////////////// + + /// bind1st + /// + template + class binder1st : public unary_function + { + protected: + typename Operation::first_argument_type value; + Operation op; + + public: + binder1st(const Operation& x, const typename Operation::first_argument_type& y) + : value(y), op(x) { } + + typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const + { return op(value, x); } + + typename Operation::result_type operator()(typename Operation::second_argument_type& x) const + { return op(value, x); } + }; + + + template + inline binder1st bind1st(const Operation& op, const T& x) + { + typedef typename Operation::first_argument_type value; + return binder1st(op, value(x)); + } + + + /// bind2nd + /// + template + class binder2nd : public unary_function + { + protected: + Operation op; + typename Operation::second_argument_type value; + + public: + binder2nd(const Operation& x, const typename Operation::second_argument_type& y) + : op(x), value(y) { } + + typename Operation::result_type operator()(const typename Operation::first_argument_type& x) const + { return op(x, value); } + + typename Operation::result_type operator()(typename Operation::first_argument_type& x) const + { return op(x, value); } + }; + + + template + inline binder2nd bind2nd(const Operation& op, const T& x) + { + typedef typename Operation::second_argument_type value; + return binder2nd(op, value(x)); + } + +} // namespace eastl + +#endif // Header include guard + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/generic_iterator.h b/libs/eastl/include/EASTL/internal/generic_iterator.h new file mode 100644 index 0000000..8aa630f --- /dev/null +++ b/libs/eastl/include/EASTL/internal/generic_iterator.h @@ -0,0 +1,229 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Implements a generic iterator from a given iteratable type, such as a pointer. +// We cannot put this file into our own iterator.h file because we need to +// still be able to use this file when we have our iterator.h disabled. +// +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_GENERIC_ITERATOR_H +#define EASTL_INTERNAL_GENERIC_ITERATOR_H + + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include +#include +#include + + +#ifdef _MSC_VER + #pragma warning(push) // VC++ generates a bogus warning that you cannot code away. + #pragma warning(disable: 4619) // There is no warning number 'number'. + #pragma warning(disable: 4217) // Member template functions cannot be used for copy-assignment or copy-construction. +#endif + + +namespace eastl +{ + + /// generic_iterator + /// + /// Converts something which can be iterated into a formal iterator. + /// While this class' primary purpose is to allow the conversion of + /// a pointer to an iterator, you can convert anything else to an + /// iterator by defining an iterator_traits<> specialization for that + /// object type. See EASTL iterator.h for this. + /// + /// Example usage: + /// typedef generic_iterator IntArrayIterator; + /// typedef generic_iterator IntArrayIteratorOther; + /// + template + class generic_iterator + { + protected: + Iterator mIterator; + + public: + typedef typename eastl::iterator_traits::iterator_category iterator_category; + typedef typename eastl::iterator_traits::value_type value_type; + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::iterator_traits::reference reference; + typedef typename eastl::iterator_traits::pointer pointer; + typedef Iterator iterator_type; + typedef iterator_type wrapped_iterator_type; // This is not in the C++ Standard; it's used by use to identify it as a wrapping iterator type. + typedef Container container_type; + typedef generic_iterator this_type; + + generic_iterator() + : mIterator(iterator_type()) { } + + explicit generic_iterator(const iterator_type& x) + : mIterator(x) { } + + this_type& operator=(const iterator_type& x) + { mIterator = x; return *this; } + + template + generic_iterator(const generic_iterator& x) + : mIterator(x.base()) { } + + reference operator*() const + { return *mIterator; } + + pointer operator->() const + { return mIterator; } + + this_type& operator++() + { ++mIterator; return *this; } + + this_type operator++(int) + { return this_type(mIterator++); } + + this_type& operator--() + { --mIterator; return *this; } + + this_type operator--(int) + { return this_type(mIterator--); } + + reference operator[](const difference_type& n) const + { return mIterator[n]; } + + this_type& operator+=(const difference_type& n) + { mIterator += n; return *this; } + + this_type operator+(const difference_type& n) const + { return this_type(mIterator + n); } + + this_type& operator-=(const difference_type& n) + { mIterator -= n; return *this; } + + this_type operator-(const difference_type& n) const + { return this_type(mIterator - n); } + + const iterator_type& base() const + { return mIterator; } + + }; // class generic_iterator + + + template + inline bool operator==(const generic_iterator& lhs, const generic_iterator& rhs) + { return lhs.base() == rhs.base(); } + + template + inline bool operator==(const generic_iterator& lhs, const generic_iterator& rhs) + { return lhs.base() == rhs.base(); } + + template + inline bool operator!=(const generic_iterator& lhs, const generic_iterator& rhs) + { return lhs.base() != rhs.base(); } + + template + inline bool operator!=(const generic_iterator& lhs, const generic_iterator& rhs) + { return lhs.base() != rhs.base(); } + + template + inline bool operator<(const generic_iterator& lhs, const generic_iterator& rhs) + { return lhs.base() < rhs.base(); } + + template + inline bool operator<(const generic_iterator& lhs, const generic_iterator& rhs) + { return lhs.base() < rhs.base(); } + + template + inline bool operator>(const generic_iterator& lhs, const generic_iterator& rhs) + { return lhs.base() > rhs.base(); } + + template + inline bool operator>(const generic_iterator& lhs, const generic_iterator& rhs) + { return lhs.base() > rhs.base(); } + + template + inline bool operator<=(const generic_iterator& lhs, const generic_iterator& rhs) + { return lhs.base() <= rhs.base(); } + + template + inline bool operator<=(const generic_iterator& lhs, const generic_iterator& rhs) + { return lhs.base() <= rhs.base(); } + + template + inline bool operator>=(const generic_iterator& lhs, const generic_iterator& rhs) + { return lhs.base() >= rhs.base(); } + + template + inline bool operator>=(const generic_iterator& lhs, const generic_iterator& rhs) + { return lhs.base() >= rhs.base(); } + + template + inline typename generic_iterator::difference_type + operator-(const generic_iterator& lhs, const generic_iterator& rhs) + { return lhs.base() - rhs.base(); } + + template + inline generic_iterator + operator+(typename generic_iterator::difference_type n, const generic_iterator& x) + { return generic_iterator(x.base() + n); } + + + + /// is_generic_iterator + /// + /// Tells if an iterator is one of these generic_iterators. This is useful if you want to + /// write code that uses miscellaneous iterators but wants to tell if they are generic_iterators. + /// A primary reason to do so is that you can get at the pointer within the generic_iterator. + /// + template + struct is_generic_iterator : public false_type { }; + + template + struct is_generic_iterator > : public true_type { }; + + + /// unwrap_generic_iterator + /// + /// Returns Iterator::get_base() if it's a generic_iterator, else returns Iterator as-is. + /// + /// Example usage: + /// vector intVector; + /// eastl::generic_iterator::iterator> genericIterator(intVector.begin()); + /// vector::iterator it = unwrap_generic_iterator(genericIterator); + /// + template + inline typename eastl::is_iterator_wrapper_helper::value>::iterator_type unwrap_generic_iterator(Iterator it) + { return eastl::is_iterator_wrapper_helper::value>::get_base(it); } + + +} // namespace eastl + + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + + +#endif // Header include guard + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/hashtable.h b/libs/eastl/include/EASTL/internal/hashtable.h new file mode 100644 index 0000000..4a56556 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/hashtable.h @@ -0,0 +1,2984 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements a hashtable, much like the C++11 unordered_set/unordered_map. +// proposed classes. +// The primary distinctions between this hashtable and C++11 unordered containers are: +// - hashtable is savvy to an environment that doesn't have exception handling, +// as is sometimes the case with console or embedded environments. +// - hashtable is slightly more space-efficient than a conventional std hashtable +// implementation on platforms with 64 bit size_t. This is +// because std STL uses size_t (64 bits) in data structures whereby 32 bits +// of data would be fine. +// - hashtable can contain objects with alignment requirements. TR1 hash tables +// cannot do so without a bit of tedious non-portable effort. +// - hashtable supports debug memory naming natively. +// - hashtable provides a find function that lets you specify a type that is +// different from the hash table key type. This is particularly useful for +// the storing of string objects but finding them by char pointers. +// - hashtable provides a lower level insert function which lets the caller +// specify the hash code and optionally the node instance. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_HASHTABLE_H +#define EASTL_INTERNAL_HASHTABLE_H + + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + #pragma warning(push, 0) + #include + #include + #pragma warning(pop) +#else + #include + #include +#endif + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4512) // 'class' : assignment operator could not be generated. + #pragma warning(disable: 4530) // C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc + #pragma warning(disable: 4571) // catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught. +#endif + + +namespace eastl +{ + + /// EASTL_HASHTABLE_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_HASHTABLE_DEFAULT_NAME + #define EASTL_HASHTABLE_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " hashtable" // Unless the user overrides something, this is "EASTL hashtable". + #endif + + + /// EASTL_HASHTABLE_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_HASHTABLE_DEFAULT_ALLOCATOR + #define EASTL_HASHTABLE_DEFAULT_ALLOCATOR allocator_type(EASTL_HASHTABLE_DEFAULT_NAME) + #endif + + + /// kHashtableAllocFlagBuckets + /// Flag to allocator which indicates that we are allocating buckets and not nodes. + enum { kHashtableAllocFlagBuckets = 0x00400000 }; + + + /// gpEmptyBucketArray + /// + /// A shared representation of an empty hash table. This is present so that + /// a new empty hashtable allocates no memory. It has two entries, one for + /// the first lone empty (NULL) bucket, and one for the non-NULL trailing sentinel. + /// + extern EASTL_API void* gpEmptyBucketArray[2]; + + + /// EASTL_MACRO_SWAP + /// + /// Use EASTL_MACRO_SWAP because GCC (at least v4.6-4.8) has a bug where it fails to compile eastl::swap(mpBucketArray, x.mpBucketArray). + /// + #define EASTL_MACRO_SWAP(Type, a, b) \ + { Type temp = a; a = b; b = temp; } + + + /// hash_node + /// + /// A hash_node stores an element in a hash table, much like a + /// linked list node stores an element in a linked list. + /// A hash_node additionally can, via template parameter, + /// store a hash code in the node to speed up hash calculations + /// and comparisons in some cases. + /// + template + struct hash_node; + + EA_DISABLE_VC_WARNING(4625) // disable warning: "copy constructor could not be generated because a base class copy constructor is inaccessible or deleted" + #ifdef EA_COMPILER_MSVC_2015 + EA_DISABLE_VC_WARNING(5026) // disable warning: "move constructor was implicitly defined as deleted" + #endif + template + struct hash_node + { + Value mValue; + hash_node* mpNext; + eastl_size_t mnHashCode; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + } EASTL_MAY_ALIAS; + + template + struct hash_node + { + Value mValue; + hash_node* mpNext; + } EASTL_MAY_ALIAS; + + #ifdef EA_COMPILER_MSVC_2015 + EA_RESTORE_VC_WARNING() + #endif + EA_RESTORE_VC_WARNING() + + + + /// node_iterator_base + /// + /// Node iterators iterate nodes within a given bucket. + /// + /// We define a base class here because it is shared by both const and + /// non-const iterators. + /// + template + struct node_iterator_base + { + public: + typedef hash_node node_type; + + node_type* mpNode; + + public: + node_iterator_base(node_type* pNode) + : mpNode(pNode) { } + + void increment() + { mpNode = mpNode->mpNext; } + }; + + + + /// node_iterator + /// + /// Node iterators iterate nodes within a given bucket. + /// + /// The bConst parameter defines if the iterator is a const_iterator + /// or an iterator. + /// + template + struct node_iterator : public node_iterator_base + { + public: + typedef node_iterator_base base_type; + typedef node_iterator this_type; + typedef typename base_type::node_type node_type; + typedef Value value_type; + typedef typename type_select::type pointer; + typedef typename type_select::type reference; + typedef ptrdiff_t difference_type; + typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; + + public: + explicit node_iterator(node_type* pNode = NULL) + : base_type(pNode) { } + + node_iterator(const node_iterator& x) + : base_type(x.mpNode) { } + + reference operator*() const + { return base_type::mpNode->mValue; } + + pointer operator->() const + { return &(base_type::mpNode->mValue); } + + node_iterator& operator++() + { base_type::increment(); return *this; } + + node_iterator operator++(int) + { node_iterator temp(*this); base_type::increment(); return temp; } + + }; // node_iterator + + + + /// hashtable_iterator_base + /// + /// A hashtable_iterator iterates the entire hash table and not just + /// nodes within a single bucket. Users in general will use a hash + /// table iterator much more often, as it is much like other container + /// iterators (e.g. vector::iterator). + /// + /// We define a base class here because it is shared by both const and + /// non-const iterators. + /// + template + struct hashtable_iterator_base + { + public: + typedef hashtable_iterator_base this_type; + typedef hash_node node_type; + + protected: + template + friend class hashtable; + + template + friend struct hashtable_iterator; + + template + friend bool operator==(const hashtable_iterator_base&, const hashtable_iterator_base&); + + template + friend bool operator!=(const hashtable_iterator_base&, const hashtable_iterator_base&); + + node_type* mpNode; // Current node within current bucket. + node_type** mpBucket; // Current bucket. + + public: + hashtable_iterator_base(node_type* pNode, node_type** pBucket) + : mpNode(pNode), mpBucket(pBucket) { } + + void increment_bucket() + { + ++mpBucket; + while(*mpBucket == NULL) // We store an extra bucket with some non-NULL value at the end + ++mpBucket; // of the bucket array so that finding the end of the bucket + mpNode = *mpBucket; // array is quick and simple. + } + + void increment() + { + mpNode = mpNode->mpNext; + + while(mpNode == NULL) + mpNode = *++mpBucket; + } + + }; // hashtable_iterator_base + + + + + /// hashtable_iterator + /// + /// A hashtable_iterator iterates the entire hash table and not just + /// nodes within a single bucket. Users in general will use a hash + /// table iterator much more often, as it is much like other container + /// iterators (e.g. vector::iterator). + /// + /// The bConst parameter defines if the iterator is a const_iterator + /// or an iterator. + /// + template + struct hashtable_iterator : public hashtable_iterator_base + { + public: + typedef hashtable_iterator_base base_type; + typedef hashtable_iterator this_type; + typedef hashtable_iterator this_type_non_const; + typedef typename base_type::node_type node_type; + typedef Value value_type; + typedef typename type_select::type pointer; + typedef typename type_select::type reference; + typedef ptrdiff_t difference_type; + typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; + + public: + hashtable_iterator(node_type* pNode = NULL, node_type** pBucket = NULL) + : base_type(pNode, pBucket) { } + + hashtable_iterator(node_type** pBucket) + : base_type(*pBucket, pBucket) { } + + hashtable_iterator(const this_type_non_const& x) + : base_type(x.mpNode, x.mpBucket) { } + + reference operator*() const + { return base_type::mpNode->mValue; } + + pointer operator->() const + { return &(base_type::mpNode->mValue); } + + hashtable_iterator& operator++() + { base_type::increment(); return *this; } + + hashtable_iterator operator++(int) + { hashtable_iterator temp(*this); base_type::increment(); return temp; } + + const node_type* get_node() const + { return base_type::mpNode; } + + }; // hashtable_iterator + + + + + /// ht_distance + /// + /// This function returns the same thing as distance() for + /// forward iterators but returns zero for input iterators. + /// The reason why is that input iterators can only be read + /// once, and calling distance() on an input iterator destroys + /// the ability to read it. This ht_distance is used only for + /// optimization and so the code will merely work better with + /// forward iterators that input iterators. + /// + template + inline typename eastl::iterator_traits::difference_type + distance_fw_impl(Iterator /*first*/, Iterator /*last*/, EASTL_ITC_NS::input_iterator_tag) + { + return 0; + } + + template + inline typename eastl::iterator_traits::difference_type + distance_fw_impl(Iterator first, Iterator last, EASTL_ITC_NS::forward_iterator_tag) + { return eastl::distance(first, last); } + + template + inline typename eastl::iterator_traits::difference_type + ht_distance(Iterator first, Iterator last) + { + typedef typename eastl::iterator_traits::iterator_category IC; + return distance_fw_impl(first, last, IC()); + } + + + + + /// mod_range_hashing + /// + /// Implements the algorithm for conversion of a number in the range of + /// [0, SIZE_T_MAX] to the range of [0, BucketCount). + /// + struct mod_range_hashing + { + uint32_t operator()(size_t r, uint32_t n) const + { return r % n; } + }; + + + /// default_ranged_hash + /// + /// Default ranged hash function H. In principle it should be a + /// function object composed from objects of type H1 and H2 such that + /// h(k, n) = h2(h1(k), n), but that would mean making extra copies of + /// h1 and h2. So instead we'll just use a tag to tell class template + /// hashtable to do that composition. + /// + struct default_ranged_hash{ }; + + + /// prime_rehash_policy + /// + /// Default value for rehash policy. Bucket size is (usually) the + /// smallest prime that keeps the load factor small enough. + /// + struct EASTL_API prime_rehash_policy + { + public: + float mfMaxLoadFactor; + float mfGrowthFactor; + mutable uint32_t mnNextResize; + + public: + prime_rehash_policy(float fMaxLoadFactor = 1.f) + : mfMaxLoadFactor(fMaxLoadFactor), mfGrowthFactor(2.f), mnNextResize(0) { } + + float GetMaxLoadFactor() const + { return mfMaxLoadFactor; } + + /// Return a bucket count no greater than nBucketCountHint, + /// Don't update member variables while at it. + static uint32_t GetPrevBucketCountOnly(uint32_t nBucketCountHint); + + /// Return a bucket count no greater than nBucketCountHint. + /// This function has a side effect of updating mnNextResize. + uint32_t GetPrevBucketCount(uint32_t nBucketCountHint) const; + + /// Return a bucket count no smaller than nBucketCountHint. + /// This function has a side effect of updating mnNextResize. + uint32_t GetNextBucketCount(uint32_t nBucketCountHint) const; + + /// Return a bucket count appropriate for nElementCount elements. + /// This function has a side effect of updating mnNextResize. + uint32_t GetBucketCount(uint32_t nElementCount) const; + + /// nBucketCount is current bucket count, nElementCount is current element count, + /// and nElementAdd is number of elements to be inserted. Do we need + /// to increase bucket count? If so, return pair(true, n), where + /// n is the new bucket count. If not, return pair(false, 0). + eastl::pair + GetRehashRequired(uint32_t nBucketCount, uint32_t nElementCount, uint32_t nElementAdd) const; + }; + + + + + + /////////////////////////////////////////////////////////////////////// + // Base classes for hashtable. We define these base classes because + // in some cases we want to do different things depending on the + // value of a policy class. In some cases the policy class affects + // which member functions and nested typedefs are defined; we handle that + // by specializing base class templates. Several of the base class templates + // need to access other members of class template hashtable, so we use + // the "curiously recurring template pattern" (parent class is templated + // on type of child class) for them. + /////////////////////////////////////////////////////////////////////// + + + /// rehash_base + /// + /// Give hashtable the get_max_load_factor functions if the rehash + /// policy is prime_rehash_policy. + /// + template + struct rehash_base { }; + + template + struct rehash_base + { + // Returns the max load factor, which is the load factor beyond + // which we rebuild the container with a new bucket count. + float get_max_load_factor() const + { + const Hashtable* const pThis = static_cast(this); + return pThis->rehash_policy().GetMaxLoadFactor(); + } + + // If you want to make the hashtable never rehash (resize), + // set the max load factor to be a very high number (e.g. 100000.f). + void set_max_load_factor(float fMaxLoadFactor) + { + Hashtable* const pThis = static_cast(this); + pThis->rehash_policy(prime_rehash_policy(fMaxLoadFactor)); + } + }; + + + + + /// hash_code_base + /// + /// Encapsulates two policy issues that aren't quite orthogonal. + /// (1) The difference between using a ranged hash function and using + /// the combination of a hash function and a range-hashing function. + /// In the former case we don't have such things as hash codes, so + /// we have a dummy type as placeholder. + /// (2) Whether or not we cache hash codes. Caching hash codes is + /// meaningless if we have a ranged hash function. This is because + /// a ranged hash function converts an object directly to its + /// bucket index without ostensibly using a hash code. + /// We also put the key extraction and equality comparison function + /// objects here, for convenience. + /// + template + struct hash_code_base; + + + /// hash_code_base + /// + /// Specialization: ranged hash function, no caching hash codes. + /// H1 and H2 are provided but ignored. We define a dummy hash code type. + /// + template + struct hash_code_base + { + protected: + ExtractKey mExtractKey; // To do: Make this member go away entirely, as it never has any data. + Equal mEqual; // To do: Make this instance use zero space when it is zero size. + H mRangedHash; // To do: Make this instance use zero space when it is zero size + + public: + H1 hash_function() const + { return H1(); } + + Equal equal_function() const // Deprecated. Use key_eq() instead, as key_eq is what the new C++ standard + { return mEqual; } // has specified in its hashtable (unordered_*) proposal. + + const Equal& key_eq() const + { return mEqual; } + + Equal& key_eq() + { return mEqual; } + + protected: + typedef void* hash_code_t; + typedef uint32_t bucket_index_t; + + hash_code_base(const ExtractKey& extractKey, const Equal& eq, const H1&, const H2&, const H& h) + : mExtractKey(extractKey), mEqual(eq), mRangedHash(h) { } + + hash_code_t get_hash_code(const Key& key) const + { + EA_UNUSED(key); + return NULL; + } + + bucket_index_t bucket_index(hash_code_t, uint32_t) const + { return (bucket_index_t)0; } + + bucket_index_t bucket_index(const Key& key, hash_code_t, uint32_t nBucketCount) const + { return (bucket_index_t)mRangedHash(key, nBucketCount); } + + bucket_index_t bucket_index(const hash_node* pNode, uint32_t nBucketCount) const + { return (bucket_index_t)mRangedHash(mExtractKey(pNode->mValue), nBucketCount); } + + bool compare(const Key& key, hash_code_t, hash_node* pNode) const + { return mEqual(key, mExtractKey(pNode->mValue)); } + + void copy_code(hash_node*, const hash_node*) const + { } // Nothing to do. + + void set_code(hash_node* pDest, hash_code_t c) const + { + EA_UNUSED(pDest); + EA_UNUSED(c); + } + + void base_swap(hash_code_base& x) + { + eastl::swap(mExtractKey, x.mExtractKey); + eastl::swap(mEqual, x.mEqual); + eastl::swap(mRangedHash, x.mRangedHash); + } + + }; // hash_code_base + + + + // No specialization for ranged hash function while caching hash codes. + // That combination is meaningless, and trying to do it is an error. + + + /// hash_code_base + /// + /// Specialization: ranged hash function, cache hash codes. + /// This combination is meaningless, so we provide only a declaration + /// and no definition. + /// + template + struct hash_code_base; + + + + /// hash_code_base + /// + /// Specialization: hash function and range-hashing function, + /// no caching of hash codes. H is provided but ignored. + /// Provides typedef and accessor required by TR1. + /// + template + struct hash_code_base + { + protected: + ExtractKey mExtractKey; + Equal mEqual; + H1 m_h1; + H2 m_h2; + + public: + typedef H1 hasher; + + H1 hash_function() const + { return m_h1; } + + Equal equal_function() const // Deprecated. Use key_eq() instead, as key_eq is what the new C++ standard + { return mEqual; } // has specified in its hashtable (unordered_*) proposal. + + const Equal& key_eq() const + { return mEqual; } + + Equal& key_eq() + { return mEqual; } + + protected: + typedef size_t hash_code_t; + typedef uint32_t bucket_index_t; + typedef hash_node node_type; + + hash_code_base(const ExtractKey& ex, const Equal& eq, const H1& h1, const H2& h2, const default_ranged_hash&) + : mExtractKey(ex), mEqual(eq), m_h1(h1), m_h2(h2) { } + + hash_code_t get_hash_code(const Key& key) const + { return (hash_code_t)m_h1(key); } + + bucket_index_t bucket_index(hash_code_t c, uint32_t nBucketCount) const + { return (bucket_index_t)m_h2(c, nBucketCount); } + + bucket_index_t bucket_index(const Key&, hash_code_t c, uint32_t nBucketCount) const + { return (bucket_index_t)m_h2(c, nBucketCount); } + + bucket_index_t bucket_index(const node_type* pNode, uint32_t nBucketCount) const + { return (bucket_index_t)m_h2((hash_code_t)m_h1(mExtractKey(pNode->mValue)), nBucketCount); } + + bool compare(const Key& key, hash_code_t, node_type* pNode) const + { return mEqual(key, mExtractKey(pNode->mValue)); } + + void copy_code(node_type*, const node_type*) const + { } // Nothing to do. + + void set_code(node_type*, hash_code_t) const + { } // Nothing to do. + + void base_swap(hash_code_base& x) + { + eastl::swap(mExtractKey, x.mExtractKey); + eastl::swap(mEqual, x.mEqual); + eastl::swap(m_h1, x.m_h1); + eastl::swap(m_h2, x.m_h2); + } + + }; // hash_code_base + + + + /// hash_code_base + /// + /// Specialization: hash function and range-hashing function, + /// caching hash codes. H is provided but ignored. + /// Provides typedef and accessor required by TR1. + /// + template + struct hash_code_base + { + protected: + ExtractKey mExtractKey; + Equal mEqual; + H1 m_h1; + H2 m_h2; + + public: + typedef H1 hasher; + + H1 hash_function() const + { return m_h1; } + + Equal equal_function() const // Deprecated. Use key_eq() instead, as key_eq is what the new C++ standard + { return mEqual; } // has specified in its hashtable (unordered_*) proposal. + + const Equal& key_eq() const + { return mEqual; } + + Equal& key_eq() + { return mEqual; } + + protected: + typedef uint32_t hash_code_t; + typedef uint32_t bucket_index_t; + typedef hash_node node_type; + + hash_code_base(const ExtractKey& ex, const Equal& eq, const H1& h1, const H2& h2, const default_ranged_hash&) + : mExtractKey(ex), mEqual(eq), m_h1(h1), m_h2(h2) { } + + hash_code_t get_hash_code(const Key& key) const + { return (hash_code_t)m_h1(key); } + + bucket_index_t bucket_index(hash_code_t c, uint32_t nBucketCount) const + { return (bucket_index_t)m_h2(c, nBucketCount); } + + bucket_index_t bucket_index(const Key&, hash_code_t c, uint32_t nBucketCount) const + { return (bucket_index_t)m_h2(c, nBucketCount); } + + bucket_index_t bucket_index(const node_type* pNode, uint32_t nBucketCount) const + { return (bucket_index_t)m_h2((uint32_t)pNode->mnHashCode, nBucketCount); } + + bool compare(const Key& key, hash_code_t c, node_type* pNode) const + { return (pNode->mnHashCode == c) && mEqual(key, mExtractKey(pNode->mValue)); } + + void copy_code(node_type* pDest, const node_type* pSource) const + { pDest->mnHashCode = pSource->mnHashCode; } + + void set_code(node_type* pDest, hash_code_t c) const + { pDest->mnHashCode = c; } + + void base_swap(hash_code_base& x) + { + eastl::swap(mExtractKey, x.mExtractKey); + eastl::swap(mEqual, x.mEqual); + eastl::swap(m_h1, x.m_h1); + eastl::swap(m_h2, x.m_h2); + } + + }; // hash_code_base + + + + + + /////////////////////////////////////////////////////////////////////////// + /// hashtable + /// + /// Key and Value: arbitrary CopyConstructible types. + /// + /// ExtractKey: function object that takes a object of type Value + /// and returns a value of type Key. + /// + /// Equal: function object that takes two objects of type k and returns + /// a bool-like value that is true if the two objects are considered equal. + /// + /// H1: a hash function. A unary function object with argument type + /// Key and result type size_t. Return values should be distributed + /// over the entire range [0, numeric_limits::max()]. + /// + /// H2: a range-hashing function (in the terminology of Tavori and + /// Dreizin). This is a function which takes the output of H1 and + /// converts it to the range of [0, n]. Usually it merely takes the + /// output of H1 and mods it to n. + /// + /// H: a ranged hash function (Tavori and Dreizin). This is merely + /// a class that combines the functionality of H1 and H2 together, + /// possibly in some way that is somehow improved over H1 and H2 + /// It is a binary function whose argument types are Key and size_t + /// and whose result type is uint32_t. Given arguments k and n, the + /// return value is in the range [0, n). Default: h(k, n) = h2(h1(k), n). + /// If H is anything other than the default, H1 and H2 are ignored, + /// as H is thus overriding H1 and H2. + /// + /// RehashPolicy: Policy class with three members, all of which govern + /// the bucket count. nBucket(n) returns a bucket count no smaller + /// than n. GetBucketCount(n) returns a bucket count appropriate + /// for an element count of n. GetRehashRequired(nBucketCount, nElementCount, nElementAdd) + /// determines whether, if the current bucket count is nBucket and the + /// current element count is nElementCount, we need to increase the bucket + /// count. If so, returns pair(true, n), where n is the new + /// bucket count. If not, returns pair(false, ). + /// + /// Currently it is hard-wired that the number of buckets never + /// shrinks. Should we allow RehashPolicy to change that? + /// + /// bCacheHashCode: true if we store the value of the hash + /// function along with the value. This is a time-space tradeoff. + /// Storing it may improve lookup speed by reducing the number of + /// times we need to call the Equal function. + /// + /// bMutableIterators: true if hashtable::iterator is a mutable + /// iterator, false if iterator and const_iterator are both const + /// iterators. This is true for hash_map and hash_multimap, + /// false for hash_set and hash_multiset. + /// + /// bUniqueKeys: true if the return value of hashtable::count(k) + /// is always at most one, false if it may be an arbitrary number. + /// This is true for hash_set and hash_map and is false for + /// hash_multiset and hash_multimap. + /// + /////////////////////////////////////////////////////////////////////// + /// Note: + /// If you want to make a hashtable never increase its bucket usage, + /// call set_max_load_factor with a very high value such as 100000.f. + /// + /// find_as + /// In order to support the ability to have a hashtable of strings but + /// be able to do efficiently lookups via char pointers (i.e. so they + /// aren't converted to string objects), we provide the find_as + /// function. This function allows you to do a find with a key of a + /// type other than the hashtable key type. See the find_as function + /// for more documentation on this. + /// + /// find_by_hash + /// In the interest of supporting fast operations wherever possible, + /// we provide a find_by_hash function which finds a node using its + /// hash code. This is useful for cases where the node's hash is + /// already known, allowing us to avoid a redundant hash operation + /// in the normal find path. + /// + template + class hashtable + : public rehash_base >, + public hash_code_base + { + public: + typedef Key key_type; + typedef Value value_type; + typedef typename ExtractKey::result_type mapped_type; + typedef hash_code_base hash_code_base_type; + typedef typename hash_code_base_type::hash_code_t hash_code_t; + typedef Allocator allocator_type; + typedef Equal key_equal; + typedef ptrdiff_t difference_type; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef value_type& reference; + typedef const value_type& const_reference; + typedef node_iterator local_iterator; + typedef node_iterator const_local_iterator; + typedef hashtable_iterator iterator; + typedef hashtable_iterator const_iterator; + typedef hash_node node_type; + typedef typename type_select, iterator>::type insert_return_type; + typedef hashtable this_type; + typedef RehashPolicy rehash_policy_type; + typedef ExtractKey extract_key_type; + typedef H1 h1_type; + typedef H2 h2_type; + typedef H h_type; + typedef integral_constant has_unique_keys_type; + + using hash_code_base_type::key_eq; + using hash_code_base_type::hash_function; + using hash_code_base_type::mExtractKey; + using hash_code_base_type::get_hash_code; + using hash_code_base_type::bucket_index; + using hash_code_base_type::compare; + using hash_code_base_type::set_code; + using hash_code_base_type::copy_code; + + static const bool kCacheHashCode = bCacheHashCode; + + enum + { + // This enumeration is deprecated in favor of eastl::kHashtableAllocFlagBuckets. + kAllocFlagBuckets = eastl::kHashtableAllocFlagBuckets // Flag to allocator which indicates that we are allocating buckets and not nodes. + }; + + protected: + node_type** mpBucketArray; + size_type mnBucketCount; + size_type mnElementCount; + RehashPolicy mRehashPolicy; // To do: Use base class optimization to make this go away. + allocator_type mAllocator; // To do: Use base class optimization to make this go away. + + public: + hashtable(size_type nBucketCount, const H1&, const H2&, const H&, const Equal&, const ExtractKey&, + const allocator_type& allocator = EASTL_HASHTABLE_DEFAULT_ALLOCATOR); + + template + hashtable(FowardIterator first, FowardIterator last, size_type nBucketCount, + const H1&, const H2&, const H&, const Equal&, const ExtractKey&, + const allocator_type& allocator = EASTL_HASHTABLE_DEFAULT_ALLOCATOR); // allocator arg removed because VC7.1 fails on the default arg. To do: Make a second version of this function without a default arg. + + hashtable(const hashtable& x); + + // initializer_list ctor support is implemented in subclasses (e.g. hash_set). + // hashtable(initializer_list, size_type nBucketCount, const H1&, const H2&, const H&, + // const Equal&, const ExtractKey&, const allocator_type& allocator = EASTL_HASHTABLE_DEFAULT_ALLOCATOR); + + #if EASTL_MOVE_SEMANTICS_ENABLED + hashtable(this_type&& x); + hashtable(this_type&& x, const allocator_type& allocator); + #endif + + ~hashtable(); + + const allocator_type& get_allocator() const EA_NOEXCEPT; + allocator_type& get_allocator() EA_NOEXCEPT; + void set_allocator(const allocator_type& allocator); + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + public: + iterator begin() EA_NOEXCEPT + { + iterator i(mpBucketArray); + if(!i.mpNode) + i.increment_bucket(); + return i; + } + + const_iterator begin() const EA_NOEXCEPT + { + const_iterator i(mpBucketArray); + if(!i.mpNode) + i.increment_bucket(); + return i; + } + + const_iterator cbegin() const EA_NOEXCEPT + { return begin(); } + + iterator end() EA_NOEXCEPT + { return iterator(mpBucketArray + mnBucketCount); } + + const_iterator end() const EA_NOEXCEPT + { return const_iterator(mpBucketArray + mnBucketCount); } + + const_iterator cend() const EA_NOEXCEPT + { return const_iterator(mpBucketArray + mnBucketCount); } + + // Returns an iterator to the first item in bucket n. + local_iterator begin(size_type n) EA_NOEXCEPT + { return local_iterator(mpBucketArray[n]); } + + const_local_iterator begin(size_type n) const EA_NOEXCEPT + { return const_local_iterator(mpBucketArray[n]); } + + const_local_iterator cbegin(size_type n) const EA_NOEXCEPT + { return const_local_iterator(mpBucketArray[n]); } + + // Returns an iterator to the last item in a bucket returned by begin(n). + local_iterator end(size_type) EA_NOEXCEPT + { return local_iterator(NULL); } + + const_local_iterator end(size_type) const EA_NOEXCEPT + { return const_local_iterator(NULL); } + + const_local_iterator cend(size_type) const EA_NOEXCEPT + { return const_local_iterator(NULL); } + + bool empty() const EA_NOEXCEPT + { return mnElementCount == 0; } + + size_type size() const EA_NOEXCEPT + { return mnElementCount; } + + size_type bucket_count() const EA_NOEXCEPT + { return mnBucketCount; } + + size_type bucket_size(size_type n) const EA_NOEXCEPT + { return (size_type)eastl::distance(begin(n), end(n)); } + + //size_type bucket(const key_type& k) const EA_NOEXCEPT + // { return bucket_index(k, (hash code here), (uint32_t)mnBucketCount); } + + public: + // Returns the ratio of element count to bucket count. A return value of 1 means + // there's an optimal 1 bucket for each element. + float load_factor() const EA_NOEXCEPT + { return (float)mnElementCount / (float)mnBucketCount; } + + // Inherited from the base class. + // Returns the max load factor, which is the load factor beyond + // which we rebuild the container with a new bucket count. + // get_max_load_factor comes from rehash_base. + // float get_max_load_factor() const; + + // Inherited from the base class. + // If you want to make the hashtable never rehash (resize), + // set the max load factor to be a very high number (e.g. 100000.f). + // set_max_load_factor comes from rehash_base. + // void set_max_load_factor(float fMaxLoadFactor); + + /// Generalization of get_max_load_factor. This is an extension that's + /// not present in C++ hash tables (unordered containers). + const rehash_policy_type& rehash_policy() const EA_NOEXCEPT + { return mRehashPolicy; } + + /// Generalization of set_max_load_factor. This is an extension that's + /// not present in C++ hash tables (unordered containers). + void rehash_policy(const rehash_policy_type& rehashPolicy); + + public: + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + insert_return_type emplace(Args&&... args); + + template + iterator emplace_hint(const_iterator position, Args&&... args); + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + insert_return_type emplace(value_type&& value); + iterator emplace_hint(const_iterator position, value_type&& value); + #endif + + insert_return_type emplace(const value_type& value); + iterator emplace_hint(const_iterator position, const value_type& value); + #endif + + #if EASTL_MOVE_SEMANTICS_ENABLED + insert_return_type insert(value_type&& otherValue); + + template // See comments below for the const value_type& equivalent to this function. + insert_return_type insert(hash_code_t c, node_type* pNodeNew, P&& otherValue); + + // Currently limited to value_type instead of P because it collides with insert(InputIterator, InputIterator). + // To allow this to work with templated P we need to implement a compile-time specialization for the + // case that P&& is const_iterator and have that specialization handle insert(InputIterator, InputIterator) + // instead of insert(InputIterator, InputIterator). Curiously, neither libstdc++ nor libc++ + // implement this function either, which suggests they ran into the same problem I did here + // and haven't yet resolved it (at least as of March 2014, GCC 4.8.1). + iterator insert(const_iterator hint, value_type&& value); + #endif + + insert_return_type insert(const value_type& value); + iterator insert(const_iterator, const value_type& value); + + void insert(std::initializer_list ilist); + + template + void insert(InputIterator first, InputIterator last); + + // We provide a version of insert which lets the caller directly specify the hash value and + // a potential node to insert if needed. This allows for less thread contention in the case + // of a thread-shared hash table that's accessed during a mutex lock, because the hash calculation + // and node creation is done outside of the lock. If pNodeNew is supplied by the user (i.e. non-NULL) + // then it must be freeable via the hash table's allocator. If the return value is true then this function + // took over ownership of pNodeNew, else pNodeNew is still owned by the caller to free or to pass + // to another call to insert. pNodeNew need not be assigned the value by the caller, as the insert + // function will assign value to pNodeNew upon insertion into the hash table. pNodeNew may be + // created by the user with the allocate_uninitialized_node function, and freed by the free_uninitialized_node function. + insert_return_type insert(hash_code_t c, node_type* pNodeNew, const value_type& value); + + // Used to allocate and free memory used by insert(const value_type& value, hash_code_t c, node_type* pNodeNew). + node_type* allocate_uninitialized_node(); + void free_uninitialized_node(node_type* pNode); + + public: + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + size_type erase(const key_type& k); + + void clear(); + void clear(bool clearBuckets); // If clearBuckets is true, we free the bucket memory and set the bucket count back to the newly constructed count. + void reset_lose_memory() EA_NOEXCEPT; // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + void rehash(size_type nBucketCount); + + #if EASTL_RESET_ENABLED + void reset() EA_NOEXCEPT; // This function name is deprecated; use reset_lose_memory instead. + #endif + + public: + iterator find(const key_type& key); + const_iterator find(const key_type& key) const; + + /// Implements a find whereby the user supplies a comparison of a different type + /// than the hashtable value_type. A useful case of this is one whereby you have + /// a container of string objects but want to do searches via passing in char pointers. + /// The problem is that without this kind of find, you need to do the expensive operation + /// of converting the char pointer to a string so it can be used as the argument to the + /// find function. + /// + /// Example usage (namespaces omitted for brevity): + /// hash_set hashSet; + /// hashSet.find_as("hello"); // Use default hash and compare. + /// + /// Example usage (note that the predicate uses string as first type and char* as second): + /// hash_set hashSet; + /// hashSet.find_as("hello", hash(), equal_to_2()); + /// + template + iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate); + + template + const_iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate) const; + + template + iterator find_as(const U& u); + + template + const_iterator find_as(const U& u) const; + + // Note: find_by_hash and find_range_by_hash both perform a search based on a hash value. + // It is important to note that multiple hash values may map to the same hash bucket, so + // it would be incorrect to assume all items returned match the hash value that + // was searched for. + + /// Implements a find whereby the user supplies the node's hash code. + /// It returns an iterator to the first element that matches the given hash. However, there may be multiple elements that match the given hash. + iterator find_by_hash(hash_code_t c); + const_iterator find_by_hash(hash_code_t c) const; + iterator find_by_hash(const key_type& k, hash_code_t c); + const_iterator find_by_hash(const key_type& k, hash_code_t c) const; + + // Returns a pair that allows iterating over all nodes in a hash bucket + // first in the pair returned holds the iterator for the beginning of the bucket, + // second in the pair returned holds the iterator for the end of the bucket, + // If no bucket is found, both values in the pair are set to end(). + // + // See also the note above. + eastl::pair find_range_by_hash(hash_code_t c); + eastl::pair find_range_by_hash(hash_code_t c) const; + + size_type count(const key_type& k) const EA_NOEXCEPT; + + eastl::pair equal_range(const key_type& k); + eastl::pair equal_range(const key_type& k) const; + + public: + bool validate() const; + int validate_iterator(const_iterator i) const; + + protected: + iterator DoGetResultIterator(true_type, const insert_return_type& irt) const EA_NOEXCEPT { return irt.first; } + iterator DoGetResultIterator(false_type, const insert_return_type& irt) const EA_NOEXCEPT { return irt; } + + node_type* DoAllocateNodeFromKey(const key_type& key); + void DoFreeNode(node_type* pNode); + void DoFreeNodes(node_type** pBucketArray, size_type); + + node_type** DoAllocateBuckets(size_type n); + void DoFreeBuckets(node_type** pBucketArray, size_type n); + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + eastl::pair DoInsertValue(true_type, Args&&... args); + + template + iterator DoInsertValue(false_type, Args&&... args); + + template + node_type* DoAllocateNode(Args&&... args); + #endif + + #if EASTL_MOVE_SEMANTICS_ENABLED + eastl::pair DoInsertValueExtra(true_type, const key_type& k, hash_code_t c, node_type* pNodeNew, value_type&& value); + eastl::pair DoInsertValue(true_type, value_type&& value); + iterator DoInsertValueExtra(false_type, const key_type& k, hash_code_t c, node_type* pNodeNew, value_type&& value); + iterator DoInsertValue(false_type, value_type&& value); + node_type* DoAllocateNode(value_type&& value); + #endif + + eastl::pair DoInsertValueExtra(true_type, const key_type& k, hash_code_t c, node_type* pNodeNew, const value_type& value); + eastl::pair DoInsertValue(true_type, const value_type& value); + iterator DoInsertValueExtra(false_type, const key_type& k, hash_code_t c, node_type* pNodeNew, const value_type& value); + iterator DoInsertValue(false_type, const value_type& value); + node_type* DoAllocateNode(const value_type& value); + + eastl::pair DoInsertKey(true_type, const key_type& key); + iterator DoInsertKey(false_type, const key_type& key); + + void DoRehash(size_type nBucketCount); + node_type* DoFindNode(node_type* pNode, const key_type& k, hash_code_t c) const; + node_type* DoFindNode(node_type* pNode, hash_code_t c) const; + + template + node_type* DoFindNodeT(node_type* pNode, const U& u, BinaryPredicate predicate) const; + + }; // class hashtable + + + + + + /////////////////////////////////////////////////////////////////////// + // node_iterator_base + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const node_iterator_base& a, const node_iterator_base& b) + { return a.mpNode == b.mpNode; } + + template + inline bool operator!=(const node_iterator_base& a, const node_iterator_base& b) + { return a.mpNode != b.mpNode; } + + + + + /////////////////////////////////////////////////////////////////////// + // hashtable_iterator_base + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const hashtable_iterator_base& a, const hashtable_iterator_base& b) + { return a.mpNode == b.mpNode; } + + template + inline bool operator!=(const hashtable_iterator_base& a, const hashtable_iterator_base& b) + { return a.mpNode != b.mpNode; } + + + + + /////////////////////////////////////////////////////////////////////// + // hashtable + /////////////////////////////////////////////////////////////////////// + + template + hashtable + ::hashtable(size_type nBucketCount, const H1& h1, const H2& h2, const H& h, + const Eq& eq, const EK& ek, const allocator_type& allocator) + : rehash_base(), + hash_code_base(ek, eq, h1, h2, h), + mnBucketCount(0), + mnElementCount(0), + mRehashPolicy(), + mAllocator(allocator) + { + if(nBucketCount < 2) // If we are starting in an initially empty state, with no memory allocation done. + reset_lose_memory(); + else // Else we are creating a potentially non-empty hashtable... + { + EASTL_ASSERT(nBucketCount < 10000000); + mnBucketCount = (size_type)mRehashPolicy.GetNextBucketCount((uint32_t)nBucketCount); + mpBucketArray = DoAllocateBuckets(mnBucketCount); // mnBucketCount will always be at least 2. + } + } + + + + template + template + hashtable::hashtable(FowardIterator first, FowardIterator last, size_type nBucketCount, + const H1& h1, const H2& h2, const H& h, + const Eq& eq, const EK& ek, const allocator_type& allocator) + : rehash_base(), + hash_code_base(ek, eq, h1, h2, h), + //mnBucketCount(0), // This gets re-assigned below. + mnElementCount(0), + mRehashPolicy(), + mAllocator(allocator) + { + if(nBucketCount < 2) + { + const size_type nElementCount = (size_type)eastl::ht_distance(first, last); + mnBucketCount = (size_type)mRehashPolicy.GetBucketCount((uint32_t)nElementCount); + } + else + { + EASTL_ASSERT(nBucketCount < 10000000); + mnBucketCount = nBucketCount; + } + + mpBucketArray = DoAllocateBuckets(mnBucketCount); // mnBucketCount will always be at least 2. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + for(; first != last; ++first) + insert(*first); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + clear(); + DoFreeBuckets(mpBucketArray, mnBucketCount); + throw; + } + #endif + } + + + + template + hashtable::hashtable(const this_type& x) + : rehash_base(x), + hash_code_base(x), + mnBucketCount(x.mnBucketCount), + mnElementCount(x.mnElementCount), + mRehashPolicy(x.mRehashPolicy), + mAllocator(x.mAllocator) + { + if(mnElementCount) // If there is anything to copy... + { + mpBucketArray = DoAllocateBuckets(mnBucketCount); // mnBucketCount will be at least 2. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + for(size_type i = 0; i < x.mnBucketCount; ++i) + { + node_type* pNodeSource = x.mpBucketArray[i]; + node_type** ppNodeDest = mpBucketArray + i; + + while(pNodeSource) + { + *ppNodeDest = DoAllocateNode(pNodeSource->mValue); + copy_code(*ppNodeDest, pNodeSource); + ppNodeDest = &(*ppNodeDest)->mpNext; + pNodeSource = pNodeSource->mpNext; + } + } + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + clear(); + DoFreeBuckets(mpBucketArray, mnBucketCount); + throw; + } + #endif + } + else + { + // In this case, instead of allocate memory and copy nothing from x, + // we reset ourselves to a zero allocation state. + reset_lose_memory(); + } + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + hashtable::hashtable(this_type&& x) + : rehash_base(x), + hash_code_base(x), + mnBucketCount(0), + mnElementCount(0), + mRehashPolicy(x.mRehashPolicy), + mAllocator(x.mAllocator) + { + reset_lose_memory(); // We do this here the same as we do it in the default ctor because it puts the container in a proper initial empty state. This code would be cleaner if we could rely on being able to use C++11 delegating constructors and just call the default ctor here. + swap(x); + } + + + template + hashtable::hashtable(this_type&& x, const allocator_type& allocator) + : rehash_base(x), + hash_code_base(x), + mnBucketCount(0), + mnElementCount(0), + mRehashPolicy(x.mRehashPolicy), + mAllocator(allocator) + { + reset_lose_memory(); // We do this here the same as we do it in the default ctor because it puts the container in a proper initial empty state. This code would be cleaner if we could rely on being able to use C++11 delegating constructors and just call the default ctor here. + swap(x); // swap will directly or indirectly handle the possibility that mAllocator != x.mAllocator. + } + #endif + + + template + inline const typename hashtable::allocator_type& + hashtable::get_allocator() const EA_NOEXCEPT + { + return mAllocator; + } + + + + template + inline typename hashtable::allocator_type& + hashtable::get_allocator() EA_NOEXCEPT + { + return mAllocator; + } + + + + template + inline void hashtable::set_allocator(const allocator_type& allocator) + { + mAllocator = allocator; + } + + + + template + inline typename hashtable::this_type& + hashtable::operator=(const this_type& x) + { + if(this != &x) + { + clear(); + + #if EASTL_ALLOCATOR_COPY_ENABLED + mAllocator = x.mAllocator; + #endif + + insert(x.begin(), x.end()); + } + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename hashtable::this_type& + hashtable::operator=(this_type&& x) + { + if(this != &x) + { + clear(); // To consider: Are we really required to clear here? x is going away soon and will clear itself in its dtor. + swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. + } + return *this; + } + #endif + + + template + inline typename hashtable::this_type& + hashtable::operator=(std::initializer_list ilist) + { + // The simplest means of doing this is to clear and insert. There probably isn't a generic + // solution that's any more efficient without having prior knowledge of the ilist contents. + clear(); + insert(ilist.begin(), ilist.end()); + return *this; + } + + + + template + inline hashtable::~hashtable() + { + clear(); + DoFreeBuckets(mpBucketArray, mnBucketCount); + } + + + template + typename hashtable::node_type* + hashtable::DoAllocateNodeFromKey(const key_type& key) + { + node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + ::new((void*)&pNode->mValue) value_type(key); + pNode->mpNext = NULL; + return pNode; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + EASTLFree(mAllocator, pNode, sizeof(node_type)); + throw; + } + #endif + } + + + + template + inline void hashtable::DoFreeNode(node_type* pNode) + { + pNode->~node_type(); + EASTLFree(mAllocator, pNode, sizeof(node_type)); + } + + + + template + void hashtable::DoFreeNodes(node_type** pNodeArray, size_type n) + { + for(size_type i = 0; i < n; ++i) + { + node_type* pNode = pNodeArray[i]; + while(pNode) + { + node_type* const pTempNode = pNode; + pNode = pNode->mpNext; + DoFreeNode(pTempNode); + } + pNodeArray[i] = NULL; + } + } + + + + template + typename hashtable::node_type** + hashtable::DoAllocateBuckets(size_type n) + { + // We allocate one extra bucket to hold a sentinel, an arbitrary + // non-null pointer. Iterator increment relies on this. + EASTL_ASSERT(n > 1); // We reserve an mnBucketCount of 1 for the shared gpEmptyBucketArray. + EASTL_CT_ASSERT(kHashtableAllocFlagBuckets == 0x00400000); // Currently we expect this to be so, because the allocator has a copy of this enum. + node_type** const pBucketArray = (node_type**)EASTLAllocAlignedFlags(mAllocator, (n + 1) * sizeof(node_type*), EASTL_ALIGN_OF(node_type*), 0, kHashtableAllocFlagBuckets); + //eastl::fill(pBucketArray, pBucketArray + n, (node_type*)NULL); + memset(pBucketArray, 0, n * sizeof(node_type*)); + pBucketArray[n] = reinterpret_cast((uintptr_t)~0); + return pBucketArray; + } + + + + template + inline void hashtable::DoFreeBuckets(node_type** pBucketArray, size_type n) + { + // If n <= 1, then pBucketArray is from the shared gpEmptyBucketArray. We don't test + // for pBucketArray == &gpEmptyBucketArray because one library have a different gpEmptyBucketArray + // than another but pass a hashtable to another. So we go by the size. + if(n > 1) + EASTLFree(mAllocator, pBucketArray, (n + 1) * sizeof(node_type*)); // '+1' because DoAllocateBuckets allocates nBucketCount + 1 buckets in order to have a NULL sentinel at the end. + } + + + template + void hashtable::swap(this_type& x) + { + if(mAllocator == x.mAllocator) // If allocators are equivalent... + { + // We leave mAllocator as-is. + hash_code_base::base_swap(x); // hash_code_base has multiple implementations, so we let them handle the swap. + eastl::swap(mRehashPolicy, x.mRehashPolicy); + EASTL_MACRO_SWAP(node_type**, mpBucketArray, x.mpBucketArray); // Use EASTL_MACRO_SWAP because GCC (at least v4.6-4.8) has a bug where it fails to compile eastl::swap(mpBucketArray, x.mpBucketArray). + eastl::swap(mnBucketCount, x.mnBucketCount); + eastl::swap(mnElementCount, x.mnElementCount); + } + else + { + const this_type temp(*this); // Can't call eastl::swap because that would + *this = x; // itself call this member swap function. + x = temp; + } + } + + + template + inline void hashtable::rehash_policy(const rehash_policy_type& rehashPolicy) + { + mRehashPolicy = rehashPolicy; + + const size_type nBuckets = rehashPolicy.GetBucketCount((uint32_t)mnElementCount); + + if(nBuckets > mnBucketCount) + DoRehash(nBuckets); + } + + + + template + inline typename hashtable::iterator + hashtable::find(const key_type& k) + { + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + + node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); + return pNode ? iterator(pNode, mpBucketArray + n) : iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + + + + template + inline typename hashtable::const_iterator + hashtable::find(const key_type& k) const + { + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + + node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); + return pNode ? const_iterator(pNode, mpBucketArray + n) : const_iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + + + + template + template + inline typename hashtable::iterator + hashtable::find_as(const U& other, UHash uhash, BinaryPredicate predicate) + { + const hash_code_t c = (hash_code_t)uhash(other); + const size_type n = (size_type)(c % mnBucketCount); // This assumes we are using the mod range policy. + + node_type* const pNode = DoFindNodeT(mpBucketArray[n], other, predicate); + return pNode ? iterator(pNode, mpBucketArray + n) : iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + + + + template + template + inline typename hashtable::const_iterator + hashtable::find_as(const U& other, UHash uhash, BinaryPredicate predicate) const + { + const hash_code_t c = (hash_code_t)uhash(other); + const size_type n = (size_type)(c % mnBucketCount); // This assumes we are using the mod range policy. + + node_type* const pNode = DoFindNodeT(mpBucketArray[n], other, predicate); + return pNode ? const_iterator(pNode, mpBucketArray + n) : const_iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + + + /// hashtable_find + /// + /// Helper function that defaults to using hash and equal_to_2. + /// This makes it so that by default you don't need to provide these. + /// Note that the default hash functions may not be what you want, though. + /// + /// Example usage. Instead of this: + /// hash_set hashSet; + /// hashSet.find("hello", hash(), equal_to_2()); + /// + /// You can use this: + /// hash_set hashSet; + /// hashtable_find(hashSet, "hello"); + /// + template + inline typename H::iterator hashtable_find(H& hashTable, U u) + { return hashTable.find_as(u, eastl::hash(), eastl::equal_to_2()); } + + template + inline typename H::const_iterator hashtable_find(const H& hashTable, U u) + { return hashTable.find_as(u, eastl::hash(), eastl::equal_to_2()); } + + + + template + template + inline typename hashtable::iterator + hashtable::find_as(const U& other) + { return eastl::hashtable_find(*this, other); } + // VC++ doesn't appear to like the following, though it seems correct to me. + // So we implement the workaround above until we can straighten this out. + //{ return find_as(other, eastl::hash(), eastl::equal_to_2()); } + + + template + template + inline typename hashtable::const_iterator + hashtable::find_as(const U& other) const + { return eastl::hashtable_find(*this, other); } + // VC++ doesn't appear to like the following, though it seems correct to me. + // So we implement the workaround above until we can straighten this out. + //{ return find_as(other, eastl::hash(), eastl::equal_to_2()); } + + + template + inline typename hashtable::iterator + hashtable::find_by_hash(hash_code_t c) + { + EASTL_CT_ASSERT_MSG(bC, "find_by_hash(hash_code_t c) is designed to avoid recomputing hashes, " + "so it requires cached hash codes. Consider setting template parameter " + "bCacheHashCode to true or using find_by_hash(const key_type& k, hash_code_t c) instead."); + const size_type n = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + + node_type* const pNode = DoFindNode(mpBucketArray[n], c); + return pNode ? iterator(pNode, mpBucketArray + n) : iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + + + template + inline typename hashtable::const_iterator + hashtable::find_by_hash(hash_code_t c) const + { + EASTL_CT_ASSERT_MSG(bC, "find_by_hash(hash_code_t c) is designed to avoid recomputing hashes, " + "so it requires cached hash codes. Consider setting template parameter " + "bCacheHashCode to true or using find_by_hash(const key_type& k, hash_code_t c) instead."); + const size_type n = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + + node_type* const pNode = DoFindNode(mpBucketArray[n], c); + return pNode ? const_iterator(pNode, mpBucketArray + n) : const_iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + + + template + inline typename hashtable::iterator + hashtable::find_by_hash(const key_type& k, hash_code_t c) + { + const size_type n = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + + node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); + return pNode ? iterator(pNode, mpBucketArray + n) : iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + + + template + inline typename hashtable::const_iterator + hashtable::find_by_hash(const key_type& k, hash_code_t c) const + { + const size_type n = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + + node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); + return pNode ? const_iterator(pNode, mpBucketArray + n) : const_iterator(mpBucketArray + mnBucketCount); // iterator(mpBucketArray + mnBucketCount) == end() + } + + + template + eastl::pair::const_iterator, + typename hashtable::const_iterator> + hashtable::find_range_by_hash(hash_code_t c) const + { + const size_type start = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + node_type* const pNodeStart = mpBucketArray[start]; + + if (pNodeStart) + { + eastl::pair pair(const_iterator(pNodeStart, mpBucketArray + start), + const_iterator(pNodeStart, mpBucketArray + start)); + pair.second.increment_bucket(); + return pair; + } + + return eastl::pair(const_iterator(mpBucketArray + mnBucketCount), + const_iterator(mpBucketArray + mnBucketCount)); + } + + + + template + eastl::pair::iterator, + typename hashtable::iterator> + hashtable::find_range_by_hash(hash_code_t c) + { + const size_type start = (size_type)bucket_index(c, (uint32_t)mnBucketCount); + node_type* const pNodeStart = mpBucketArray[start]; + + if (pNodeStart) + { + eastl::pair pair(iterator(pNodeStart, mpBucketArray + start), + iterator(pNodeStart, mpBucketArray + start)); + pair.second.increment_bucket(); + return pair; + + } + + return eastl::pair(iterator(mpBucketArray + mnBucketCount), + iterator(mpBucketArray + mnBucketCount)); + } + + + + template + typename hashtable::size_type + hashtable::count(const key_type& k) const EA_NOEXCEPT + { + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + size_type result = 0; + + // To do: Make a specialization for bU (unique keys) == true and take + // advantage of the fact that the count will always be zero or one in that case. + for(node_type* pNode = mpBucketArray[n]; pNode; pNode = pNode->mpNext) + { + if(compare(k, c, pNode)) + ++result; + } + return result; + } + + + + template + eastl::pair::iterator, + typename hashtable::iterator> + hashtable::equal_range(const key_type& k) + { + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + node_type** head = mpBucketArray + n; + node_type* pNode = DoFindNode(*head, k, c); + + if(pNode) + { + node_type* p1 = pNode->mpNext; + + for(; p1; p1 = p1->mpNext) + { + if(!compare(k, c, p1)) + break; + } + + iterator first(pNode, head); + iterator last(p1, head); + + if(!p1) + last.increment_bucket(); + + return eastl::pair(first, last); + } + + return eastl::pair(iterator(mpBucketArray + mnBucketCount), // iterator(mpBucketArray + mnBucketCount) == end() + iterator(mpBucketArray + mnBucketCount)); + } + + + + + template + eastl::pair::const_iterator, + typename hashtable::const_iterator> + hashtable::equal_range(const key_type& k) const + { + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + node_type** head = mpBucketArray + n; + node_type* pNode = DoFindNode(*head, k, c); + + if(pNode) + { + node_type* p1 = pNode->mpNext; + + for(; p1; p1 = p1->mpNext) + { + if(!compare(k, c, p1)) + break; + } + + const_iterator first(pNode, head); + const_iterator last(p1, head); + + if(!p1) + last.increment_bucket(); + + return eastl::pair(first, last); + } + + return eastl::pair(const_iterator(mpBucketArray + mnBucketCount), // iterator(mpBucketArray + mnBucketCount) == end() + const_iterator(mpBucketArray + mnBucketCount)); + } + + + + template + inline typename hashtable::node_type* + hashtable::DoFindNode(node_type* pNode, const key_type& k, hash_code_t c) const + { + for(; pNode; pNode = pNode->mpNext) + { + if(compare(k, c, pNode)) + return pNode; + } + return NULL; + } + + + + template + template + inline typename hashtable::node_type* + hashtable::DoFindNodeT(node_type* pNode, const U& other, BinaryPredicate predicate) const + { + for(; pNode; pNode = pNode->mpNext) + { + if(predicate(mExtractKey(pNode->mValue), other)) // Intentionally compare with key as first arg and other as second arg. + return pNode; + } + return NULL; + } + + + + template + inline typename hashtable::node_type* + hashtable::DoFindNode(node_type* pNode, hash_code_t c) const + { + for(; pNode; pNode = pNode->mpNext) + { + if(pNode->mnHashCode == c) + return pNode; + } + return NULL; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + template + eastl::pair::iterator, bool> + hashtable::DoInsertValue(true_type, Args&&... args) // true_type means bUniqueKeys is true. + { + // Adds the value to the hash table if not already present. + // If already present then the existing value is returned via an iterator/bool pair. + + // We have a chicken-and-egg problem here. In order to know if and where to insert the value, we need to get the + // hashtable key for the value. But we don't explicitly have a value argument, we have a templated Args&&... argument. + // We need the value_type in order to proceed, but that entails getting an instance of a value_type from the args. + // And it may turn out that the value is already present in the hashtable and we need to cancel the insertion, + // despite having obtained a value_type to put into the hashtable. We have mitigated this problem somewhat by providing + // specializations of the insert function for const value_type& and value_type&&, and so the only time this function + // should get called is when args refers to arguments to construct a value_type. + + node_type* const pNodeNew = DoAllocateNode(eastl::forward(args)...); + const key_type& k = mExtractKey(pNodeNew->mValue); + const hash_code_t c = get_hash_code(k); + size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); + + if(pNode == NULL) // If value is not present... add it. + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); + + set_code(pNodeNew, c); // This is a no-op for most hashtables. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + if(bRehash.first) + { + n = (size_type)bucket_index(k, c, (uint32_t)bRehash.second); + DoRehash(bRehash.second); + } + + EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + ++mnElementCount; + + return eastl::pair(iterator(pNodeNew, mpBucketArray + n), true); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeNode(pNodeNew); + throw; + } + #endif + } + else + { + // To do: We have an inefficiency to deal with here. We allocated a node above but we are freeing it here because + // it turned out it wasn't needed. But we needed to create the node in order to get the hashtable key for + // the node. One possible resolution is to create specializations: DoInsertValue(true_type, value_type&&) and + // DoInsertValue(true_type, const value_type&) which don't need to create a node up front in order to get the + // hashtable key. Probably most users would end up using these pathways instead of this Args... pathway. + // While we should considering handling this to-do item, a lot of the performance limitations of maps and sets + // in practice is with finding elements rather than adding (potentially redundant) new elements. + DoFreeNode(pNodeNew); + } + + return eastl::pair(iterator(pNode, mpBucketArray + n), false); + } + + + template + template + typename hashtable::iterator + hashtable::DoInsertValue(false_type, Args&&... args) // false_type means bUniqueKeys is false. + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); + + if(bRehash.first) + DoRehash(bRehash.second); + + node_type* pNodeNew = DoAllocateNode(eastl::forward(args)...); + const key_type& k = mExtractKey(pNodeNew->mValue); + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + + set_code(pNodeNew, c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. + // The benefit is that equal_range can work in a sensible manner and that + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? + node_type* const pNodePrev = DoFindNode(mpBucketArray[n], k, c); + + if(pNodePrev == NULL) + { + EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } + else + { + pNodeNew->mpNext = pNodePrev->mpNext; + pNodePrev->mpNext = pNodeNew; + } + + ++mnElementCount; + + return iterator(pNodeNew, mpBucketArray + n); + } + + + template + template + typename hashtable::node_type* + hashtable::DoAllocateNode(Args&&... args) + { + node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + ::new((void*)&pNode->mValue) value_type(eastl::forward(args)...); + pNode->mpNext = NULL; + return pNode; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + EASTLFree(mAllocator, pNode, sizeof(node_type)); + throw; + } + #endif + } + + #endif // EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Note: The following insertion-related functions are nearly copies of the above three functions, + // but are for value_type&& and const value_type& arguments. It's useful for us to have the functions + // below, even when using a fully compliant C++11 compiler that supports the above functions. + // The reason is because the specializations below are slightly more efficient because they can delay + // the creation of a node until it's known that it will be needed. + //////////////////////////////////////////////////////////////////////////////////////////////////// + + #if EASTL_MOVE_SEMANTICS_ENABLED + + template + eastl::pair::iterator, bool> + hashtable::DoInsertValueExtra(true_type, const key_type& k, hash_code_t c, node_type* pNodeNew, value_type&& value) // true_type means bUniqueKeys is true. + { + // Adds the value to the hash table if not already present. + // If already present then the existing value is returned via an iterator/bool pair. + size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); + + if(pNode == NULL) // If value is not present... add it. + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); + + // Allocate the new node before doing the rehash so that we don't + // do a rehash if the allocation throws. + #if EASTL_EXCEPTIONS_ENABLED + bool nodeAllocated; // If exceptions are enabled then we we need to track if we allocated the node so we can free it in the catch block. + #endif + + if(pNodeNew) + { + ::new((void*)&pNodeNew->mValue) value_type(eastl::move(value)); // It's expected that pNodeNew was allocated with allocate_uninitialized_node. + #if EASTL_EXCEPTIONS_ENABLED + nodeAllocated = false; + #endif + } + else + { + pNodeNew = DoAllocateNode(eastl::move(value)); + #if EASTL_EXCEPTIONS_ENABLED + nodeAllocated = true; + #endif + } + + set_code(pNodeNew, c); // This is a no-op for most hashtables. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + if(bRehash.first) + { + n = (size_type)bucket_index(k, c, (uint32_t)bRehash.second); + DoRehash(bRehash.second); + } + + EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + ++mnElementCount; + + return eastl::pair(iterator(pNodeNew, mpBucketArray + n), true); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + if(nodeAllocated) // If we allocated the node within this function, free it. Else let the caller retain ownership of it. + DoFreeNode(pNodeNew); + throw; + } + #endif + } + // Else the value is already present, so don't add a new node. And don't free pNodeNew. + + return eastl::pair(iterator(pNode, mpBucketArray + n), false); + } + + + template + eastl::pair::iterator, bool> + hashtable::DoInsertValue(true_type, value_type&& value) // true_type means bUniqueKeys is true. + { + const key_type& k = mExtractKey(value); + const hash_code_t c = get_hash_code(k); + + return DoInsertValueExtra(true_type(), k, c, NULL, eastl::move(value)); + } + + + + template + typename hashtable::iterator + hashtable::DoInsertValueExtra(false_type, const key_type& k, hash_code_t c, node_type* pNodeNew, value_type&& value) // false_type means bUniqueKeys is false. + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); + + if(bRehash.first) + DoRehash(bRehash.second); // Note: We don't need to wrap this call with try/catch because there's nothing we would need to do in the catch. + + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + + if(pNodeNew) + ::new((void*)&pNodeNew->mValue) value_type(eastl::move(value)); // It's expected that pNodeNew was allocated with allocate_uninitialized_node. + else + pNodeNew = DoAllocateNode(eastl::move(value)); + + set_code(pNodeNew, c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. + // The benefit is that equal_range can work in a sensible manner and that + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? + node_type* const pNodePrev = DoFindNode(mpBucketArray[n], k, c); + + if(pNodePrev == NULL) + { + EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } + else + { + pNodeNew->mpNext = pNodePrev->mpNext; + pNodePrev->mpNext = pNodeNew; + } + + ++mnElementCount; + + return iterator(pNodeNew, mpBucketArray + n); + } + + + template + typename hashtable::iterator + hashtable::DoInsertValue(false_type, value_type&& value) // false_type means bUniqueKeys is false. + { + const key_type& k = mExtractKey(value); + const hash_code_t c = get_hash_code(k); + + return DoInsertValueExtra(false_type(), k, c, NULL, eastl::move(value)); + } + + + template + typename hashtable::node_type* + hashtable::DoAllocateNode(value_type&& value) + { + node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + ::new((void*)&pNode->mValue) value_type(eastl::move(value)); + pNode->mpNext = NULL; + return pNode; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + EASTLFree(mAllocator, pNode, sizeof(node_type)); + throw; + } + #endif + } + #endif + + + template + eastl::pair::iterator, bool> + hashtable::DoInsertValueExtra(true_type, const key_type& k, hash_code_t c, node_type* pNodeNew, const value_type& value) // true_type means bUniqueKeys is true. + { + // Adds the value to the hash table if not already present. + // If already present then the existing value is returned via an iterator/bool pair. + size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + node_type* const pNode = DoFindNode(mpBucketArray[n], k, c); + + if(pNode == NULL) // If value is not present... add it. + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); + + // Allocate the new node before doing the rehash so that we don't + // do a rehash if the allocation throws. + #if EASTL_EXCEPTIONS_ENABLED + bool nodeAllocated; // If exceptions are enabled then we we need to track if we allocated the node so we can free it in the catch block. + #endif + + if(pNodeNew) + { + ::new((void*)&pNodeNew->mValue) value_type(value); // It's expected that pNodeNew was allocated with allocate_uninitialized_node. + #if EASTL_EXCEPTIONS_ENABLED + nodeAllocated = false; + #endif + } + else + { + pNodeNew = DoAllocateNode(value); + #if EASTL_EXCEPTIONS_ENABLED + nodeAllocated = true; + #endif + } + + set_code(pNodeNew, c); // This is a no-op for most hashtables. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + if(bRehash.first) + { + n = (size_type)bucket_index(k, c, (uint32_t)bRehash.second); + DoRehash(bRehash.second); + } + + EASTL_ASSERT((uintptr_t)mpBucketArray != (uintptr_t)&gpEmptyBucketArray[0]); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + ++mnElementCount; + + return eastl::pair(iterator(pNodeNew, mpBucketArray + n), true); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + if(nodeAllocated) // If we allocated the node within this function, free it. Else let the caller retain ownership of it. + DoFreeNode(pNodeNew); + throw; + } + #endif + } + // Else the value is already present, so don't add a new node. And don't free pNodeNew. + + return eastl::pair(iterator(pNode, mpBucketArray + n), false); + } + + + template + eastl::pair::iterator, bool> + hashtable::DoInsertValue(true_type, const value_type& value) // true_type means bUniqueKeys is true. + { + const key_type& k = mExtractKey(value); + const hash_code_t c = get_hash_code(k); + + return DoInsertValueExtra(true_type(), k, c, NULL, value); + } + + + template + typename hashtable::iterator + hashtable::DoInsertValueExtra(false_type, const key_type& k, hash_code_t c, node_type* pNodeNew, const value_type& value) // false_type means bUniqueKeys is false. + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); + + if(bRehash.first) + DoRehash(bRehash.second); // Note: We don't need to wrap this call with try/catch because there's nothing we would need to do in the catch. + + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + + if(pNodeNew) + ::new((void*)&pNodeNew->mValue) value_type(value); // It's expected that pNodeNew was allocated with allocate_uninitialized_node. + else + pNodeNew = DoAllocateNode(value); + + set_code(pNodeNew, c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. + // The benefit is that equal_range can work in a sensible manner and that + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? + node_type* const pNodePrev = DoFindNode(mpBucketArray[n], k, c); + + if(pNodePrev == NULL) + { + EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } + else + { + pNodeNew->mpNext = pNodePrev->mpNext; + pNodePrev->mpNext = pNodeNew; + } + + ++mnElementCount; + + return iterator(pNodeNew, mpBucketArray + n); + } + + + template + typename hashtable::iterator + hashtable::DoInsertValue(false_type, const value_type& value) // true_type means bUniqueKeys is true. + { + const key_type& k = mExtractKey(value); + const hash_code_t c = get_hash_code(k); + + return DoInsertValueExtra(false_type(), k, c, NULL, value); + } + + + template + typename hashtable::node_type* + hashtable::DoAllocateNode(const value_type& value) + { + node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + ::new((void*)&pNode->mValue) value_type(value); + pNode->mpNext = NULL; + return pNode; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + EASTLFree(mAllocator, pNode, sizeof(node_type)); + throw; + } + #endif + } + + + template + typename hashtable::node_type* + hashtable::allocate_uninitialized_node() + { + // We don't wrap this in try/catch because users of this function are expected to do that themselves as needed. + node_type* const pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + // Leave pNode->mValue uninitialized. + pNode->mpNext = NULL; + return pNode; + } + + + template + void hashtable::free_uninitialized_node(node_type* pNode) + { + // pNode->mValue is expected to be uninitialized. + EASTLFree(mAllocator, pNode, sizeof(node_type)); + } + + + template + eastl::pair::iterator, bool> + hashtable::DoInsertKey(true_type, const key_type& key) // true_type means bUniqueKeys is true. + { + const hash_code_t c = get_hash_code(key); + size_type n = (size_type)bucket_index(key, c, (uint32_t)mnBucketCount); + node_type* const pNode = DoFindNode(mpBucketArray[n], key, c); + + if(pNode == NULL) + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); + + // Allocate the new node before doing the rehash so that we don't + // do a rehash if the allocation throws. + node_type* const pNodeNew = DoAllocateNodeFromKey(key); + set_code(pNodeNew, c); // This is a no-op for most hashtables. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + if(bRehash.first) + { + n = (size_type)bucket_index(key, c, (uint32_t)bRehash.second); + DoRehash(bRehash.second); + } + + EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + ++mnElementCount; + + return eastl::pair(iterator(pNodeNew, mpBucketArray + n), true); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeNode(pNodeNew); + throw; + } + #endif + } + + return eastl::pair(iterator(pNode, mpBucketArray + n), false); + } + + + + template + typename hashtable::iterator + hashtable::DoInsertKey(false_type, const key_type& key) // false_type means bUniqueKeys is false. + { + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); + + if(bRehash.first) + DoRehash(bRehash.second); + + const hash_code_t c = get_hash_code(key); + const size_type n = (size_type)bucket_index(key, c, (uint32_t)mnBucketCount); + + node_type* const pNodeNew = DoAllocateNodeFromKey(key); + set_code(pNodeNew, c); // This is a no-op for most hashtables. + + // To consider: Possibly make this insertion not make equal elements contiguous. + // As it stands now, we insert equal values contiguously in the hashtable. + // The benefit is that equal_range can work in a sensible manner and that + // erase(value) can more quickly find equal values. The downside is that + // this insertion operation taking some extra time. How important is it to + // us that equal_range span all equal items? + node_type* const pNodePrev = DoFindNode(mpBucketArray[n], key, c); + + if(pNodePrev == NULL) + { + EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); + pNodeNew->mpNext = mpBucketArray[n]; + mpBucketArray[n] = pNodeNew; + } + else + { + pNodeNew->mpNext = pNodePrev->mpNext; + pNodePrev->mpNext = pNodeNew; + } + + ++mnElementCount; + + return iterator(pNodeNew, mpBucketArray + n); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + template + typename hashtable::insert_return_type + hashtable::emplace(Args&&... args) + { + return DoInsertValue(has_unique_keys_type(), eastl::forward(args)...); // Need to use forward instead of move because Args&& is a "universal reference" instead of an rvalue reference. + } + + template + template + typename hashtable::iterator + hashtable::emplace_hint(const_iterator, Args&&... args) + { + // We currently ignore the iterator argument as a hint. + insert_return_type result = DoInsertValue(has_unique_keys_type(), eastl::forward(args)...); + return DoGetResultIterator(has_unique_keys_type(), result); + } + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + template + typename hashtable::insert_return_type + hashtable::emplace(value_type&& value) + { + return DoInsertValue(has_unique_keys_type(), eastl::move(value)); + } + + template + typename hashtable::iterator + hashtable::emplace_hint(const_iterator position, value_type&& value) + { + // We currently ignore the iterator argument as a hint. + insert_return_type result = DoInsertValue(has_unique_keys_type(), eastl::move(value)); + return DoGetResultIterator(has_unique_keys_type(), result); + } + #endif + + template + typename hashtable::insert_return_type + hashtable::emplace(const value_type& value) + { + return DoInsertValue(has_unique_keys_type(), value); + } + + template + typename hashtable::iterator + hashtable::emplace_hint(const_iterator position, const value_type& value) + { + // We currently ignore the iterator argument as a hint. + insert_return_type result = DoInsertValue(has_unique_keys_type(), value); + return DoGetResultIterator(has_unique_keys_type(), result); + } + #endif + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + typename hashtable::insert_return_type + hashtable::insert(value_type&& otherValue) + { + return DoInsertValue(has_unique_keys_type(), eastl::move(otherValue)); + } + + + template + template + typename hashtable::insert_return_type + hashtable::insert(hash_code_t c, node_type* pNodeNew, P&& otherValue) + { + // pNodeNew->mValue is expected to be uninitialized. + value_type value(eastl::forward

(otherValue)); // Need to use forward instead of move because P&& is a "universal reference" instead of an rvalue reference. + const key_type& k = mExtractKey(value); + return DoInsertValueExtra(has_unique_keys_type(), k, c, pNodeNew, eastl::move(value)); + } + + + template + typename hashtable::iterator + hashtable::insert(const_iterator, value_type&& value) + { + // We currently ignore the iterator argument as a hint. + insert_return_type result = DoInsertValue(has_unique_keys_type(), value_type(eastl::move(value))); + return DoGetResultIterator(has_unique_keys_type(), result); + } + #endif + + + template + typename hashtable::insert_return_type + hashtable::insert(const value_type& value) + { + return DoInsertValue(has_unique_keys_type(), value); + } + + + template + typename hashtable::insert_return_type + hashtable::insert(hash_code_t c, node_type* pNodeNew, const value_type& value) + { + // pNodeNew->mValue is expected to be uninitialized. + const key_type& k = mExtractKey(value); + return DoInsertValueExtra(has_unique_keys_type(), k, c, pNodeNew, value); + } + + + template + typename hashtable::iterator + hashtable::insert(const_iterator, const value_type& value) + { + // We ignore the first argument (hint iterator). It's not likely to be useful for hashtable containers. + insert_return_type result = DoInsertValue(has_unique_keys_type(), value); + return result.first; // Note by Paul Pedriana while perusing this code: This code will fail to compile when bU is false (i.e. for multiset, multimap). + } + + + + template + void hashtable::insert(std::initializer_list ilist) + { + insert(ilist.begin(), ilist.end()); + } + + + template + template + void + hashtable::insert(InputIterator first, InputIterator last) + { + const uint32_t nElementAdd = (uint32_t)eastl::ht_distance(first, last); + const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, nElementAdd); + + if(bRehash.first) + DoRehash(bRehash.second); + + for(; first != last; ++first) + DoInsertValue(has_unique_keys_type(), *first); + } + + + + template + typename hashtable::iterator + hashtable::erase(const_iterator i) + { + iterator iNext(i.mpNode, i.mpBucket); // Convert from const_iterator to iterator while constructing. + ++iNext; + + node_type* pNode = i.mpNode; + node_type* pNodeCurrent = *i.mpBucket; + + if(pNodeCurrent == pNode) + *i.mpBucket = pNodeCurrent->mpNext; + else + { + // We have a singly-linked list, so we have no choice but to + // walk down it till we find the node before the node at 'i'. + node_type* pNodeNext = pNodeCurrent->mpNext; + + while(pNodeNext != pNode) + { + pNodeCurrent = pNodeNext; + pNodeNext = pNodeCurrent->mpNext; + } + + pNodeCurrent->mpNext = pNodeNext->mpNext; + } + + DoFreeNode(pNode); + --mnElementCount; + + return iNext; + } + + + + template + inline typename hashtable::iterator + hashtable::erase(const_iterator first, const_iterator last) + { + while(first != last) + first = erase(first); + return iterator(first.mpNode, first.mpBucket); + } + + + + template + typename hashtable::size_type + hashtable::erase(const key_type& k) + { + // To do: Reimplement this function to do a single loop and not try to be + // smart about element contiguity. The mechanism here is only a benefit if the + // buckets are heavily overloaded; otherwise this mechanism may be slightly slower. + + const hash_code_t c = get_hash_code(k); + const size_type n = (size_type)bucket_index(k, c, (uint32_t)mnBucketCount); + const size_type nElementCountSaved = mnElementCount; + + node_type** pBucketArray = mpBucketArray + n; + + while(*pBucketArray && !compare(k, c, *pBucketArray)) + pBucketArray = &(*pBucketArray)->mpNext; + + while(*pBucketArray && compare(k, c, *pBucketArray)) + { + node_type* const pNode = *pBucketArray; + *pBucketArray = pNode->mpNext; + DoFreeNode(pNode); + --mnElementCount; + } + + return nElementCountSaved - mnElementCount; + } + + + + template + inline void hashtable::clear() + { + DoFreeNodes(mpBucketArray, mnBucketCount); + mnElementCount = 0; + } + + + + template + inline void hashtable::clear(bool clearBuckets) + { + DoFreeNodes(mpBucketArray, mnBucketCount); + if(clearBuckets) + { + DoFreeBuckets(mpBucketArray, mnBucketCount); + reset_lose_memory(); + } + mnElementCount = 0; + } + + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void hashtable::reset() EA_NOEXCEPT + { + reset_lose_memory(); + } + #endif + + + + template + inline void hashtable::reset_lose_memory() EA_NOEXCEPT + { + // The reset function is a special extension function which unilaterally + // resets the container to an empty state without freeing the memory of + // the contained objects. This is useful for very quickly tearing down a + // container built into scratch memory. + mnBucketCount = 1; + + #ifdef _MSC_VER + mpBucketArray = (node_type**)&gpEmptyBucketArray[0]; + #else + void* p = &gpEmptyBucketArray[0]; + memcpy(&mpBucketArray, &p, sizeof(mpBucketArray)); // Other compilers implement strict aliasing and casting is thus unsafe. + #endif + + mnElementCount = 0; + mRehashPolicy.mnNextResize = 0; + } + + + + template + inline void hashtable::rehash(size_type nBucketCount) + { + // Note that we unilaterally use the passed in bucket count; we do not attempt migrate it + // up to the next prime number. We leave it at the user's discretion to do such a thing. + DoRehash(nBucketCount); + } + + + + template + void hashtable::DoRehash(size_type nNewBucketCount) + { + node_type** const pBucketArray = DoAllocateBuckets(nNewBucketCount); // nNewBucketCount should always be >= 2. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + node_type* pNode; + + for(size_type i = 0; i < mnBucketCount; ++i) + { + while((pNode = mpBucketArray[i]) != NULL) // Using '!=' disables compiler warnings. + { + const size_type nNewBucketIndex = (size_type)bucket_index(pNode, (uint32_t)nNewBucketCount); + + mpBucketArray[i] = pNode->mpNext; + pNode->mpNext = pBucketArray[nNewBucketIndex]; + pBucketArray[nNewBucketIndex] = pNode; + } + } + + DoFreeBuckets(mpBucketArray, mnBucketCount); + mnBucketCount = nNewBucketCount; + mpBucketArray = pBucketArray; + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + // A failure here means that a hash function threw an exception. + // We can't restore the previous state without calling the hash + // function again, so the only sensible recovery is to delete everything. + DoFreeNodes(pBucketArray, nNewBucketCount); + DoFreeBuckets(pBucketArray, nNewBucketCount); + DoFreeNodes(mpBucketArray, mnBucketCount); + mnElementCount = 0; + throw; + } + #endif + } + + + template + inline bool hashtable::validate() const + { + // Verify our empty bucket array is unmodified. + if(gpEmptyBucketArray[0] != NULL) + return false; + + if(gpEmptyBucketArray[1] != (void*)uintptr_t(~0)) + return false; + + // Verify that we have at least one bucket. Calculations can + // trigger division by zero exceptions otherwise. + if(mnBucketCount == 0) + return false; + + // Verify that gpEmptyBucketArray is used correctly. + // gpEmptyBucketArray is only used when initially empty. + if((void**)mpBucketArray == &gpEmptyBucketArray[0]) + { + if(mnElementCount) // gpEmptyBucketArray is used only for empty hash tables. + return false; + + if(mnBucketCount != 1) // gpEmptyBucketArray is used exactly an only for mnBucketCount == 1. + return false; + } + else + { + if(mnBucketCount < 2) // Small bucket counts *must* use gpEmptyBucketArray. + return false; + } + + // Verify that the element count matches mnElementCount. + size_type nElementCount = 0; + + for(const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp) + ++nElementCount; + + if(nElementCount != mnElementCount) + return false; + + // To do: Verify that individual elements are in the expected buckets. + + return true; + } + + + template + int hashtable::validate_iterator(const_iterator i) const + { + // To do: Come up with a more efficient mechanism of doing this. + + for(const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp) + { + if(temp == i) + return (isf_valid | isf_current | isf_can_dereference); + } + + if(i == end()) + return (isf_valid | isf_current); + + return isf_none; + } + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + // operator==, != have been moved to the specific container subclasses (e.g. hash_map). + + // The following comparison operators are deprecated and will likely be removed in a + // future version of this package. + // + // Comparing hash tables for less-ness is an odd thing to do. We provide it for + // completeness, though the user is advised to be wary of how they use this. + // + template + inline bool operator<(const hashtable& a, + const hashtable& b) + { + // This requires hash table elements to support operator<. Since the hash table + // doesn't compare elements via less (it does so via equals), we must use the + // globally defined operator less for the elements. + return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); + } + + + template + inline bool operator>(const hashtable& a, + const hashtable& b) + { + return b < a; + } + + + template + inline bool operator<=(const hashtable& a, + const hashtable& b) + { + return !(b < a); + } + + + template + inline bool operator>=(const hashtable& a, + const hashtable& b) + { + return !(a < b); + } + + + template + inline void swap(const hashtable& a, + const hashtable& b) + { + a.swap(b); + } + + +} // namespace eastl + + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + + + +#endif // Header include guard + + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/integer_sequence.h b/libs/eastl/include/EASTL/internal/integer_sequence.h new file mode 100644 index 0000000..fbc9f8b --- /dev/null +++ b/libs/eastl/include/EASTL/internal/integer_sequence.h @@ -0,0 +1,70 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_INTEGER_SEQUENCE_H +#define EASTL_INTEGER_SEQUENCE_H + +#include +#include +#include + +namespace eastl +{ + +#if EASTL_VARIADIC_TEMPLATES_ENABLED && !defined(EA_COMPILER_NO_TEMPLATE_ALIASES) + +// integer_sequence +template +class integer_sequence +{ +public: + typedef T value_type; + static_assert(is_integral::value, "eastl::integer_sequence can only be instantiated with an integral type"); + static EA_CONSTEXPR size_t size() EA_NOEXCEPT { return sizeof...(Ints); } +}; + +template +struct make_index_sequence_impl; + +template +struct make_index_sequence_impl> +{ + typedef typename make_index_sequence_impl>::type type; +}; + +template +struct make_index_sequence_impl<0, integer_sequence> +{ + typedef integer_sequence type; +}; + +template +using index_sequence = integer_sequence; + +template +using make_index_sequence = typename make_index_sequence_impl>::type; + +template +struct integer_sequence_convert_impl; + +template +struct integer_sequence_convert_impl> +{ + typedef integer_sequence type; +}; + +template +struct make_integer_sequence_impl +{ + typedef typename integer_sequence_convert_impl>::type type; +}; + +template +using make_integer_sequence = typename make_integer_sequence_impl::type; + +#endif // EASTL_VARIADIC_TEMPLATES_ENABLED + +} // namespace eastl + +#endif // EASTL_INTEGER_SEQUENCE_H diff --git a/libs/eastl/include/EASTL/internal/intrusive_hashtable.h b/libs/eastl/include/EASTL/internal/intrusive_hashtable.h new file mode 100644 index 0000000..fd00e47 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/intrusive_hashtable.h @@ -0,0 +1,1005 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements an intrusive hash table, which is a hash table whereby +// the container nodes are the hash table objects themselves. This has benefits +// primarily in terms of memory management. There are some minor limitations +// that result from this. +// +/////////////////////////////////////////////////////////////////////////////// + + + +#ifndef EASTL_INTERNAL_INTRUSIVE_HASHTABLE_H +#define EASTL_INTERNAL_INTRUSIVE_HASHTABLE_H + + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + #pragma warning(push, 0) + #include + #include + #include + #pragma warning(pop) +#else + #include + #include + #include +#endif + + + +namespace eastl +{ + + /// intrusive_hash_node + /// + /// A hash_node stores an element in a hash table, much like a + /// linked list node stores an element in a linked list. + /// An intrusive_hash_node additionally can, via template parameter, + /// store a hash code in the node to speed up hash calculations + /// and comparisons in some cases. + /// + /// To consider: Make a version of intrusive_hash_node which is + /// templated on the container type. This would allow for the + /// mpNext pointer to be the container itself and thus allow + /// for easier debugging. + /// + /// Example usage: + /// struct Widget : public intrusive_hash_node{ ... }; + /// + /// struct Dagget : public intrusive_hash_node_key{ ... }; + /// + struct intrusive_hash_node + { + intrusive_hash_node* mpNext; + }; + + + template + struct intrusive_hash_node_key : public intrusive_hash_node + { + typedef Key key_type; + Key mKey; + }; + + + + /// intrusive_node_iterator + /// + /// Node iterators iterate nodes within a given bucket. + /// + /// The bConst parameter defines if the iterator is a const_iterator + /// or an iterator. + /// + template + struct intrusive_node_iterator + { + public: + typedef intrusive_node_iterator this_type; + typedef Value value_type; + typedef Value node_type; + typedef ptrdiff_t difference_type; + typedef typename type_select::type pointer; + typedef typename type_select::type reference; + typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; + + public: + node_type* mpNode; + + public: + intrusive_node_iterator() + : mpNode(NULL) { } + + explicit intrusive_node_iterator(value_type* pNode) + : mpNode(pNode) { } + + intrusive_node_iterator(const intrusive_node_iterator& x) + : mpNode(x.mpNode) { } + + reference operator*() const + { return *mpNode; } + + pointer operator->() const + { return mpNode; } + + this_type& operator++() + { mpNode = static_cast(mpNode->mpNext); return *this; } + + this_type operator++(int) + { this_type temp(*this); mpNode = static_cast(mpNode->mpNext); return temp; } + + }; // intrusive_node_iterator + + + + + /// intrusive_hashtable_iterator_base + /// + /// An intrusive_hashtable_iterator_base iterates the entire hash table and + /// not just nodes within a single bucket. Users in general will use a hash + /// table iterator much more often, as it is much like other container + /// iterators (e.g. vector::iterator). + /// + /// We define a base class here because it is shared by both const and + /// non-const iterators. + /// + template + struct intrusive_hashtable_iterator_base + { + public: + typedef Value value_type; + + protected: + template + friend class intrusive_hashtable; + + template + friend struct intrusive_hashtable_iterator; + + template + friend bool operator==(const intrusive_hashtable_iterator_base&, const intrusive_hashtable_iterator_base&); + + template + friend bool operator!=(const intrusive_hashtable_iterator_base&, const intrusive_hashtable_iterator_base&); + + value_type* mpNode; // Current node within current bucket. + value_type** mpBucket; // Current bucket. + + public: + intrusive_hashtable_iterator_base(value_type* pNode, value_type** pBucket) + : mpNode(pNode), mpBucket(pBucket) { } + + void increment_bucket() + { + ++mpBucket; + while(*mpBucket == NULL) // We store an extra bucket with some non-NULL value at the end + ++mpBucket; // of the bucket array so that finding the end of the bucket + mpNode = *mpBucket; // array is quick and simple. + } + + void increment() + { + mpNode = static_cast(mpNode->mpNext); + + while(mpNode == NULL) + mpNode = *++mpBucket; + } + + }; // intrusive_hashtable_iterator_base + + + + + /// intrusive_hashtable_iterator + /// + /// An intrusive_hashtable_iterator iterates the entire hash table and not + /// just nodes within a single bucket. Users in general will use a hash + /// table iterator much more often, as it is much like other container + /// iterators (e.g. vector::iterator). + /// + /// The bConst parameter defines if the iterator is a const_iterator + /// or an iterator. + /// + template + struct intrusive_hashtable_iterator : public intrusive_hashtable_iterator_base + { + public: + typedef intrusive_hashtable_iterator_base base_type; + typedef intrusive_hashtable_iterator this_type; + typedef intrusive_hashtable_iterator this_type_non_const; + typedef typename base_type::value_type value_type; + typedef typename type_select::type pointer; + typedef typename type_select::type reference; + typedef ptrdiff_t difference_type; + typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; + + public: + intrusive_hashtable_iterator() + : base_type(NULL, NULL) { } + + explicit intrusive_hashtable_iterator(value_type* pNode, value_type** pBucket) + : base_type(pNode, pBucket) { } + + explicit intrusive_hashtable_iterator(value_type** pBucket) + : base_type(*pBucket, pBucket) { } + + intrusive_hashtable_iterator(const this_type_non_const& x) + : base_type(x.mpNode, x.mpBucket) { } + + reference operator*() const + { return *base_type::mpNode; } + + pointer operator->() const + { return base_type::mpNode; } + + this_type& operator++() + { base_type::increment(); return *this; } + + this_type operator++(int) + { this_type temp(*this); base_type::increment(); return temp; } + + }; // intrusive_hashtable_iterator + + + + /// use_intrusive_key + /// + /// operator()(x) returns x.mKey. Used in maps, as opposed to sets. + /// This is a template policy implementation; it is an alternative to + /// the use_self template implementation, which is used for sets. + /// + template + struct use_intrusive_key // : public unary_function // Perhaps we want to make it a subclass of unary_function. + { + typedef Key result_type; + + const result_type& operator()(const Node& x) const + { return x.mKey; } + }; + + + + /////////////////////////////////////////////////////////////////////////// + /// intrusive_hashtable + /// + template + class intrusive_hashtable + { + public: + typedef intrusive_hashtable this_type; + typedef Key key_type; + typedef Value value_type; + typedef Value mapped_type; + typedef Value node_type; + typedef uint32_t hash_code_t; + typedef Equal key_equal; + typedef ptrdiff_t difference_type; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef value_type& reference; + typedef const value_type& const_reference; + typedef intrusive_node_iterator local_iterator; + typedef intrusive_node_iterator const_local_iterator; + typedef intrusive_hashtable_iterator iterator; + typedef intrusive_hashtable_iterator const_iterator; + typedef typename type_select, iterator>::type insert_return_type; + typedef typename type_select, + eastl::use_intrusive_key >::type extract_key; + + enum + { + kBucketCount = bucketCount + }; + + protected: + node_type* mBucketArray[kBucketCount + 1]; // '+1' because we have an end bucket which is non-NULL so iterators always stop on it. + size_type mnElementCount; + Hash mHash; // To do: Use base class optimization to make this go away when it is of zero size. + Equal mEqual; // To do: Use base class optimization to make this go away when it is of zero size. + + public: + intrusive_hashtable(const Hash&, const Equal&); + + void swap(this_type& x); + + iterator begin() EA_NOEXCEPT + { + iterator i(mBucketArray); + if(!i.mpNode) + i.increment_bucket(); + return i; + } + + const_iterator begin() const EA_NOEXCEPT + { + const_iterator i(const_cast(mBucketArray)); + if(!i.mpNode) + i.increment_bucket(); + return i; + } + + const_iterator cbegin() const EA_NOEXCEPT + { + return begin(); + } + + iterator end() EA_NOEXCEPT + { return iterator(mBucketArray + kBucketCount); } + + const_iterator end() const EA_NOEXCEPT + { return const_iterator(const_cast(mBucketArray) + kBucketCount); } + + const_iterator cend() const EA_NOEXCEPT + { return const_iterator(const_cast(mBucketArray) + kBucketCount); } + + local_iterator begin(size_type n) EA_NOEXCEPT + { return local_iterator(mBucketArray[n]); } + + const_local_iterator begin(size_type n) const EA_NOEXCEPT + { return const_local_iterator(mBucketArray[n]); } + + const_local_iterator cbegin(size_type n) const EA_NOEXCEPT + { return const_local_iterator(mBucketArray[n]); } + + local_iterator end(size_type) EA_NOEXCEPT + { return local_iterator(NULL); } + + const_local_iterator end(size_type) const EA_NOEXCEPT + { return const_local_iterator(NULL); } + + const_local_iterator cend(size_type) const EA_NOEXCEPT + { return const_local_iterator(NULL); } + + size_type size() const EA_NOEXCEPT + { return mnElementCount; } + + bool empty() const EA_NOEXCEPT + { return mnElementCount == 0; } + + size_type bucket_count() const EA_NOEXCEPT // This function is unnecessary, as the user can directly reference + { return kBucketCount; } // intrusive_hashtable::kBucketCount as a constant. + + size_type bucket_size(size_type n) const EA_NOEXCEPT + { return (size_type)eastl::distance(begin(n), end(n)); } + + size_type bucket(const key_type& k) const EA_NOEXCEPT + { return (size_type)(mHash(k) % kBucketCount); } + + public: + float load_factor() const EA_NOEXCEPT + { return (float)mnElementCount / (float)kBucketCount; } + + public: + insert_return_type insert(value_type& value) + { return DoInsertValue(value, integral_constant()); } + + insert_return_type insert(const_iterator, value_type& value) + { return insert(value); } // To consider: We might be able to use the iterator argument to specify a specific insertion location. + + template + void insert(InputIterator first, InputIterator last); + + public: + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + size_type erase(const key_type& k); + iterator remove(value_type& value); // Removes by value instead of by iterator. This is an O(1) operation, due to this hashtable being 'intrusive'. + + void clear(); + + public: + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + + /// Implements a find whereby the user supplies a comparison of a different type + /// than the hashtable value_type. A useful case of this is one whereby you have + /// a container of string objects but want to do searches via passing in char pointers. + /// The problem is that without this kind of find, you need to do the expensive operation + /// of converting the char pointer to a string so it can be used as the argument to the + /// find function. + /// + /// Example usage: + /// hash_set hashSet; + /// hashSet.find_as("hello"); // Use default hash and compare. + /// + /// Example usage (namespaces omitted for brevity): + /// hash_set hashSet; + /// hashSet.find_as("hello", hash(), equal_to_2()); + /// + template + iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate); + + template + const_iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate) const; + + template + iterator find_as(const U& u); + + template + const_iterator find_as(const U& u) const; + + size_type count(const key_type& k) const; + + // The use for equal_range in a hash_table seems somewhat questionable. + // The primary reason for its existence is to replicate the interface of set/map. + eastl::pair equal_range(const key_type& k); + eastl::pair equal_range(const key_type& k) const; + + public: + bool validate() const; + int validate_iterator(const_iterator i) const; + + public: + Hash hash_function() const + { return mHash; } + + Equal equal_function() const // Deprecated. Use key_eq() instead, as key_eq is what the new C++ standard + { return mEqual; } // has specified in its hashtable (unordered_*) proposal. + + const key_equal& key_eq() const + { return mEqual; } + + key_equal& key_eq() + { return mEqual; } + + protected: + eastl::pair DoInsertValue(value_type&, true_type); // true_type means bUniqueKeys is true. + iterator DoInsertValue(value_type&, false_type); // false_type means bUniqueKeys is false. + + node_type* DoFindNode(node_type* pNode, const key_type& k) const; + + template + node_type* DoFindNode(node_type* pNode, const U& u, BinaryPredicate predicate) const; + + }; // class intrusive_hashtable + + + + + + /////////////////////////////////////////////////////////////////////// + // node_iterator_base + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const intrusive_node_iterator& a, + const intrusive_node_iterator& b) + { return a.mpNode == b.mpNode; } + + template + inline bool operator!=(const intrusive_node_iterator& a, + const intrusive_node_iterator& b) + { return a.mpNode != b.mpNode; } + + + + + /////////////////////////////////////////////////////////////////////// + // hashtable_iterator_base + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const intrusive_hashtable_iterator_base& a, + const intrusive_hashtable_iterator_base& b) + { return a.mpNode == b.mpNode; } + + + template + inline bool operator!=(const intrusive_hashtable_iterator_base& a, + const intrusive_hashtable_iterator_base& b) + { return a.mpNode != b.mpNode; } + + + + + /////////////////////////////////////////////////////////////////////// + // intrusive_hashtable + /////////////////////////////////////////////////////////////////////// + + template + inline intrusive_hashtable::intrusive_hashtable(const H& h, const Eq& eq) + : mnElementCount(0), + mHash(h), + mEqual(eq) + { + memset(mBucketArray, 0, kBucketCount * sizeof(mBucketArray[0])); + mBucketArray[kBucketCount] = reinterpret_cast((uintptr_t)~0); + } + + + template + void intrusive_hashtable::swap(this_type& x) + { + for(size_t i = 0; i < kBucketCount; i++) + eastl::swap(mBucketArray[i], x.mBucketArray[i]); + + eastl::swap(mnElementCount, x.mnElementCount); + eastl::swap(mHash, x.mHash); + eastl::swap(mEqual, x.mEqual); + } + + + template + inline typename intrusive_hashtable::iterator + intrusive_hashtable::find(const key_type& k) + { + const size_type n = (size_type)(mHash(k) % kBucketCount); + node_type* const pNode = DoFindNode(mBucketArray[n], k); + return pNode ? iterator(pNode, mBucketArray + n) : iterator(mBucketArray + kBucketCount); + } + + + template + inline typename intrusive_hashtable::const_iterator + intrusive_hashtable::find(const key_type& k) const + { + const size_type n = (size_type)(mHash(k) % kBucketCount); + node_type* const pNode = DoFindNode(mBucketArray[n], k); + return pNode ? const_iterator(pNode, const_cast(mBucketArray) + n) : const_iterator(const_cast(mBucketArray) + kBucketCount); + } + + + template + template + inline typename intrusive_hashtable::iterator + intrusive_hashtable::find_as(const U& other, UHash uhash, BinaryPredicate predicate) + { + const size_type n = (size_type)(uhash(other) % kBucketCount); + node_type* const pNode = DoFindNode(mBucketArray[n], other, predicate); + return pNode ? iterator(pNode, mBucketArray + n) : iterator(mBucketArray + kBucketCount); + } + + + template + template + inline typename intrusive_hashtable::const_iterator + intrusive_hashtable::find_as(const U& other, UHash uhash, BinaryPredicate predicate) const + { + const size_type n = (size_type)(uhash(other) % kBucketCount); + node_type* const pNode = DoFindNode(mBucketArray[n], other, predicate); + return pNode ? const_iterator(pNode, const_cast(mBucketArray) + n) : const_iterator(const_cast(mBucketArray) + kBucketCount); + } + + + /// intrusive_hashtable_find + /// + /// Helper function that defaults to using hash and equal_to_2. + /// This makes it so that by default you don't need to provide these. + /// Note that the default hash functions may not be what you want, though. + /// + /// Example usage. Instead of this: + /// hash_set hashSet; + /// hashSet.find("hello", hash(), equal_to_2()); + /// + /// You can use this: + /// hash_set hashSet; + /// hashtable_find(hashSet, "hello"); + /// + template + inline typename H::iterator intrusive_hashtable_find(H& hashTable, const U& u) + { return hashTable.find_as(u, eastl::hash(), eastl::equal_to_2()); } + + template + inline typename H::const_iterator intrusive_hashtable_find(const H& hashTable, const U& u) + { return hashTable.find_as(u, eastl::hash(), eastl::equal_to_2()); } + + + + template + template + inline typename intrusive_hashtable::iterator + intrusive_hashtable::find_as(const U& other) + { return eastl::intrusive_hashtable_find(*this, other); } + // VC++ doesn't appear to like the following, though it seems correct to me. + // So we implement the workaround above until we can straighten this out. + //{ return find_as(other, eastl::hash(), eastl::equal_to_2()); } + + + template + template + inline typename intrusive_hashtable::const_iterator + intrusive_hashtable::find_as(const U& other) const + { return eastl::intrusive_hashtable_find(*this, other); } + // VC++ doesn't appear to like the following, though it seems correct to me. + // So we implement the workaround above until we can straighten this out. + //{ return find_as(other, eastl::hash(), eastl::equal_to_2()); } + + + template + typename intrusive_hashtable::size_type + intrusive_hashtable::count(const key_type& k) const + { + const size_type n = (size_type)(mHash(k) % kBucketCount); + size_type result = 0; + extract_key extractKey; // extract_key is empty and thus this ctor is a no-op. + + // To do: Make a specialization for bU (unique keys) == true and take + // advantage of the fact that the count will always be zero or one in that case. + for(node_type* pNode = mBucketArray[n]; pNode; pNode = static_cast(pNode->mpNext)) + { + if(mEqual(k, extractKey(*pNode))) + ++result; + } + return result; + } + + + template + eastl::pair::iterator, + typename intrusive_hashtable::iterator> + intrusive_hashtable::equal_range(const key_type& k) + { + const size_type n = (size_type)(mHash(k) % kBucketCount); + node_type** head = mBucketArray + n; + node_type* pNode = DoFindNode(*head, k); + extract_key extractKey; // extract_key is empty and thus this ctor is a no-op. + + if(pNode) + { + node_type* p1 = static_cast(pNode->mpNext); + + for(; p1; p1 = static_cast(p1->mpNext)) + { + if(!mEqual(k, extractKey(*p1))) + break; + } + + iterator first(pNode, head); + iterator last(p1, head); + + if(!p1) + last.increment_bucket(); + + return eastl::pair(first, last); + } + + return eastl::pair(iterator(mBucketArray + kBucketCount), + iterator(mBucketArray + kBucketCount)); + } + + + + + template + eastl::pair::const_iterator, + typename intrusive_hashtable::const_iterator> + intrusive_hashtable::equal_range(const key_type& k) const + { + const size_type n = (size_type)(mHash(k) % kBucketCount); + node_type** head = const_cast(mBucketArray + n); + node_type* pNode = DoFindNode(*head, k); + extract_key extractKey; // extract_key is empty and thus this ctor is a no-op. + + if(pNode) + { + node_type* p1 = static_cast(pNode->mpNext); + + for(; p1; p1 = static_cast(p1->mpNext)) + { + if(!mEqual(k, extractKey(*p1))) + break; + } + + const_iterator first(pNode, head); + const_iterator last(p1, head); + + if(!p1) + last.increment_bucket(); + + return eastl::pair(first, last); + } + + return eastl::pair(const_iterator(const_cast(mBucketArray) + kBucketCount), + const_iterator(const_cast(mBucketArray) + kBucketCount)); + } + + + template + inline typename intrusive_hashtable::node_type* + intrusive_hashtable::DoFindNode(node_type* pNode, const key_type& k) const + { + extract_key extractKey; // extract_key is empty and thus this ctor is a no-op. + + for(; pNode; pNode = static_cast(pNode->mpNext)) + { + if(mEqual(k, extractKey(*pNode))) + return pNode; + } + return NULL; + } + + + template + template + inline typename intrusive_hashtable::node_type* + intrusive_hashtable::DoFindNode(node_type* pNode, const U& other, BinaryPredicate predicate) const + { + extract_key extractKey; // extract_key is empty and thus this ctor is a no-op. + + for(; pNode; pNode = static_cast(pNode->mpNext)) + { + if(predicate(extractKey(*pNode), other)) // Intentionally compare with key as first arg and other as second arg. + return pNode; + } + return NULL; + } + + + template + eastl::pair::iterator, bool> + intrusive_hashtable::DoInsertValue(value_type& value, true_type) // true_type means bUniqueKeys is true. + { + // For sets (as opposed to maps), one could argue that all insertions are successful, + // as all elements are unique. However, the equal function might not think so. + extract_key extractKey; // extract_key is empty and thus this ctor is a no-op. + const size_type n = (size_type)(mHash(extractKey(value)) % kBucketCount); + node_type* const pNode = DoFindNode(mBucketArray[n], extractKey(value)); + + if(pNode == NULL) + { + value.mpNext = mBucketArray[n]; + mBucketArray[n] = &value; + ++mnElementCount; + + return eastl::pair(iterator(&value, mBucketArray + n), true); + } + + return eastl::pair(iterator(pNode, mBucketArray + n), false); + } + + + template + typename intrusive_hashtable::iterator + intrusive_hashtable::DoInsertValue(value_type& value, false_type) // false_type means bUniqueKeys is false. + { + extract_key extractKey; // extract_key is empty and thus this ctor is a no-op. + const size_type n = (size_type)(mHash(extractKey(value)) % kBucketCount); + node_type* const pNodePrev = DoFindNode(mBucketArray[n], extractKey(value)); + + if(pNodePrev == NULL) + { + value.mpNext = mBucketArray[n]; + mBucketArray[n] = &value; + } + else + { + value.mpNext = pNodePrev->mpNext; + pNodePrev->mpNext = &value; + } + + ++mnElementCount; + + return iterator(&value, mBucketArray + n); + } + + + + template + template + inline void intrusive_hashtable::insert(InputIterator first, InputIterator last) + { + for(; first != last; ++first) + insert(*first); + } + + + template + typename intrusive_hashtable::iterator + intrusive_hashtable::erase(const_iterator i) + { + iterator iNext(i.mpNode, i.mpBucket); + ++iNext; + + node_type* pNode = i.mpNode; + node_type* pNodeCurrent = *i.mpBucket; + + if(pNodeCurrent == pNode) + *i.mpBucket = static_cast(pNodeCurrent->mpNext); + else + { + // We have a singly-linked list, so we have no choice but to + // walk down it till we find the node before the node at 'i'. + node_type* pNodeNext = static_cast(pNodeCurrent->mpNext); + + while(pNodeNext != pNode) + { + pNodeCurrent = pNodeNext; + pNodeNext = static_cast(pNodeCurrent->mpNext); + } + + pNodeCurrent->mpNext = static_cast(pNodeNext->mpNext); + } + + // To consider: In debug builds set the node mpNext to NULL. + --mnElementCount; + + return iNext; + } + + + template + inline typename intrusive_hashtable::iterator + intrusive_hashtable::erase(const_iterator first, const_iterator last) + { + while(first != last) + first = erase(first); + return iterator(first.mpNode, first.mpBucket); + } + + + template + typename intrusive_hashtable::size_type + intrusive_hashtable::erase(const key_type& k) + { + const size_type n = (size_type)(mHash(k) % kBucketCount); + const size_type nElementCountSaved = mnElementCount; + node_type*& pNodeBase = mBucketArray[n]; + extract_key extractKey; // extract_key is empty and thus this ctor is a no-op. + + // Note by Paul Pedriana: + // We have two loops here, and I'm not finding any easy way to having just one + // loop without changing the requirements of the hashtable node definition. + // It's a problem of taking an address of a variable and converting it to the + // address of another type without knowing what that type is. Perhaps I'm a + // little overly tired, so if there is a simple solution I am probably missing it. + + while(pNodeBase && mEqual(k, extractKey(*pNodeBase))) + { + pNodeBase = static_cast(pNodeBase->mpNext); + --mnElementCount; + } + + node_type* pNodePrev = pNodeBase; + + if(pNodePrev) + { + node_type* pNodeCur; + + while((pNodeCur = static_cast(pNodePrev->mpNext)) != NULL) + { + if(mEqual(k, extractKey(*pNodeCur))) + { + pNodePrev->mpNext = static_cast(pNodeCur->mpNext); + --mnElementCount; // To consider: In debug builds set the node mpNext to NULL. + } + else + pNodePrev = static_cast(pNodePrev->mpNext); + } + } + + return nElementCountSaved - mnElementCount; + } + + + template + inline typename intrusive_hashtable::iterator + intrusive_hashtable::remove(value_type& value) + { + extract_key extractKey; // extract_key is empty and thus this ctor is a no-op. + const size_type n = (size_type)(mHash(extractKey(value)) % kBucketCount); + + return erase(iterator(&value, &mBucketArray[n])); + } + + + template + inline void intrusive_hashtable::clear() + { + // To consider: In debug builds set the node mpNext to NULL. + memset(mBucketArray, 0, kBucketCount * sizeof(mBucketArray[0])); + mnElementCount = 0; + } + + + template + inline bool intrusive_hashtable::validate() const + { + // Verify that the element count matches mnElementCount. + size_type nElementCount = 0; + + for(const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp) + ++nElementCount; + + if(nElementCount != mnElementCount) + return false; + + // To do: Verify that individual elements are in the expected buckets. + + return true; + } + + + template + int intrusive_hashtable::validate_iterator(const_iterator i) const + { + // To do: Come up with a more efficient mechanism of doing this. + + for(const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp) + { + if(temp == i) + return (isf_valid | isf_current | isf_can_dereference); + } + + if(i == end()) + return (isf_valid | isf_current); + + return isf_none; + } + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const intrusive_hashtable& a, + const intrusive_hashtable& b) + { + return (a.size() == b.size()) && eastl::equal(a.begin(), a.end(), b.begin()); + } + + + template + inline bool operator!=(const intrusive_hashtable& a, + const intrusive_hashtable& b) + { + return !(a == b); + } + + + // Comparing hash tables for less-ness is an odd thing to do. We provide it for + // completeness, though the user is advised to be wary of how they use this. + template + inline bool operator<(const intrusive_hashtable& a, + const intrusive_hashtable& b) + { + // This requires hash table elements to support operator<. Since the hash table + // doesn't compare elements via less (it does so via equals), we must use the + // globally defined operator less for the elements. + return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); + } + + + template + inline bool operator>(const intrusive_hashtable& a, + const intrusive_hashtable& b) + { + return b < a; + } + + + template + inline bool operator<=(const intrusive_hashtable& a, + const intrusive_hashtable& b) + { + return !(b < a); + } + + + template + inline bool operator>=(const intrusive_hashtable& a, + const intrusive_hashtable& b) + { + return !(a < b); + } + + + template + inline void swap(const intrusive_hashtable& a, + const intrusive_hashtable& b) + { + a.swap(b); + } + + +} // namespace eastl + + + +#endif // Header include guard + + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/mem_fn.h b/libs/eastl/include/EASTL/internal/mem_fn.h new file mode 100644 index 0000000..e36a92c --- /dev/null +++ b/libs/eastl/include/EASTL/internal/mem_fn.h @@ -0,0 +1,470 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_MEM_FN_H +#define EASTL_INTERNAL_MEM_FN_H + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) +#pragma once +#endif + +//////////////////////////////////////////////////////////////////////////////// +// The code in this file is a modification of the libcxx implementation. We copy +// the license information here as required. +// +// We implement only enough of mem_fn to implement eastl::function. +//////////////////////////////////////////////////////////////////////////////// + +//===------------------------ functional ----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +namespace eastl +{ + // + // apply_cv + // + template ::type>::value, + bool = is_volatile::type>::value> + struct apply_cv { typedef U type; }; + + template struct apply_cv { typedef const U type; }; + template struct apply_cv { typedef volatile U type; }; + template struct apply_cv { typedef const volatile U type; }; + template struct apply_cv { typedef U& type; }; + template struct apply_cv { typedef const U& type; }; + template struct apply_cv { typedef volatile U& type; }; + template struct apply_cv { typedef const volatile U& type; }; + + + + // + // has_result_type + // + template + struct has_result_type + { + private: + template + static eastl::no_type test(...); + + template + static eastl::yes_type test(typename U::result_type* = 0); + + public: + static const bool value = sizeof(test(0)) == sizeof(eastl::yes_type); + }; + + + + // + // derives_from_unary_function + // derives_from_binary_function + // + template + struct derives_from_unary_function + { + private: + static eastl::no_type test(...); + + template + static unary_function test(const volatile unary_function*); + + public: + static const bool value = !is_same::value; + typedef decltype(test((T*)0)) type; + }; + + template + struct derives_from_binary_function + { + private: + static eastl::no_type test(...); + template + static binary_function test(const volatile binary_function*); + + public: + static const bool value = !is_same::value; + typedef decltype(test((T*)0)) type; + }; + + + + // + // maybe_derives_from_unary_function + // maybe_derives_from_binary_function + // + template ::value> + struct maybe_derive_from_unary_function // bool is true + : public derives_from_unary_function::type { }; + + template + struct maybe_derive_from_unary_function { }; + + template ::value> + struct maybe_derive_from_binary_function // bool is true + : public derives_from_binary_function::type { }; + + template + struct maybe_derive_from_binary_function { }; + + + + // + // weak_result_type_imp + // + template ::value> + struct weak_result_type_imp // bool is true + : public maybe_derive_from_unary_function, + public maybe_derive_from_binary_function + { + typedef typename T::result_type result_type; + }; + + template + struct weak_result_type_imp : public maybe_derive_from_unary_function, + public maybe_derive_from_binary_function { }; + + + + // + // weak_result_type + // + template + struct weak_result_type : public weak_result_type_imp { }; + + // 0 argument case + template struct weak_result_type { typedef R result_type; }; + template struct weak_result_type { typedef R result_type; }; + template struct weak_result_type { typedef R result_type; }; + + // 1 argument case + template struct weak_result_type : public unary_function { }; + template struct weak_result_type : public unary_function { }; + template struct weak_result_type : public unary_function { }; + template struct weak_result_type : public unary_function { }; + template struct weak_result_type : public unary_function { }; + template struct weak_result_type : public unary_function { }; + template struct weak_result_type : public unary_function { }; + + // 2 argument case + template struct weak_result_type : public binary_function { }; + template struct weak_result_type : public binary_function { }; + template struct weak_result_type : public binary_function { }; + template struct weak_result_type : public binary_function { }; + template struct weak_result_type : public binary_function { }; + template struct weak_result_type : public binary_function { }; + template struct weak_result_type : public binary_function { }; + + // 3 or more arguments +#if EASTL_VARIADIC_TEMPLATES_ENABLED + template struct weak_result_type { typedef R result_type; }; + template struct weak_result_type { typedef R result_type; }; + template struct weak_result_type { typedef R result_type; }; + template struct weak_result_type { typedef R result_type; }; + template struct weak_result_type { typedef R result_type; }; + template struct weak_result_type { typedef R result_type; }; + template struct weak_result_type { typedef R result_type; }; +#endif + + + // + // invoke_impl + // +#if EASTL_VARIADIC_TEMPLATES_ENABLED + template + EASTL_FORCE_INLINE auto invoke_impl(F&& f, A0&& a0, Args&&... args) + -> decltype((eastl::forward(a0).*f)(eastl::forward(args)...)) + { + return (eastl::forward(a0).*f)(eastl::forward(args)...); + } + + // Enable once expressions FINAE is widely available. + // + // template + // EASTL_FORCE_INLINE auto invoke_impl(F&& f, A0&& a0, Args&&... args) + // -> decltype(((*eastl::forward(a0)).*f)(eastl::forward(args)...)) + // { + // return ((*eastl::forward(a0)).*f)(eastl::forward(args)...); + // } + + template + EASTL_FORCE_INLINE auto invoke_impl(F&& f, A0&& a0) -> decltype(eastl::forward(a0).*f) + { + return eastl::forward(a0).*f; + } + + // Enable once expressions FINAE is widely available. + // + // template + // EASTL_FORCE_INLINE auto invoke_impl(F&& f, A0&& a0) -> decltype((*eastl::forward(a0)).*f) + // { + // return (*eastl::forward(a0)).*f; + // } + + template + EASTL_FORCE_INLINE auto invoke_impl(F&& f, Args&&... args) + -> decltype(eastl::forward(f)(eastl::forward(args)...)) + { + return eastl::forward(f)(eastl::forward(args)...); + } +#else + template + EASTL_FORCE_INLINE auto invoke_impl(F&& f, A0&& a0) + -> decltype(eastl::forward(f)(eastl::forward(a0))) + { + return eastl::forward(f)(eastl::forward(a0)); + } + + template + EASTL_FORCE_INLINE auto invoke_impl(F&& f, A0&& a0, A1&& a1) + -> decltype(eastl::forward(f)(eastl::forward(a0), eastl::forward(a1))) + { + return eastl::forward(f)(eastl::forward(a0), eastl::forward(a1)); + } + + template + EASTL_FORCE_INLINE auto invoke_impl(F&& f, A0&& a0, A1&& a1, A2&& a2) + -> decltype(eastl::forward(f)(eastl::forward(a0), eastl::forward(a1), eastl::forward(a2))) + { + return eastl::forward(f)(eastl::forward(a0), eastl::forward(a1), eastl::forward(a2)); + } +#endif + + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // invoke_return + // +#if EASTL_VARIADIC_TEMPLATES_ENABLED + template + struct invoke_return + { + typedef decltype(invoke_impl(eastl::declval(), eastl::declval()...)) type; + }; +#else + // Following are required for binary_function/unary_function support. + // Since this isn't important for our environment this is left as future work. + // + // template ::value>> + // struct invoke_return + // { + // typedef typename weak_result_type::result_type type; + // }; + + // template + // struct invoke_return + // { + // typedef decltype(invoke_impl(eastl::declval())) type; + // }; + + template + struct invoke_return + { + typedef decltype(invoke_impl(eastl::declval(), eastl::declval())) type; + }; + + template + struct invoke_return0 + { + typedef decltype(invoke_impl(eastl::declval(), eastl::declval())) type; + }; + + template + struct invoke_return0 + { + typedef typename apply_cv::type& type; + }; + + template + struct invoke_return0 + { + typedef typename apply_cv::type& type; + }; + + template + struct invoke_return1 + { + typedef decltype(invoke_impl(eastl::declval(), eastl::declval(), eastl::declval())) type; + }; + + template + struct invoke_return2 + { + typedef decltype( + invoke_impl(eastl::declval(), eastl::declval(), eastl::declval(), eastl::declval())) type; + }; +#endif + + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // eastl::invoke + // +#if EASTL_VARIADIC_TEMPLATES_ENABLED + template + typename invoke_return::type + invoke(F&& f, Args&&... args) + { + return invoke_impl(eastl::forward(f), eastl::forward(args)...); + } +#else + template + typename invoke_return0::type + invoke(F&& f, A0&& a0) + { + return invoke_impl(eastl::forward(f), eastl::forward(a0)); + } + + template + typename invoke_return1::type + invoke(F&& f, A0&& a0, A1&& a1) + { + return invoke_impl(eastl::forward(f), eastl::forward(a0), eastl::forward(a1)); + } + + template + typename invoke_return2::type + invoke(F&& f, A0&& a0, A1&& a1, A2&& a2) + { + return invoke_impl(eastl::forward(f), eastl::forward(a0), eastl::forward(a1), eastl::forward(a2)); + } +#endif + + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // mem_fn_impl + // + template + class mem_fn_impl +#if defined(_MSC_VER) && (_MSC_VER >= 1900) // VS2015 or later + // Due to a (seemingly random) internal compiler error on VS2013 we disable eastl::unary_function and + // binary_function support for eastl::mem_fn as its not widely (if at all) used. If you require this support + // on VS2013 or below please contact us. + : public weak_result_type +#endif + { + public: + typedef T type; + + private: + type func; + + public: + EASTL_FORCE_INLINE mem_fn_impl(type _func) : func(_func) {} + +#if EASTL_VARIADIC_TEMPLATES_ENABLED + template + typename invoke_return::type operator()(ArgTypes&&... args) const + { + return invoke_impl(func, eastl::forward(args)...); + } +#else + typename invoke_return::type operator()() const { return invoke_impl(func); } + + template + typename invoke_return0::type operator()(A0& a0) const + { + return invoke_impl(func, a0); + } + + template + typename invoke_return1::type operator()(A0& a0, A1& a1) const + { + return invoke_impl(func, a0, a1); + } + + template + typename invoke_return2::type operator()(A0& a0, A1& a1, A2& a2) const + { + return invoke_impl(func, a0, a1, a2); + } +#endif + }; // mem_fn_impl + + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // mem_fn -> mem_fn_impl adapters + // + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R T::*pm) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)()) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)(A0)) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)(A0, A1)) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)(A0, A1, A2)) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)() const) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)(A0) const) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)(A0, A1) const) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)(A0, A1, A2) const) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)() volatile) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)(A0) volatile) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)(A0, A1) volatile) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)(A0, A1, A2) volatile) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)() const volatile) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)(A0) const volatile) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)(A0, A1) const volatile) + { return mem_fn_impl(pm); } + + template + EASTL_FORCE_INLINE mem_fn_impl mem_fn(R (T::*pm)(A0, A1, A2) const volatile) + { return mem_fn_impl(pm); } + +} // namespace eastl + +#endif // EASTL_INTERNAL_MEM_FN_H diff --git a/libs/eastl/include/EASTL/internal/move_help.h b/libs/eastl/include/EASTL/internal/move_help.h new file mode 100644 index 0000000..20bab67 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/move_help.h @@ -0,0 +1,196 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_MOVE_HELP_H +#define EASTL_INTERNAL_MOVE_HELP_H + + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include +#include + + +// C++11's rvalue references aren't supported by earlier versions of C++. +// It turns out that in a number of cases under earlier C++ versions we can +// write code that uses rvalues similar to lvalues. We have macros below for +// such cases. For example, eastl::move (same as std::move) can be treated +// as a no-op under C++03, though with the consequence that move functionality +// isn't taken advantage of. + + +/// EASTL_MOVE +/// Acts like eastl::move when possible. Same as C++11 std::move. +/// +/// EASTL_MOVE_INLINE +/// Acts like eastl::move but is implemented inline instead of a function call. +/// This allows code to be faster in debug builds in particular. +/// Depends on C++ compiler decltype support or a similar extension. +/// +/// EASTL_FORWARD +/// Acts like eastl::forward when possible. Same as C++11 std::forward. +/// +/// EASTL_FORWARD_INLINE +/// Acts like eastl::forward but is implemented inline instead of a function call. +/// This allows code to be faster in debug builds in particular. +/// +#if EASTL_MOVE_SEMANTICS_ENABLED + #define EASTL_MOVE(x) eastl::move(x) + #if !defined(EA_COMPILER_NO_DECLTYPE) + #define EASTL_MOVE_INLINE(x) static_cast::type&&>(x) + #elif defined(__GNUC__) + #define EASTL_MOVE_INLINE(x) static_cast::type&&>(x) + #else + #define EASTL_MOVE_INLINE(x) eastl::move(x) + #endif + + #define EASTL_FORWARD(T, x) eastl::forward(x) + #define EASTL_FORWARD_INLINE(T, x) eastl::forward(x) // Need to investigate how to properly make a macro for this. (eastl::is_reference::value ? static_cast(static_cast(x)) : static_cast(x)) +#else + #define EASTL_MOVE(x) (x) + #define EASTL_MOVE_INLINE(x) (x) + + #define EASTL_FORWARD(T, x) (x) + #define EASTL_FORWARD_INLINE(T, x) (x) +#endif + + + + +/// EASTL_MOVE_RANGE +/// Acts like the eastl::move algorithm when possible. Same as C++11 std::move. +/// Note to be confused with the single argument move: (typename remove_reference::type&& move(T&& x)) +/// http://en.cppreference.com/w/cpp/algorithm/move +/// http://en.cppreference.com/w/cpp/algorithm/move_backward +/// +#if EASTL_MOVE_SEMANTICS_ENABLED + #define EASTL_MOVE_RANGE(first, last, result) eastl::move(first, last, result) + #define EASTL_MOVE_BACKWARD_RANGE(first, last, resultEnd) eastl::move_backward(first, last, resultEnd) +#else + #define EASTL_MOVE_RANGE(first, last, result) eastl::copy(first, last, result) + #define EASTL_MOVE_BACKWARD_RANGE(first, last, result) eastl::copy_backward(first, last, result) +#endif + + +namespace eastl +{ + #if EASTL_MOVE_SEMANTICS_ENABLED + // forward + // + // forwards the argument to another function exactly as it was passed to the calling function. + // Not to be confused with move, this is specifically for echoing templated argument types + // to another function. move is specifically about making a type be an rvalue reference (i.e. movable) type. + // + // Example usage: + // template + // void WrapperFunction(T&& arg) + // { foo(eastl::forward(arg)); } + // + // template + // void WrapperFunction(Args&&... args) + // { foo(eastl::forward(args)...); } + // + // See the C++ Standard, section 20.2.3 + // http://en.cppreference.com/w/cpp/utility/forward + // + template + EA_CPP14_CONSTEXPR T&& forward(typename eastl::remove_reference::type& x) EA_NOEXCEPT + { + return static_cast(x); + } + + + template + EA_CPP14_CONSTEXPR T&& forward(typename eastl::remove_reference::type&& x) EA_NOEXCEPT + { + //static_assert(!is_lvalue_reference::value, "forward T isn't lvalue reference"); + return static_cast(x); + } + + + // move + // + // move obtains an rvalue reference to its argument and converts it to an xvalue. + // Returns, by definition: static_cast::type&&>(t). + // The primary use of this is to pass a move'd type to a function which takes T&&, + // and thus select that function instead of (e.g.) a function which takes T or T&. + // See the C++ Standard, section 20.2.3 + // http://en.cppreference.com/w/cpp/utility/move + // + template + EA_CPP14_CONSTEXPR typename eastl::remove_reference::type&& + move(T&& x) EA_NOEXCEPT + { + return ((typename eastl::remove_reference::type&&)x); + } + + + // move_if_noexcept + // + // Returns T&& if move-constructing T throws no exceptions. Instead returns const T& if + // move-constructing T throws exceptions or has no accessible copy constructor. + // The purpose of this is to use automatically use copy construction instead of move + // construction when the move may possible throw an exception. + // See the C++ Standard, section 20.2.3 + // http://en.cppreference.com/w/cpp/utility/move_if_noexcept + // + #if EASTL_EXCEPTIONS_ENABLED + template + EA_CPP14_CONSTEXPR typename eastl::conditional::value && + eastl::is_copy_constructible::value, const T&, T&&>::type + move_if_noexcept(T& x) EA_NOEXCEPT + { + return eastl::move(x); + } + #else + template + EA_CPP14_CONSTEXPR T&& + move_if_noexcept(T& x) EA_NOEXCEPT + { + return eastl::move(x); + } + #endif + #else + template + T& forward(T& x) EA_NOEXCEPT + { + return x; + } + + template + T& move(T& x) EA_NOEXCEPT + { + return x; + } + + template + T& move_if_noexcept(T& x) EA_NOEXCEPT + { + return x; + } + + #endif // EASTL_MOVE_SEMANTICS_ENABLED + +} // namespace eastl + +#endif // Header include guard + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/pair_fwd_decls.h b/libs/eastl/include/EASTL/internal/pair_fwd_decls.h new file mode 100644 index 0000000..a716482 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/pair_fwd_decls.h @@ -0,0 +1,16 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_PAIR_FWD_DECLS_H +#define EASTL_PAIR_FWD_DECLS_H + +#include + +namespace eastl +{ + template + struct pair; +} + +#endif // EASTL_PAIR_FWD_DECLS_H diff --git a/libs/eastl/include/EASTL/internal/red_black_tree.h b/libs/eastl/include/EASTL/internal/red_black_tree.h new file mode 100644 index 0000000..a0a2ff1 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/red_black_tree.h @@ -0,0 +1,2296 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_RED_BLACK_TREE_H +#define EASTL_RED_BLACK_TREE_H + + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + #pragma warning(push, 0) + #include + #include + #pragma warning(pop) +#else + #include + #include +#endif + + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4512) // 'class' : assignment operator could not be generated + #pragma warning(disable: 4530) // C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc + #pragma warning(disable: 4571) // catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught. +#endif + + +namespace eastl +{ + + /// EASTL_RBTREE_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_RBTREE_DEFAULT_NAME + #define EASTL_RBTREE_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " rbtree" // Unless the user overrides something, this is "EASTL rbtree". + #endif + + + /// EASTL_RBTREE_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_RBTREE_DEFAULT_ALLOCATOR + #define EASTL_RBTREE_DEFAULT_ALLOCATOR allocator_type(EASTL_RBTREE_DEFAULT_NAME) + #endif + + + + /// RBTreeColor + /// + enum RBTreeColor + { + kRBTreeColorRed, + kRBTreeColorBlack + }; + + + + /// RBTreeColor + /// + enum RBTreeSide + { + kRBTreeSideLeft, + kRBTreeSideRight + }; + + + + /// rbtree_node_base + /// + /// We define a rbtree_node_base separately from rbtree_node (below), because it + /// allows us to have non-templated operations, and it makes it so that the + /// rbtree anchor node doesn't carry a T with it, which would waste space and + /// possibly lead to surprising the user due to extra Ts existing that the user + /// didn't explicitly create. The downside to all of this is that it makes debug + /// viewing of an rbtree harder, given that the node pointers are of type + /// rbtree_node_base and not rbtree_node. + /// + struct rbtree_node_base + { + typedef rbtree_node_base this_type; + + public: + this_type* mpNodeRight; // Declared first because it is used most often. + this_type* mpNodeLeft; + this_type* mpNodeParent; + char mColor; // We only need one bit here, would be nice if we could stuff that bit somewhere else. + }; + + + /// rbtree_node + /// + template + struct rbtree_node : public rbtree_node_base + { + Value mValue; // For set and multiset, this is the user's value, for map and multimap, this is a pair of key/value. + + // This type is never constructed, so to avoid a MSVC warning we "delete" the copy constructor. + // + // Potentially we could provide a constructor that would satisfy the compiler and change the code to use this constructor + // instead of constructing mValue in place within an unconstructed rbtree_node. + #if defined(_MSC_VER) + #if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) + rbtree_node(const rbtree_node&) = delete; + #else + private: + rbtree_node(const rbtree_node&); + #endif + #endif + }; + + + + + // rbtree_node_base functions + // + // These are the fundamental functions that we use to maintain the + // tree. The bulk of the work of the tree maintenance is done in + // these functions. + // + EASTL_API rbtree_node_base* RBTreeIncrement (const rbtree_node_base* pNode); + EASTL_API rbtree_node_base* RBTreeDecrement (const rbtree_node_base* pNode); + EASTL_API rbtree_node_base* RBTreeGetMinChild (const rbtree_node_base* pNode); + EASTL_API rbtree_node_base* RBTreeGetMaxChild (const rbtree_node_base* pNode); + EASTL_API size_t RBTreeGetBlackCount(const rbtree_node_base* pNodeTop, + const rbtree_node_base* pNodeBottom); + EASTL_API void RBTreeInsert ( rbtree_node_base* pNode, + rbtree_node_base* pNodeParent, + rbtree_node_base* pNodeAnchor, + RBTreeSide insertionSide); + EASTL_API void RBTreeErase ( rbtree_node_base* pNode, + rbtree_node_base* pNodeAnchor); + + + + + + + + /// rbtree_iterator + /// + template + struct rbtree_iterator + { + typedef rbtree_iterator this_type; + typedef rbtree_iterator iterator; + typedef rbtree_iterator const_iterator; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef rbtree_node_base base_node_type; + typedef rbtree_node node_type; + typedef Pointer pointer; + typedef Reference reference; + typedef EASTL_ITC_NS::bidirectional_iterator_tag iterator_category; + + public: + node_type* mpNode; + + public: + rbtree_iterator(); + explicit rbtree_iterator(const node_type* pNode); + rbtree_iterator(const iterator& x); + + reference operator*() const; + pointer operator->() const; + + rbtree_iterator& operator++(); + rbtree_iterator operator++(int); + + rbtree_iterator& operator--(); + rbtree_iterator operator--(int); + + }; // rbtree_iterator + + + + + + /////////////////////////////////////////////////////////////////////////////// + // rb_base + // + // This class allows us to use a generic rbtree as the basis of map, multimap, + // set, and multiset transparently. The vital template parameters for this are + // the ExtractKey and the bUniqueKeys parameters. + // + // If the rbtree has a value type of the form pair (i.e. it is a map or + // multimap and not a set or multiset) and a key extraction policy that returns + // the first part of the pair, the rbtree gets a mapped_type typedef. + // If it satisfies those criteria and also has unique keys, then it also gets an + // operator[] (which only map and set have and multimap and multiset don't have). + // + /////////////////////////////////////////////////////////////////////////////// + + + + /// rb_base + /// This specialization is used for 'set'. In this case, Key and Value + /// will be the same as each other and ExtractKey will be eastl::use_self. + /// + template + struct rb_base + { + typedef ExtractKey extract_key; + + public: + Compare mCompare; // To do: Make sure that empty Compare classes go away via empty base optimizations. + + public: + rb_base() : mCompare() {} + rb_base(const Compare& compare) : mCompare(compare) {} + }; + + + /// rb_base + /// This class is used for 'multiset'. + /// In this case, Key and Value will be the same as each + /// other and ExtractKey will be eastl::use_self. + /// + template + struct rb_base + { + typedef ExtractKey extract_key; + + public: + Compare mCompare; // To do: Make sure that empty Compare classes go away via empty base optimizations. + + public: + rb_base() : mCompare() {} + rb_base(const Compare& compare) : mCompare(compare) {} + }; + + + /// rb_base + /// This specialization is used for 'map'. + /// + template + struct rb_base, true, RBTree> + { + typedef eastl::use_first extract_key; + + public: + Compare mCompare; // To do: Make sure that empty Compare classes go away via empty base optimizations. + + public: + rb_base() : mCompare() {} + rb_base(const Compare& compare) : mCompare(compare) {} + }; + + + /// rb_base + /// This specialization is used for 'multimap'. + /// + template + struct rb_base, false, RBTree> + { + typedef eastl::use_first extract_key; + + public: + Compare mCompare; // To do: Make sure that empty Compare classes go away via empty base optimizations. + + public: + rb_base() : mCompare() {} + rb_base(const Compare& compare) : mCompare(compare) {} + }; + + + + + + /// rbtree + /// + /// rbtree is the red-black tree basis for the map, multimap, set, and multiset + /// containers. Just about all the work of those containers is done here, and + /// they are merely a shell which sets template policies that govern the code + /// generation for this rbtree. + /// + /// This rbtree implementation is pretty much the same as all other modern + /// rbtree implementations, as the topic is well known and researched. We may + /// choose to implement a "relaxed balancing" option at some point in the + /// future if it is deemed worthwhile. Most rbtree implementations don't do this. + /// + /// The primary rbtree member variable is mAnchor, which is a node_type and + /// acts as the end node. However, like any other node, it has mpNodeLeft, + /// mpNodeRight, and mpNodeParent members. We do the conventional trick of + /// assigning begin() (left-most rbtree node) to mpNodeLeft, assigning + /// 'end() - 1' (a.k.a. rbegin()) to mpNodeRight, and assigning the tree root + /// node to mpNodeParent. + /// + /// Compare (functor): This is a comparison class which defaults to 'less'. + /// It is a common STL thing which takes two arguments and returns true if + /// the first is less than the second. + /// + /// ExtractKey (functor): This is a class which gets the key from a stored + /// node. With map and set, the node is a pair, whereas with set and multiset + /// the node is just the value. ExtractKey will be either eastl::use_first (map and multimap) + /// or eastl::use_self (set and multiset). + /// + /// bMutableIterators (bool): true if rbtree::iterator is a mutable + /// iterator, false if iterator and const_iterator are both const iterators. + /// It will be true for map and multimap and false for set and multiset. + /// + /// bUniqueKeys (bool): true if the keys are to be unique, and false if there + /// can be multiple instances of a given key. It will be true for set and map + /// and false for multiset and multimap. + /// + /// To consider: Add an option for relaxed tree balancing. This could result + /// in performance improvements but would require a more complicated implementation. + /// + /////////////////////////////////////////////////////////////////////// + /// find_as + /// In order to support the ability to have a tree of strings but + /// be able to do efficiently lookups via char pointers (i.e. so they + /// aren't converted to string objects), we provide the find_as + /// function. This function allows you to do a find with a key of a + /// type other than the tree's key type. See the find_as function + /// for more documentation on this. + /// + template + class rbtree + : public rb_base > + { + public: + typedef ptrdiff_t difference_type; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef Key key_type; + typedef Value value_type; + typedef rbtree_node node_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + + typedef typename type_select, + rbtree_iterator >::type iterator; + typedef rbtree_iterator const_iterator; + typedef eastl::reverse_iterator reverse_iterator; + typedef eastl::reverse_iterator const_reverse_iterator; + + typedef Allocator allocator_type; + typedef Compare key_compare; + typedef typename type_select, iterator>::type insert_return_type; // map/set::insert return a pair, multimap/multiset::iterator return an iterator. + typedef rbtree this_type; + typedef rb_base base_type; + typedef integral_constant has_unique_keys_type; + typedef typename base_type::extract_key extract_key; + + using base_type::mCompare; + + public: + rbtree_node_base mAnchor; /// This node acts as end() and its mpLeft points to begin(), and mpRight points to rbegin() (the last node on the right). + size_type mnSize; /// Stores the count of nodes in the tree (not counting the anchor node). + allocator_type mAllocator; // To do: Use base class optimization to make this go away. + + public: + // ctor/dtor + rbtree(); + rbtree(const allocator_type& allocator); + rbtree(const Compare& compare, const allocator_type& allocator = EASTL_RBTREE_DEFAULT_ALLOCATOR); + rbtree(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + rbtree(this_type&& x); + rbtree(this_type&& x, const allocator_type& allocator); + #endif + + template + rbtree(InputIterator first, InputIterator last, const Compare& compare, const allocator_type& allocator = EASTL_RBTREE_DEFAULT_ALLOCATOR); + + ~rbtree(); + + public: + // properties + const allocator_type& get_allocator() const EA_NOEXCEPT; + allocator_type& get_allocator() EA_NOEXCEPT; + void set_allocator(const allocator_type& allocator); + + const key_compare& key_comp() const { return mCompare; } + key_compare& key_comp() { return mCompare; } + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + void swap(this_type& x); + + public: + // iterators + iterator begin() EA_NOEXCEPT; + const_iterator begin() const EA_NOEXCEPT; + const_iterator cbegin() const EA_NOEXCEPT; + + iterator end() EA_NOEXCEPT; + const_iterator end() const EA_NOEXCEPT; + const_iterator cend() const EA_NOEXCEPT; + + reverse_iterator rbegin() EA_NOEXCEPT; + const_reverse_iterator rbegin() const EA_NOEXCEPT; + const_reverse_iterator crbegin() const EA_NOEXCEPT; + + reverse_iterator rend() EA_NOEXCEPT; + const_reverse_iterator rend() const EA_NOEXCEPT; + const_reverse_iterator crend() const EA_NOEXCEPT; + + public: + bool empty() const EA_NOEXCEPT; + size_type size() const EA_NOEXCEPT; + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + insert_return_type emplace(Args&&... args); + + template + iterator emplace_hint(const_iterator position, Args&&... args); + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + insert_return_type emplace(value_type&& value); + iterator emplace_hint(const_iterator position, value_type&& value); + #endif + + insert_return_type emplace(const value_type& value); + iterator emplace_hint(const_iterator position, const value_type& value); + #endif + + #if EASTL_MOVE_SEMANTICS_ENABLED + template // Requires that "value_type is constructible from forward

(otherValue)." + insert_return_type insert(P&& otherValue); + + // Currently limited to value_type instead of P because it collides with insert(InputIterator, InputIterator). + // To allow this to work with templated P we need to implement a compile-time specialization for the + // case that P&& is const_iterator and have that specialization handle insert(InputIterator, InputIterator) + // instead of insert(InputIterator, InputIterator). Curiously, neither libstdc++ nor libc++ + // implement this function either, which suggests they ran into the same problem I did here + // and haven't yet resolved it (at least as of March 2014, GCC 4.8.1). + iterator insert(const_iterator hint, value_type&& value); + #endif + + /// map::insert and set::insert return a pair, while multimap::insert and + /// multiset::insert return an iterator. + insert_return_type insert(const value_type& value); + + // C++ standard: inserts value if and only if there is no element with + // key equivalent to the key of t in containers with unique keys; always + // inserts value in containers with equivalent keys. Always returns the + // iterator pointing to the element with key equivalent to the key of value. + // iterator position is a hint pointing to where the insert should start + // to search. However, there is a potential defect/improvement report on this behaviour: + // LWG issue #233 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1780.html) + // We follow the same approach as SGI STL/STLPort and use the position as + // a forced insertion position for the value when possible. + iterator insert(const_iterator position, const value_type& value); + + void insert(std::initializer_list ilist); + + template + void insert(InputIterator first, InputIterator last); + + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + + reverse_iterator erase(const_reverse_iterator position); + reverse_iterator erase(const_reverse_iterator first, const_reverse_iterator last); + + // For some reason, multiple STL versions make a specialization + // for erasing an array of key_types. I'm pretty sure we don't + // need this, but just to be safe we will follow suit. + // The implementation is trivial. Returns void because the values + // could well be randomly distributed throughout the tree and thus + // a return value would be nearly meaningless. + void erase(const key_type* first, const key_type* last); + + void clear(); + void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + + iterator find(const key_type& key); + const_iterator find(const key_type& key) const; + + /// Implements a find whereby the user supplies a comparison of a different type + /// than the tree's value_type. A useful case of this is one whereby you have + /// a container of string objects but want to do searches via passing in char pointers. + /// The problem is that without this kind of find, you need to do the expensive operation + /// of converting the char pointer to a string so it can be used as the argument to the + /// find function. + /// + /// Example usage (note that the compare uses string as first type and char* as second): + /// set strings; + /// strings.find_as("hello", less_2()); + /// + template + iterator find_as(const U& u, Compare2 compare2); + + template + const_iterator find_as(const U& u, Compare2 compare2) const; + + iterator lower_bound(const key_type& key); + const_iterator lower_bound(const key_type& key) const; + + iterator upper_bound(const key_type& key); + const_iterator upper_bound(const key_type& key) const; + + bool validate() const; + int validate_iterator(const_iterator i) const; + + #if EASTL_RESET_ENABLED + void reset(); // This function name is deprecated; use reset_lose_memory instead. + #endif + + protected: + node_type* DoAllocateNode(); + void DoFreeNode(node_type* pNode); + + node_type* DoCreateNodeFromKey(const key_type& key); + node_type* DoCreateNode(const value_type& value); + #if EASTL_MOVE_SEMANTICS_ENABLED + node_type* DoCreateNode(value_type&& value); + #endif + node_type* DoCreateNode(const node_type* pNodeSource, node_type* pNodeParent); + + node_type* DoCopySubtree(const node_type* pNodeSource, node_type* pNodeDest); + void DoNukeSubtree(node_type* pNode); + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + eastl::pair DoInsertValue(true_type, Args&&... args); + + template + iterator DoInsertValue(false_type, Args&&... args); + + template + iterator DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, Args&&... args); + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + eastl::pair DoInsertValue(true_type, value_type&& value); + iterator DoInsertValue(false_type, value_type&& value); + iterator DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, value_type&& value); + #endif + + eastl::pair DoInsertValue(true_type, const value_type& value); + iterator DoInsertValue(false_type, const value_type& value); + iterator DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, const value_type& value); + #endif + + eastl::pair DoInsertKey(true_type, const key_type& key); + iterator DoInsertKey(false_type, const key_type& key); + + iterator DoInsertValueHint(true_type, const_iterator position, const value_type& value); + iterator DoInsertValueHint(false_type, const_iterator position, const value_type& value); + + iterator DoInsertKey(true_type, const_iterator position, const key_type& key); // By design we return iterator and not a pair. + iterator DoInsertKey(false_type, const_iterator position, const key_type& key); + iterator DoInsertKeyImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key); + + node_type* DoGetKeyInsertionPositionUniqueKeys(bool& canInsert, const key_type& key); + node_type* DoGetKeyInsertionPositionNonuniqueKeys(const key_type& key); + + node_type* DoGetKeyInsertionPositionUniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key); + node_type* DoGetKeyInsertionPositionNonuniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key); + + }; // rbtree + + + + + + /////////////////////////////////////////////////////////////////////// + // rbtree_node_base functions + /////////////////////////////////////////////////////////////////////// + + EASTL_API inline rbtree_node_base* RBTreeGetMinChild(const rbtree_node_base* pNodeBase) + { + while(pNodeBase->mpNodeLeft) + pNodeBase = pNodeBase->mpNodeLeft; + return const_cast(pNodeBase); + } + + EASTL_API inline rbtree_node_base* RBTreeGetMaxChild(const rbtree_node_base* pNodeBase) + { + while(pNodeBase->mpNodeRight) + pNodeBase = pNodeBase->mpNodeRight; + return const_cast(pNodeBase); + } + + // The rest of the functions are non-trivial and are found in + // the corresponding .cpp file to this file. + + + + /////////////////////////////////////////////////////////////////////// + // rbtree_iterator functions + /////////////////////////////////////////////////////////////////////// + + template + rbtree_iterator::rbtree_iterator() + : mpNode(NULL) { } + + + template + rbtree_iterator::rbtree_iterator(const node_type* pNode) + : mpNode(static_cast(const_cast(pNode))) { } + + + template + rbtree_iterator::rbtree_iterator(const iterator& x) + : mpNode(x.mpNode) { } + + + template + typename rbtree_iterator::reference + rbtree_iterator::operator*() const + { return mpNode->mValue; } + + + template + typename rbtree_iterator::pointer + rbtree_iterator::operator->() const + { return &mpNode->mValue; } + + + template + typename rbtree_iterator::this_type& + rbtree_iterator::operator++() + { + mpNode = static_cast(RBTreeIncrement(mpNode)); + return *this; + } + + + template + typename rbtree_iterator::this_type + rbtree_iterator::operator++(int) + { + this_type temp(*this); + mpNode = static_cast(RBTreeIncrement(mpNode)); + return temp; + } + + + template + typename rbtree_iterator::this_type& + rbtree_iterator::operator--() + { + mpNode = static_cast(RBTreeDecrement(mpNode)); + return *this; + } + + + template + typename rbtree_iterator::this_type + rbtree_iterator::operator--(int) + { + this_type temp(*this); + mpNode = static_cast(RBTreeDecrement(mpNode)); + return temp; + } + + + // The C++ defect report #179 requires that we support comparisons between const and non-const iterators. + // Thus we provide additional template paremeters here to support this. The defect report does not + // require us to support comparisons between reverse_iterators and const_reverse_iterators. + template + inline bool operator==(const rbtree_iterator& a, + const rbtree_iterator& b) + { + return a.mpNode == b.mpNode; + } + + + template + inline bool operator!=(const rbtree_iterator& a, + const rbtree_iterator& b) + { + return a.mpNode != b.mpNode; + } + + + // We provide a version of operator!= for the case where the iterators are of the + // same type. This helps prevent ambiguity errors in the presence of rel_ops. + template + inline bool operator!=(const rbtree_iterator& a, + const rbtree_iterator& b) + { + return a.mpNode != b.mpNode; + } + + + + + /////////////////////////////////////////////////////////////////////// + // rbtree functions + /////////////////////////////////////////////////////////////////////// + + template + inline rbtree::rbtree() + : mAnchor(), + mnSize(0), + mAllocator(EASTL_RBTREE_DEFAULT_NAME) + { + reset_lose_memory(); + } + + + template + inline rbtree::rbtree(const allocator_type& allocator) + : mAnchor(), + mnSize(0), + mAllocator(allocator) + { + reset_lose_memory(); + } + + + template + inline rbtree::rbtree(const C& compare, const allocator_type& allocator) + : base_type(compare), + mAnchor(), + mnSize(0), + mAllocator(allocator) + { + reset_lose_memory(); + } + + + template + inline rbtree::rbtree(const this_type& x) + : base_type(x.mCompare), + mAnchor(), + mnSize(0), + mAllocator(x.mAllocator) + { + reset_lose_memory(); + + if(x.mAnchor.mpNodeParent) // mAnchor.mpNodeParent is the rb_tree root node. + { + mAnchor.mpNodeParent = DoCopySubtree((const node_type*)x.mAnchor.mpNodeParent, (node_type*)&mAnchor); + mAnchor.mpNodeRight = RBTreeGetMaxChild(mAnchor.mpNodeParent); + mAnchor.mpNodeLeft = RBTreeGetMinChild(mAnchor.mpNodeParent); + mnSize = x.mnSize; + } + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline rbtree::rbtree(this_type&& x) + : base_type(x.mCompare), + mAnchor(), + mnSize(0), + mAllocator(x.mAllocator) + { + reset_lose_memory(); + swap(x); + } + + template + inline rbtree::rbtree(this_type&& x, const allocator_type& allocator) + : base_type(x.mCompare), + mAnchor(), + mnSize(0), + mAllocator(allocator) + { + reset_lose_memory(); + swap(x); // swap will directly or indirectly handle the possibility that mAllocator != x.mAllocator. + } + #endif + + + template + template + inline rbtree::rbtree(InputIterator first, InputIterator last, const C& compare, const allocator_type& allocator) + : base_type(compare), + mAnchor(), + mnSize(0), + mAllocator(allocator) + { + reset_lose_memory(); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + for(; first != last; ++first) + insert(*first); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + clear(); + throw; + } + #endif + } + + + template + inline rbtree::~rbtree() + { + // Erase the entire tree. DoNukeSubtree is not a + // conventional erase function, as it does no rebalancing. + DoNukeSubtree((node_type*)mAnchor.mpNodeParent); + } + + + template + inline const typename rbtree::allocator_type& + rbtree::get_allocator() const EA_NOEXCEPT + { + return mAllocator; + } + + + template + inline typename rbtree::allocator_type& + rbtree::get_allocator() EA_NOEXCEPT + { + return mAllocator; + } + + + template + inline void rbtree::set_allocator(const allocator_type& allocator) + { + mAllocator = allocator; + } + + + template + inline typename rbtree::size_type + rbtree::size() const EA_NOEXCEPT + { return mnSize; } + + + template + inline bool rbtree::empty() const EA_NOEXCEPT + { return (mnSize == 0); } + + + template + inline typename rbtree::iterator + rbtree::begin() EA_NOEXCEPT + { return iterator(static_cast(mAnchor.mpNodeLeft)); } + + + template + inline typename rbtree::const_iterator + rbtree::begin() const EA_NOEXCEPT + { return const_iterator(static_cast(const_cast(mAnchor.mpNodeLeft))); } + + + template + inline typename rbtree::const_iterator + rbtree::cbegin() const EA_NOEXCEPT + { return const_iterator(static_cast(const_cast(mAnchor.mpNodeLeft))); } + + + template + inline typename rbtree::iterator + rbtree::end() EA_NOEXCEPT + { return iterator(static_cast(&mAnchor)); } + + + template + inline typename rbtree::const_iterator + rbtree::end() const EA_NOEXCEPT + { return const_iterator(static_cast(const_cast(&mAnchor))); } + + + template + inline typename rbtree::const_iterator + rbtree::cend() const EA_NOEXCEPT + { return const_iterator(static_cast(const_cast(&mAnchor))); } + + + template + inline typename rbtree::reverse_iterator + rbtree::rbegin() EA_NOEXCEPT + { return reverse_iterator(end()); } + + + template + inline typename rbtree::const_reverse_iterator + rbtree::rbegin() const EA_NOEXCEPT + { return const_reverse_iterator(end()); } + + + template + inline typename rbtree::const_reverse_iterator + rbtree::crbegin() const EA_NOEXCEPT + { return const_reverse_iterator(end()); } + + + template + inline typename rbtree::reverse_iterator + rbtree::rend() EA_NOEXCEPT + { return reverse_iterator(begin()); } + + + template + inline typename rbtree::const_reverse_iterator + rbtree::rend() const EA_NOEXCEPT + { return const_reverse_iterator(begin()); } + + + template + inline typename rbtree::const_reverse_iterator + rbtree::crend() const EA_NOEXCEPT + { return const_reverse_iterator(begin()); } + + + template + inline typename rbtree::this_type& + rbtree::operator=(const this_type& x) + { + if(this != &x) + { + clear(); + + #if EASTL_ALLOCATOR_COPY_ENABLED + mAllocator = x.mAllocator; + #endif + + base_type::mCompare = x.mCompare; + + if(x.mAnchor.mpNodeParent) // mAnchor.mpNodeParent is the rb_tree root node. + { + mAnchor.mpNodeParent = DoCopySubtree((const node_type*)x.mAnchor.mpNodeParent, (node_type*)&mAnchor); + mAnchor.mpNodeRight = RBTreeGetMaxChild(mAnchor.mpNodeParent); + mAnchor.mpNodeLeft = RBTreeGetMinChild(mAnchor.mpNodeParent); + mnSize = x.mnSize; + } + } + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename rbtree::this_type& + rbtree::operator=(this_type&& x) + { + if(this != &x) + { + clear(); // To consider: Are we really required to clear here? x is going away soon and will clear itself in its dtor. + swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. + } + return *this; + } + #endif + + + template + inline typename rbtree::this_type& + rbtree::operator=(std::initializer_list ilist) + { + // The simplest means of doing this is to clear and insert. There probably isn't a generic + // solution that's any more efficient without having prior knowledge of the ilist contents. + clear(); + + for(typename std::initializer_list::iterator it = ilist.begin(), itEnd = ilist.end(); it != itEnd; ++it) + DoInsertValue(has_unique_keys_type(), eastl::move(*it)); + + return *this; + } + + + template + void rbtree::swap(this_type& x) + { + if(mAllocator == x.mAllocator) // If allocators are equivalent... + { + // Most of our members can be exchaged by a basic swap: + // We leave mAllocator as-is. + eastl::swap(mnSize, x.mnSize); + eastl::swap(base_type::mCompare, x.mCompare); + + // However, because our anchor node is a part of our class instance and not + // dynamically allocated, we can't do a swap of it but must do a more elaborate + // procedure. This is the downside to having the mAnchor be like this, but + // otherwise we consider it a good idea to avoid allocating memory for a + // nominal container instance. + + // We optimize for the expected most common case: both pointers being non-null. + if(mAnchor.mpNodeParent && x.mAnchor.mpNodeParent) // If both pointers are non-null... + { + eastl::swap(mAnchor.mpNodeRight, x.mAnchor.mpNodeRight); + eastl::swap(mAnchor.mpNodeLeft, x.mAnchor.mpNodeLeft); + eastl::swap(mAnchor.mpNodeParent, x.mAnchor.mpNodeParent); + + // We need to fix up the anchors to point to themselves (we can't just swap them). + mAnchor.mpNodeParent->mpNodeParent = &mAnchor; + x.mAnchor.mpNodeParent->mpNodeParent = &x.mAnchor; + } + else if(mAnchor.mpNodeParent) + { + x.mAnchor.mpNodeRight = mAnchor.mpNodeRight; + x.mAnchor.mpNodeLeft = mAnchor.mpNodeLeft; + x.mAnchor.mpNodeParent = mAnchor.mpNodeParent; + x.mAnchor.mpNodeParent->mpNodeParent = &x.mAnchor; + + // We need to fix up our anchor to point it itself (we can't have it swap with x). + mAnchor.mpNodeRight = &mAnchor; + mAnchor.mpNodeLeft = &mAnchor; + mAnchor.mpNodeParent = NULL; + } + else if(x.mAnchor.mpNodeParent) + { + mAnchor.mpNodeRight = x.mAnchor.mpNodeRight; + mAnchor.mpNodeLeft = x.mAnchor.mpNodeLeft; + mAnchor.mpNodeParent = x.mAnchor.mpNodeParent; + mAnchor.mpNodeParent->mpNodeParent = &mAnchor; + + // We need to fix up x's anchor to point it itself (we can't have it swap with us). + x.mAnchor.mpNodeRight = &x.mAnchor; + x.mAnchor.mpNodeLeft = &x.mAnchor; + x.mAnchor.mpNodeParent = NULL; + } // Else both are NULL and there is nothing to do. + } + else + { + const this_type temp(*this); // Can't call eastl::swap because that would + *this = x; // itself call this member swap function. + x = temp; + } + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + template + inline typename rbtree::insert_return_type // map/set::insert return a pair, multimap/multiset::iterator return an iterator. + rbtree::emplace(Args&&... args) + { + return DoInsertValue(has_unique_keys_type(), eastl::forward(args)...); + } + + template + template + typename rbtree::iterator + rbtree::emplace_hint(const_iterator position, Args&&... args) + { + return DoInsertValueHint(has_unique_keys_type(), position, eastl::forward(args)...); + } + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename rbtree::insert_return_type // map/set::insert return a pair, multimap/multiset::iterator return an iterator. + rbtree::emplace(value_type&& value) + { + return DoInsertValue(has_unique_keys_type(), eastl::move(value)); + } + + template + typename rbtree::iterator + rbtree::emplace_hint(const_iterator position, value_type&& value) + { + return DoInsertValueHint(has_unique_keys_type(), position, eastl::move(value)); + } + #endif + + template + inline typename rbtree::insert_return_type // map/set::insert return a pair, multimap/multiset::iterator return an iterator. + rbtree::emplace(const value_type& value) + { + return DoInsertValue(has_unique_keys_type(), value); + } + + template + typename rbtree::iterator + rbtree::emplace_hint(const_iterator position, const value_type& value) + { + return DoInsertValueHint(has_unique_keys_type(), position, value); + } + #endif + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + template + inline typename rbtree::insert_return_type // map/set::insert return a pair, multimap/multiset::iterator return an iterator. + rbtree::insert(P&& otherValue) + { + return DoInsertValue(has_unique_keys_type(), value_type(eastl::forward

(otherValue))); // Need to use forward instead of move because P&& is a "universal reference" instead of an rvalue reference. + } + + + template + inline typename rbtree::iterator + rbtree::insert(const_iterator position, value_type&& value) + { + return DoInsertValueHint(has_unique_keys_type(), position, value_type(eastl::move(value))); + } + #endif + + + template + inline typename rbtree::insert_return_type // map/set::insert return a pair, multimap/multiset::iterator return an iterator. + rbtree::insert(const value_type& value) + { return DoInsertValue(has_unique_keys_type(), value); } + + + template + typename rbtree::iterator + rbtree::insert(const_iterator position, const value_type& value) + { return DoInsertValueHint(has_unique_keys_type(), position, value); } + + + template + typename rbtree::node_type* + rbtree::DoGetKeyInsertionPositionUniqueKeys(bool& canInsert, const key_type& key) + { + // This code is essentially a slightly modified copy of the the rbtree::insert + // function whereby this version takes a key and not a full value_type. + extract_key extractKey; + + node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node. + node_type* pLowerBound = (node_type*)&mAnchor; // Set it to the container end for now. + node_type* pParent; // This will be where we insert the new node. + + bool bValueLessThanNode = true; // If the tree is empty, this will result in an insertion at the front. + + // Find insertion position of the value. This will either be a position which + // already contains the value, a position which is greater than the value or + // end(), which we treat like a position which is greater than the value. + while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree. + { + bValueLessThanNode = mCompare(key, extractKey(pCurrent->mValue)); + pLowerBound = pCurrent; + + if(bValueLessThanNode) + { + EASTL_VALIDATE_COMPARE(!mCompare(extractKey(pCurrent->mValue), key)); // Validate that the compare function is sane. + pCurrent = (node_type*)pCurrent->mpNodeLeft; + } + else + pCurrent = (node_type*)pCurrent->mpNodeRight; + } + + pParent = pLowerBound; // pLowerBound is actually upper bound right now (i.e. it is > value instead of <=), but we will make it the lower bound below. + + if(bValueLessThanNode) // If we ended up on the left side of the last parent node... + { + if(EASTL_LIKELY(pLowerBound != (node_type*)mAnchor.mpNodeLeft)) // If the tree was empty or if we otherwise need to insert at the very front of the tree... + { + // At this point, pLowerBound points to a node which is > than value. + // Move it back by one, so that it points to a node which is <= value. + pLowerBound = (node_type*)RBTreeDecrement(pLowerBound); + } + else + { + canInsert = true; + return pLowerBound; + } + } + + // Since here we require values to be unique, we will do nothing if the value already exists. + if(mCompare(extractKey(pLowerBound->mValue), key)) // If the node is < the value (i.e. if value is >= the node)... + { + EASTL_VALIDATE_COMPARE(!mCompare(key, extractKey(pLowerBound->mValue))); // Validate that the compare function is sane. + canInsert = true; + return pParent; + } + + // The item already exists (as found by the compare directly above), so return false. + canInsert = false; + return pLowerBound; + } + + + template + typename rbtree::node_type* + rbtree::DoGetKeyInsertionPositionNonuniqueKeys(const key_type& key) + { + // This is the pathway for insertion of non-unique keys (multimap and multiset, but not map and set). + node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node. + node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now. + extract_key extractKey; + + while(pCurrent) + { + pRangeEnd = pCurrent; + + if(mCompare(key, extractKey(pCurrent->mValue))) + { + EASTL_VALIDATE_COMPARE(!mCompare(extractKey(pCurrent->mValue), key)); // Validate that the compare function is sane. + pCurrent = (node_type*)pCurrent->mpNodeLeft; + } + else + pCurrent = (node_type*)pCurrent->mpNodeRight; + } + + return pRangeEnd; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + // To consider: We may want to have a specialization for DoInsertValue(true_type, value_type&&) and DoInsertValue(true_type, const value_type&), + // because we are forced into creating a temporary value below from the args, and yet it may be a wasted create because canInsert becomes false. + template + template + eastl::pair::iterator, bool> + rbtree::DoInsertValue(true_type, Args&&... args) // true_type means keys are unique. + { + // This is the pathway for insertion of unique keys (map and set, but not multimap and multiset). + // Note that we return a pair and not an iterator. This is because the C++ standard for map + // and set is to return a pair and not just an iterator. + + // We have a problem here if sizeof(value_type) is too big for the stack. We may want to consider having a specialization for large value_types. + // To do: Change this so that we call DoCreateNode(eastl::forward(args)...) here and use the value from the resulting pNode to get the + // key, and make DoInsertValueImpl take that node as an argument. That way there is no value created on the stack. Destroy the node if canInsert + // ends up being false. Potential optimization: Make a DoInsertValue(true_type, value_type&&) specialization which doesn't need to first create a node. + // + // Related problem: If canInsert ends up being false then value isn't used. If args was of type value_type then it would have been needlessly copied or moved. + // One possible fix is to specialize this function for value_type&& and const value_type&, which should take priority over the args... version and not have this problem. + + #if EASTL_USE_FORWARD_WORKAROUND + auto value = value_type(eastl::forward(args)...); // Workaround for compiler bug in VS2013 which results in a compiler internal crash while compiling this code. + #else + value_type value(eastl::forward(args)...); + #endif + extract_key extractKey; + key_type key(extractKey(value)); + bool canInsert; + node_type* pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, key); + + if(canInsert) + { + const iterator itResult(DoInsertValueImpl(pPosition, false, key, eastl::move(value))); + return pair(itResult, true); + } + + return pair(iterator(pPosition), false); + } + + + template + template + typename rbtree::iterator + rbtree::DoInsertValue(false_type, Args&&... args) // false_type means keys are not unique. + { + // We have a problem here if sizeof(value_type) is too big for the stack. We may want to consider having a specialization for large value_types. + // To do: Change this so that we call DoCreateNode(eastl::forward(args)...) here and use the value from the resulting pNode to get the + // key, and make DoInsertValueImpl take that node as an argument. That way there is no value created on the stack. + #if EASTL_USE_FORWARD_WORKAROUND + auto value = value_type(eastl::forward(args)...); // Workaround for compiler bug in VS2013 which results in a compiler internal crash while compiling this code. + #else + value_type value(eastl::forward(args)...); + #endif + extract_key extractKey; + key_type key(extractKey(value)); + node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key); + + return DoInsertValueImpl(pPosition, false, key, eastl::move(value)); + } + + + template + template + typename rbtree::iterator + rbtree::DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, Args&&... args) + { + RBTreeSide side; + extract_key extractKey; + + // The reason we may want to have bForceToLeft == true is that pNodeParent->mValue and value may be equal. + // In that case it doesn't matter what side we insert on, except that the C++ LWG #233 improvement report + // suggests that we should use the insert hint position to force an ordering. So that's what we do. + if(bForceToLeft || (pNodeParent == &mAnchor) || mCompare(key, extractKey(pNodeParent->mValue))) + side = kRBTreeSideLeft; + else + side = kRBTreeSideRight; + + node_type* const pNodeNew = DoCreateNode(eastl::forward(args)...); // Note that pNodeNew->mpLeft, mpRight, mpParent, will be uninitialized. + RBTreeInsert(pNodeNew, pNodeParent, &mAnchor, side); + mnSize++; + + return iterator(pNodeNew); + } + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + template + eastl::pair::iterator, bool> + rbtree::DoInsertValue(true_type, value_type&& value) // true_type means keys are unique. + { + extract_key extractKey; + key_type key(extractKey(value)); + bool canInsert; + node_type* pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, key); + + if(canInsert) + { + const iterator itResult(DoInsertValueImpl(pPosition, false, key, eastl::move(value))); + return pair(itResult, true); + } + + return pair(iterator(pPosition), false); + } + + + template + typename rbtree::iterator + rbtree::DoInsertValue(false_type, value_type&& value) // false_type means keys are not unique. + { + extract_key extractKey; + key_type key(extractKey(value)); + node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key); + + return DoInsertValueImpl(pPosition, false, key, eastl::move(value)); + } + + + template + typename rbtree::iterator + rbtree::DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, value_type&& value) + { + RBTreeSide side; + extract_key extractKey; + + // The reason we may want to have bForceToLeft == true is that pNodeParent->mValue and value may be equal. + // In that case it doesn't matter what side we insert on, except that the C++ LWG #233 improvement report + // suggests that we should use the insert hint position to force an ordering. So that's what we do. + if(bForceToLeft || (pNodeParent == &mAnchor) || mCompare(key, extractKey(pNodeParent->mValue))) + side = kRBTreeSideLeft; + else + side = kRBTreeSideRight; + + node_type* const pNodeNew = DoCreateNode(eastl::move(value)); // Note that pNodeNew->mpLeft, mpRight, mpParent, will be uninitialized. + RBTreeInsert(pNodeNew, pNodeParent, &mAnchor, side); + mnSize++; + + return iterator(pNodeNew); + } + #endif + + + template + eastl::pair::iterator, bool> + rbtree::DoInsertValue(true_type, const value_type& value) // true_type means keys are unique. + { + extract_key extractKey; + key_type key(extractKey(value)); + bool canInsert; + node_type* pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, extractKey(value)); + + if(canInsert) + { + const iterator itResult(DoInsertValueImpl(pPosition, false, key, value)); + return pair(itResult, true); + } + + return pair(iterator(pPosition), false); + } + + + template + typename rbtree::iterator + rbtree::DoInsertValue(false_type, const value_type& value) // false_type means keys are not unique. + { + extract_key extractKey; + key_type key(extractKey(value)); + node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key); + + return DoInsertValueImpl(pPosition, false, key, value); + } + + + template + typename rbtree::iterator + rbtree::DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, const value_type& value) + { + RBTreeSide side; + extract_key extractKey; + + // The reason we may want to have bForceToLeft == true is that pNodeParent->mValue and value may be equal. + // In that case it doesn't matter what side we insert on, except that the C++ LWG #233 improvement report + // suggests that we should use the insert hint position to force an ordering. So that's what we do. + if(bForceToLeft || (pNodeParent == &mAnchor) || mCompare(key, extractKey(pNodeParent->mValue))) + side = kRBTreeSideLeft; + else + side = kRBTreeSideRight; + + node_type* const pNodeNew = DoCreateNode(value); // Note that pNodeNew->mpLeft, mpRight, mpParent, will be uninitialized. + RBTreeInsert(pNodeNew, pNodeParent, &mAnchor, side); + mnSize++; + + return iterator(pNodeNew); + } + #endif + + + template + eastl::pair::iterator, bool> + rbtree::DoInsertKey(true_type, const key_type& key) // true_type means keys are unique. + { + // This is the pathway for insertion of unique keys (map and set, but not multimap and multiset). + // Note that we return a pair and not an iterator. This is because the C++ standard for map + // and set is to return a pair and not just an iterator. + bool canInsert; + node_type* pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, key); + + if(canInsert) + { + const iterator itResult(DoInsertKeyImpl(pPosition, false, key)); + return pair(itResult, true); + } + + return pair(iterator(pPosition), false); + } + + + template + typename rbtree::iterator + rbtree::DoInsertKey(false_type, const key_type& key) // false_type means keys are not unique. + { + node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key); + + return DoInsertKeyImpl(pPosition, false, key); + } + + + + template + typename rbtree::node_type* + rbtree::DoGetKeyInsertionPositionUniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key) + { + extract_key extractKey; + + if((position.mpNode != mAnchor.mpNodeRight) && (position.mpNode != &mAnchor)) // If the user specified a specific insertion position... + { + iterator itNext(position.mpNode); + ++itNext; + + // To consider: Change this so that 'position' specifies the position after + // where the insertion goes and not the position before where the insertion goes. + // Doing so would make this more in line with user expectations and with LWG #233. + const bool bPositionLessThanValue = mCompare(extractKey(position.mpNode->mValue), key); + + if(bPositionLessThanValue) // If (value > *position)... + { + EASTL_VALIDATE_COMPARE(!mCompare(key, extractKey(position.mpNode->mValue))); // Validate that the compare function is sane. + + const bool bValueLessThanNext = mCompare(key, extractKey(itNext.mpNode->mValue)); + + if(bValueLessThanNext) // If value < *itNext... + { + EASTL_VALIDATE_COMPARE(!mCompare(extractKey(itNext.mpNode->mValue), key)); // Validate that the compare function is sane. + + if(position.mpNode->mpNodeRight) + { + bForceToLeft = true; // Specifically insert in front of (to the left of) itNext (and thus after 'position'). + return itNext.mpNode; + } + + bForceToLeft = false; + return position.mpNode; + } + } + + bForceToLeft = false; + return NULL; // The above specified hint was not useful, then we do a regular insertion. + } + + if(mnSize && mCompare(extractKey(((node_type*)mAnchor.mpNodeRight)->mValue), key)) + { + EASTL_VALIDATE_COMPARE(!mCompare(key, extractKey(((node_type*)mAnchor.mpNodeRight)->mValue))); // Validate that the compare function is sane. + bForceToLeft = false; + return (node_type*)mAnchor.mpNodeRight; + } + + bForceToLeft = false; + return NULL; // The caller can do a default insert. + } + + + template + typename rbtree::node_type* + rbtree::DoGetKeyInsertionPositionNonuniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key) + { + extract_key extractKey; + + if((position.mpNode != mAnchor.mpNodeRight) && (position.mpNode != &mAnchor)) // If the user specified a specific insertion position... + { + iterator itNext(position.mpNode); + ++itNext; + + // To consider: Change this so that 'position' specifies the position after + // where the insertion goes and not the position before where the insertion goes. + // Doing so would make this more in line with user expectations and with LWG #233. + if(!mCompare(key, extractKey(position.mpNode->mValue)) && // If value >= *position && + !mCompare(extractKey(itNext.mpNode->mValue), key)) // if value <= *itNext... + { + if(position.mpNode->mpNodeRight) // If there are any nodes to the right... [this expression will always be true as long as we aren't at the end()] + { + bForceToLeft = true; // Specifically insert in front of (to the left of) itNext (and thus after 'position'). + return itNext.mpNode; + } + + bForceToLeft = false; + return position.mpNode; + } + + bForceToLeft = false; + return NULL; // The above specified hint was not useful, then we do a regular insertion. + } + + // This pathway shouldn't be commonly executed, as the user shouldn't be calling + // this hinted version of insert if the user isn't providing a useful hint. + if(mnSize && !mCompare(key, extractKey(((node_type*)mAnchor.mpNodeRight)->mValue))) // If we are non-empty and the value is >= the last node... + { + bForceToLeft =false; + return (node_type*)mAnchor.mpNodeRight; + } + + bForceToLeft = false; + return NULL; + } + + + template + typename rbtree::iterator + rbtree::DoInsertValueHint(true_type, const_iterator position, const value_type& value) // true_type means keys are unique. + { + // This is the pathway for insertion of unique keys (map and set, but not multimap and multiset). + // + // We follow the same approach as SGI STL/STLPort and use the position as + // a forced insertion position for the value when possible. + + extract_key extractKey; + key_type key(extractKey(value)); + bool bForceToLeft; + node_type* pPosition = DoGetKeyInsertionPositionUniqueKeysHint(position, bForceToLeft, key); + + if(pPosition) + return DoInsertValueImpl(pPosition, bForceToLeft, key, value); + else + return DoInsertValue(has_unique_keys_type(), value).first; + } + + + template + typename rbtree::iterator + rbtree::DoInsertValueHint(false_type, const_iterator position, const value_type& value) // false_type means keys are not unique. + { + // This is the pathway for insertion of non-unique keys (multimap and multiset, but not map and set). + // + // We follow the same approach as SGI STL/STLPort and use the position as + // a forced insertion position for the value when possible. + extract_key extractKey; + key_type key(extractKey(value)); + bool bForceToLeft; + node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeysHint(position, bForceToLeft, key); + + if(pPosition) + return DoInsertValueImpl(pPosition, bForceToLeft, key, value); + else + return DoInsertValue(has_unique_keys_type(), value); + } + + + template + typename rbtree::iterator + rbtree::DoInsertKey(true_type, const_iterator position, const key_type& key) // true_type means keys are unique. + { + bool bForceToLeft; + node_type* pPosition = DoGetKeyInsertionPositionUniqueKeysHint(position, bForceToLeft, key); + + if(pPosition) + return DoInsertKeyImpl(pPosition, bForceToLeft, key); + else + return DoInsertKey(has_unique_keys_type(), key).first; + } + + + template + typename rbtree::iterator + rbtree::DoInsertKey(false_type, const_iterator position, const key_type& key) // false_type means keys are not unique. + { + // This is the pathway for insertion of non-unique keys (multimap and multiset, but not map and set). + // + // We follow the same approach as SGI STL/STLPort and use the position as + // a forced insertion position for the value when possible. + bool bForceToLeft; + node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeysHint(position, bForceToLeft, key); + + if(pPosition) + return DoInsertKeyImpl(pPosition, bForceToLeft, key); + else + return DoInsertKey(has_unique_keys_type(), key); // We are empty or we are inserting at the end. + } + + + template + typename rbtree::iterator + rbtree::DoInsertKeyImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key) + { + RBTreeSide side; + extract_key extractKey; + + // The reason we may want to have bForceToLeft == true is that pNodeParent->mValue and value may be equal. + // In that case it doesn't matter what side we insert on, except that the C++ LWG #233 improvement report + // suggests that we should use the insert hint position to force an ordering. So that's what we do. + if(bForceToLeft || (pNodeParent == &mAnchor) || mCompare(key, extractKey(pNodeParent->mValue))) + side = kRBTreeSideLeft; + else + side = kRBTreeSideRight; + + node_type* const pNodeNew = DoCreateNodeFromKey(key); // Note that pNodeNew->mpLeft, mpRight, mpParent, will be uninitialized. + RBTreeInsert(pNodeNew, pNodeParent, &mAnchor, side); + mnSize++; + + return iterator(pNodeNew); + } + + + template + void rbtree::insert(std::initializer_list ilist) + { + for(typename std::initializer_list::iterator it = ilist.begin(), itEnd = ilist.end(); it != itEnd; ++it) + DoInsertValue(has_unique_keys_type(), eastl::move(*it)); + } + + + template + template + void rbtree::insert(InputIterator first, InputIterator last) + { + for( ; first != last; ++first) + DoInsertValue(has_unique_keys_type(), *first); // Or maybe we should call 'insert(end(), *first)' instead. If the first-last range was sorted then this might make some sense. + } + + + template + inline void rbtree::clear() + { + // Erase the entire tree. DoNukeSubtree is not a + // conventional erase function, as it does no rebalancing. + DoNukeSubtree((node_type*)mAnchor.mpNodeParent); + reset_lose_memory(); + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void rbtree::reset() + { + reset_lose_memory(); + } + #endif + + + template + inline void rbtree::reset_lose_memory() + { + // The reset_lose_memory function is a special extension function which unilaterally + // resets the container to an empty state without freeing the memory of + // the contained objects. This is useful for very quickly tearing down a + // container built into scratch memory. + mAnchor.mpNodeRight = &mAnchor; + mAnchor.mpNodeLeft = &mAnchor; + mAnchor.mpNodeParent = NULL; + mAnchor.mColor = kRBTreeColorRed; + mnSize = 0; + } + + + template + inline typename rbtree::iterator + rbtree::erase(const_iterator position) + { + const iterator iErase(position.mpNode); + --mnSize; // Interleave this between the two references to itNext. We expect no exceptions to occur during the code below. + ++position; + RBTreeErase(iErase.mpNode, &mAnchor); + DoFreeNode(iErase.mpNode); + return iterator(position.mpNode); + } + + + template + typename rbtree::iterator + rbtree::erase(const_iterator first, const_iterator last) + { + // We expect that if the user means to clear the container, they will call clear. + if(EASTL_LIKELY((first.mpNode != mAnchor.mpNodeLeft) || (last.mpNode != &mAnchor))) // If (first != begin or last != end) ... + { + // Basic implementation: + while(first != last) + first = erase(first); + return iterator(first.mpNode); + + // Inlined implementation: + //size_type n = 0; + //while(first != last) + //{ + // const iterator itErase(first); + // ++n; + // ++first; + // RBTreeErase(itErase.mpNode, &mAnchor); + // DoFreeNode(itErase.mpNode); + //} + //mnSize -= n; + //return first; + } + + clear(); + return iterator((node_type*)&mAnchor); // Same as: return end(); + } + + + template + inline typename rbtree::reverse_iterator + rbtree::erase(const_reverse_iterator position) + { + return reverse_iterator(erase((++position).base())); + } + + + template + typename rbtree::reverse_iterator + rbtree::erase(const_reverse_iterator first, const_reverse_iterator last) + { + // Version which erases in order from first to last. + // difference_type i(first.base() - last.base()); + // while(i--) + // first = erase(first); + // return first; + + // Version which erases in order from last to first, but is slightly more efficient: + return reverse_iterator(erase((++last).base(), (++first).base())); + } + + + template + inline void rbtree::erase(const key_type* first, const key_type* last) + { + // We have no choice but to run a loop like this, as the first/last range could + // have values that are discontiguously located in the tree. And some may not + // even be in the tree. + while(first != last) + erase(*first++); + } + + + template + typename rbtree::iterator + rbtree::find(const key_type& key) + { + // To consider: Implement this instead via calling lower_bound and + // inspecting the result. The following is an implementation of this: + // const iterator it(lower_bound(key)); + // return ((it.mpNode == &mAnchor) || mCompare(key, extractKey(it.mpNode->mValue))) ? iterator(&mAnchor) : it; + // We don't currently implement the above because in practice people tend to call + // find a lot with trees, but very uncommonly call lower_bound. + extract_key extractKey; + + node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node. + node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now. + + while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree. + { + if(EASTL_LIKELY(!mCompare(extractKey(pCurrent->mValue), key))) // If pCurrent is >= key... + { + pRangeEnd = pCurrent; + pCurrent = (node_type*)pCurrent->mpNodeLeft; + } + else + { + EASTL_VALIDATE_COMPARE(!mCompare(key, extractKey(pCurrent->mValue))); // Validate that the compare function is sane. + pCurrent = (node_type*)pCurrent->mpNodeRight; + } + } + + if(EASTL_LIKELY((pRangeEnd != &mAnchor) && !mCompare(key, extractKey(pRangeEnd->mValue)))) + return iterator(pRangeEnd); + return iterator((node_type*)&mAnchor); + } + + + template + inline typename rbtree::const_iterator + rbtree::find(const key_type& key) const + { + typedef rbtree rbtree_type; + return const_iterator(const_cast(this)->find(key)); + } + + + template + template + typename rbtree::iterator + rbtree::find_as(const U& u, Compare2 compare2) + { + extract_key extractKey; + + node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node. + node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now. + + while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree. + { + if(EASTL_LIKELY(!compare2(extractKey(pCurrent->mValue), u))) // If pCurrent is >= u... + { + pRangeEnd = pCurrent; + pCurrent = (node_type*)pCurrent->mpNodeLeft; + } + else + { + EASTL_VALIDATE_COMPARE(!compare2(u, extractKey(pCurrent->mValue))); // Validate that the compare function is sane. + pCurrent = (node_type*)pCurrent->mpNodeRight; + } + } + + if(EASTL_LIKELY((pRangeEnd != &mAnchor) && !compare2(u, extractKey(pRangeEnd->mValue)))) + return iterator(pRangeEnd); + return iterator((node_type*)&mAnchor); + } + + + template + template + inline typename rbtree::const_iterator + rbtree::find_as(const U& u, Compare2 compare2) const + { + typedef rbtree rbtree_type; + return const_iterator(const_cast(this)->find_as(u, compare2)); + } + + + template + typename rbtree::iterator + rbtree::lower_bound(const key_type& key) + { + extract_key extractKey; + + node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node. + node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now. + + while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree. + { + if(EASTL_LIKELY(!mCompare(extractKey(pCurrent->mValue), key))) // If pCurrent is >= key... + { + pRangeEnd = pCurrent; + pCurrent = (node_type*)pCurrent->mpNodeLeft; + } + else + { + EASTL_VALIDATE_COMPARE(!mCompare(key, extractKey(pCurrent->mValue))); // Validate that the compare function is sane. + pCurrent = (node_type*)pCurrent->mpNodeRight; + } + } + + return iterator(pRangeEnd); + } + + + template + inline typename rbtree::const_iterator + rbtree::lower_bound(const key_type& key) const + { + typedef rbtree rbtree_type; + return const_iterator(const_cast(this)->lower_bound(key)); + } + + + template + typename rbtree::iterator + rbtree::upper_bound(const key_type& key) + { + extract_key extractKey; + + node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node. + node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now. + + while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree. + { + if(EASTL_LIKELY(mCompare(key, extractKey(pCurrent->mValue)))) // If key is < pCurrent... + { + EASTL_VALIDATE_COMPARE(!mCompare(extractKey(pCurrent->mValue), key)); // Validate that the compare function is sane. + pRangeEnd = pCurrent; + pCurrent = (node_type*)pCurrent->mpNodeLeft; + } + else + pCurrent = (node_type*)pCurrent->mpNodeRight; + } + + return iterator(pRangeEnd); + } + + + template + inline typename rbtree::const_iterator + rbtree::upper_bound(const key_type& key) const + { + typedef rbtree rbtree_type; + return const_iterator(const_cast(this)->upper_bound(key)); + } + + + // To do: Move this validate function entirely to a template-less implementation. + template + bool rbtree::validate() const + { + // Red-black trees have the following canonical properties which we validate here: + // 1 Every node is either red or black. + // 2 Every leaf (NULL) is black by defintion. Any number of black nodes may appear in a sequence. + // 3 If a node is red, then both its children are black. Thus, on any path from + // the root to a leaf, red nodes must not be adjacent. + // 4 Every simple path from a node to a descendant leaf contains the same number of black nodes. + // 5 The mnSize member of the tree must equal the number of nodes in the tree. + // 6 The tree is sorted as per a conventional binary tree. + // 7 The comparison function is sane; it obeys strict weak ordering. If mCompare(a,b) is true, then mCompare(b,a) must be false. Both cannot be true. + + extract_key extractKey; + + if(mnSize) + { + // Verify basic integrity. + //if(!mAnchor.mpNodeParent || (mAnchor.mpNodeLeft == mAnchor.mpNodeRight)) + // return false; // Fix this for case of empty tree. + + if(mAnchor.mpNodeLeft != RBTreeGetMinChild(mAnchor.mpNodeParent)) + return false; + + if(mAnchor.mpNodeRight != RBTreeGetMaxChild(mAnchor.mpNodeParent)) + return false; + + const size_t nBlackCount = RBTreeGetBlackCount(mAnchor.mpNodeParent, mAnchor.mpNodeLeft); + size_type nIteratedSize = 0; + + for(const_iterator it = begin(); it != end(); ++it, ++nIteratedSize) + { + const node_type* const pNode = (const node_type*)it.mpNode; + const node_type* const pNodeRight = (const node_type*)pNode->mpNodeRight; + const node_type* const pNodeLeft = (const node_type*)pNode->mpNodeLeft; + + // Verify #7 above. + if(pNodeRight && mCompare(extractKey(pNodeRight->mValue), extractKey(pNode->mValue)) && mCompare(extractKey(pNode->mValue), extractKey(pNodeRight->mValue))) // Validate that the compare function is sane. + return false; + + // Verify #7 above. + if(pNodeLeft && mCompare(extractKey(pNodeLeft->mValue), extractKey(pNode->mValue)) && mCompare(extractKey(pNode->mValue), extractKey(pNodeLeft->mValue))) // Validate that the compare function is sane. + return false; + + // Verify item #1 above. + if((pNode->mColor != kRBTreeColorRed) && (pNode->mColor != kRBTreeColorBlack)) + return false; + + // Verify item #3 above. + if(pNode->mColor == kRBTreeColorRed) + { + if((pNodeRight && (pNodeRight->mColor == kRBTreeColorRed)) || + (pNodeLeft && (pNodeLeft->mColor == kRBTreeColorRed))) + return false; + } + + // Verify item #6 above. + if(pNodeRight && mCompare(extractKey(pNodeRight->mValue), extractKey(pNode->mValue))) + return false; + + if(pNodeLeft && mCompare(extractKey(pNode->mValue), extractKey(pNodeLeft->mValue))) + return false; + + if(!pNodeRight && !pNodeLeft) // If we are at a bottom node of the tree... + { + // Verify item #4 above. + if(RBTreeGetBlackCount(mAnchor.mpNodeParent, pNode) != nBlackCount) + return false; + } + } + + // Verify item #5 above. + if(nIteratedSize != mnSize) + return false; + + return true; + } + else + { + if((mAnchor.mpNodeLeft != &mAnchor) || (mAnchor.mpNodeRight != &mAnchor)) + return false; + } + + return true; + } + + + template + inline int rbtree::validate_iterator(const_iterator i) const + { + // To do: Come up with a more efficient mechanism of doing this. + + for(const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp) + { + if(temp == i) + return (isf_valid | isf_current | isf_can_dereference); + } + + if(i == end()) + return (isf_valid | isf_current); + + return isf_none; + } + + + template + inline typename rbtree::node_type* + rbtree::DoAllocateNode() + { + auto* pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(value_type), 0); + EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined."); + + return pNode; + } + + + template + inline void rbtree::DoFreeNode(node_type* pNode) + { + pNode->~node_type(); + EASTLFree(mAllocator, pNode, sizeof(node_type)); + } + + + template + typename rbtree::node_type* + rbtree::DoCreateNodeFromKey(const key_type& key) + { + // Note that this function intentionally leaves the node pointers uninitialized. + // The caller would otherwise just turn right around and modify them, so there's + // no point in us initializing them to anything (except in a debug build). + node_type* const pNode = DoAllocateNode(); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + ::new((void*)&pNode->mValue) value_type(key); + + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeNode(pNode); + throw; + } + #endif + + #if EASTL_DEBUG + pNode->mpNodeRight = NULL; + pNode->mpNodeLeft = NULL; + pNode->mpNodeParent = NULL; + pNode->mColor = kRBTreeColorBlack; + #endif + + return pNode; + } + + + template + typename rbtree::node_type* + rbtree::DoCreateNode(const value_type& value) + { + // Note that this function intentionally leaves the node pointers uninitialized. + // The caller would otherwise just turn right around and modify them, so there's + // no point in us initializing them to anything (except in a debug build). + node_type* const pNode = DoAllocateNode(); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + ::new((void*)&pNode->mValue) value_type(value); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeNode(pNode); + throw; + } + #endif + + #if EASTL_DEBUG + pNode->mpNodeRight = NULL; + pNode->mpNodeLeft = NULL; + pNode->mpNodeParent = NULL; + pNode->mColor = kRBTreeColorBlack; + #endif + + return pNode; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + typename rbtree::node_type* + rbtree::DoCreateNode(value_type&& value) + { + // Note that this function intentionally leaves the node pointers uninitialized. + // The caller would otherwise just turn right around and modify them, so there's + // no point in us initializing them to anything (except in a debug build). + node_type* const pNode = DoAllocateNode(); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + ::new((void*)&pNode->mValue) value_type(eastl::move(value)); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoFreeNode(pNode); + throw; + } + #endif + + #if EASTL_DEBUG + pNode->mpNodeRight = NULL; + pNode->mpNodeLeft = NULL; + pNode->mpNodeParent = NULL; + pNode->mColor = kRBTreeColorBlack; + #endif + + return pNode; + } + #endif + + + template + typename rbtree::node_type* + rbtree::DoCreateNode(const node_type* pNodeSource, node_type* pNodeParent) + { + node_type* const pNode = DoCreateNode(pNodeSource->mValue); + + pNode->mpNodeRight = NULL; + pNode->mpNodeLeft = NULL; + pNode->mpNodeParent = pNodeParent; + pNode->mColor = pNodeSource->mColor; + + return pNode; + } + + + template + typename rbtree::node_type* + rbtree::DoCopySubtree(const node_type* pNodeSource, node_type* pNodeDest) + { + node_type* const pNewNodeRoot = DoCreateNode(pNodeSource, pNodeDest); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + #endif + // Copy the right side of the tree recursively. + if(pNodeSource->mpNodeRight) + pNewNodeRoot->mpNodeRight = DoCopySubtree((const node_type*)pNodeSource->mpNodeRight, pNewNodeRoot); + + node_type* pNewNodeLeft; + + for(pNodeSource = (node_type*)pNodeSource->mpNodeLeft, pNodeDest = pNewNodeRoot; + pNodeSource; + pNodeSource = (node_type*)pNodeSource->mpNodeLeft, pNodeDest = pNewNodeLeft) + { + pNewNodeLeft = DoCreateNode(pNodeSource, pNodeDest); + + pNodeDest->mpNodeLeft = pNewNodeLeft; + + // Copy the right side of the tree recursively. + if(pNodeSource->mpNodeRight) + pNewNodeLeft->mpNodeRight = DoCopySubtree((const node_type*)pNodeSource->mpNodeRight, pNewNodeLeft); + } + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + DoNukeSubtree(pNewNodeRoot); + throw; + } + #endif + + return pNewNodeRoot; + } + + + template + void rbtree::DoNukeSubtree(node_type* pNode) + { + while(pNode) // Recursively traverse the tree and destroy items as we go. + { + DoNukeSubtree((node_type*)pNode->mpNodeRight); + + node_type* const pNodeLeft = (node_type*)pNode->mpNodeLeft; + DoFreeNode(pNode); + pNode = pNodeLeft; + } + } + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + inline bool operator==(const rbtree& a, const rbtree& b) + { + return (a.size() == b.size()) && eastl::equal(a.begin(), a.end(), b.begin()); + } + + + // Note that in operator< we do comparisons based on the tree value_type with operator<() of the + // value_type instead of the tree's Compare function. For set/multiset, the value_type is T, while + // for map/multimap the value_type is a pair. operator< for pair can be seen by looking + // utility.h, but it basically is uses the operator< for pair.first and pair.second. The C++ standard + // appears to require this behaviour, whether intentionally or not. If anything, a good reason to do + // this is for consistency. A map and a vector that contain the same items should compare the same. + template + inline bool operator<(const rbtree& a, const rbtree& b) + { + return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); + } + + + template + inline bool operator!=(const rbtree& a, const rbtree& b) + { + return !(a == b); + } + + + template + inline bool operator>(const rbtree& a, const rbtree& b) + { + return b < a; + } + + + template + inline bool operator<=(const rbtree& a, const rbtree& b) + { + return !(b < a); + } + + + template + inline bool operator>=(const rbtree& a, const rbtree& b) + { + return !(a < b); + } + + + template + inline void swap(rbtree& a, rbtree& b) + { + a.swap(b); + } + + +} // namespace eastl + + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + + +#endif // Header include guard + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/smart_ptr.h b/libs/eastl/include/EASTL/internal/smart_ptr.h new file mode 100644 index 0000000..d730349 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/smart_ptr.h @@ -0,0 +1,279 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_SMART_PTR_H +#define EASTL_INTERNAL_SMART_PTR_H + + +#include +#include +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + + +namespace eastl +{ + + namespace Internal + { + // Tells if the Deleter type has a typedef for pointer to T. If so then return it, + // else return T*. The large majority of the time the pointer type will be T*. + // The C++11 Standard requires that scoped_ptr let the deleter define the pointer type. + // + // Example usage: + // typedef typename unique_pointer_type::type pointer + // + #if defined(EA_COMPILER_NO_DECLTYPE) + // To consider: find a way to achieve this with compilers that don't + // support decltype? It's not likely to be needed by many or any users. + template + class unique_pointer_type + { + public: + typedef T* type; + }; + #else + template + class unique_pointer_type + { + template + static typename U::pointer test(typename U::pointer*); + + template + static T* test(...); + + public: + typedef decltype(test::type>(0)) type; + }; + #endif + + + /////////////////////////////////////////////////////////////////////// + // is_array_cv_convertible + // + // Tells if the array pointer P1 is cv-convertible to array pointer P2. + // The two types have two be equivalent pointer types and be convertible + // when you consider const/volatile properties of them. + // + // Example usage: + // is_array_cv_convertible::value => false + // is_array_cv_convertible::value => false + // is_array_cv_convertible::value => false + // is_array_cv_convertible::value => false + // is_array_cv_convertible::value => false + // is_array_cv_convertible::value => true + // is_array_cv_convertible::value => true + // is_array_cv_convertible::value => true + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_array_cv_convertible_CONFORMANCE 1 + + template ::element_type>::type, + typename eastl::remove_cv::element_type>::type>::value> + struct is_array_cv_convertible_impl + : public eastl::is_convertible {}; // Return true if P1 is convertible to P2. + + template + struct is_array_cv_convertible_impl + : public eastl::false_type {}; // P1's underlying type is not the same as P2's, so it can't be converted, even if P2 refers to a subclass of P1. Parent == Child, but Parent[] != Child[] + + template ::value && !eastl::is_pointer::value> + struct is_array_cv_convertible + : public is_array_cv_convertible_impl {}; + + template + struct is_array_cv_convertible + : public eastl::false_type {}; // P1 is scalar not a pointer, so it can't be converted to a pointer. + + + /////////////////////////////////////////////////////////////////////// + // is_derived + // + // Given two (possibly identical) types Base and Derived, is_base_of::value == true + // if and only if Base is a direct or indirect base class of Derived. This is like is_base_of + // but returns false if Derived is the same as Base. So is_derived is true only if Derived is actually a subclass + // of Base and not Base itself. + // + // is_derived may only be applied to complete types. + // + // Example usage: + // is_derived::value => false + // is_derived::value => false + // is_derived::value => true + // is_derived::value => false + /////////////////////////////////////////////////////////////////////// + + #if EASTL_TYPE_TRAIT_is_base_of_CONFORMANCE + #define EASTL_TYPE_TRAIT_is_derived_CONFORMANCE 1 + + template + struct is_derived : public eastl::integral_constant::value && !eastl::is_same::type, typename eastl::remove_cv::type>::value> {}; + #else + #define EASTL_TYPE_TRAIT_is_derived_CONFORMANCE 0 + + template // This returns true if Derived is unrelated to Base. That's a wrong answer, but is better for us than returning false for compilers that don't support is_base_of. + struct is_derived : public eastl::integral_constant::type, typename eastl::remove_cv::type>::value> {}; + #endif + + + /////////////////////////////////////////////////////////////////////// + // is_safe_array_conversion + // + // Say you have two array types: T* t and U* u. You want to assign the u to t but only if + // that's a safe thing to do. As shown in the logic below, the array conversion + // is safe if U* and T* are convertible, if U is an array, and if either U or T is not + // a pointer or U is not derived from T. + // + // Note: Usage of this class could be replaced with is_array_cv_convertible usage. + // To do: Do this replacement and test it. + // + /////////////////////////////////////////////////////////////////////// + + template + struct is_safe_array_conversion : public eastl::integral_constant::value && + eastl::is_array::value && + (!eastl::is_pointer::value || !is_pointer::value || !Internal::is_derived::type>::value)> {}; + + } // namespace Internal + + + + + + + + /// default_delete + /// + /// C++11 smart pointer default delete function class. + /// + /// Provides a default way to delete an object. This default is simply to call delete on the + /// object pointer. You can provide an alternative to this class or you can override this on + /// a class-by-class basis like the following: + /// template <> + /// struct smart_ptr_deleter + /// { + /// void operator()(MyClass* p) const + /// { SomeCustomFunction(p); } + /// }; + /// + template + struct default_delete + { + #if defined(EA_COMPILER_NO_DEFAULTED_FUNCTIONS) + EA_CONSTEXPR default_delete() EA_NOEXCEPT {} + #elif defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION <= 4006) // GCC prior to 4.7 has a bug with noexcept here. + EA_CONSTEXPR default_delete() = default; + #else + EA_CONSTEXPR default_delete() EA_NOEXCEPT = default; + #endif + + template // Enable if T* can be constructed with U* (i.e. U* is convertible to T*). + default_delete(const default_delete&, typename eastl::enable_if::value>::type* = 0) EA_NOEXCEPT {} + + void operator()(T* p) const EA_NOEXCEPT + { delete p; } + }; + + + template + struct default_delete // Specialization for arrays. + { + #if defined(EA_COMPILER_NO_DEFAULTED_FUNCTIONS) + EA_CONSTEXPR default_delete() EA_NOEXCEPT {} + #elif defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION <= 4006) // GCC prior to 4.7 has a bug with noexcept here. + EA_CONSTEXPR default_delete() = default; + #else + EA_CONSTEXPR default_delete() EA_NOEXCEPT = default; + #endif + + template // This ctor is enabled if T is equal to or a base of U, and if U is less or equal const/volatile-qualified than T. + default_delete(const default_delete&, typename eastl::enable_if::value>::type* = 0) EA_NOEXCEPT {} + + void operator()(T* p) const EA_NOEXCEPT + { delete[] p; } + }; + + + + + /// smart_ptr_deleter + /// + /// Deprecated in favor of the C++11 name: default_delete + /// + template + struct smart_ptr_deleter + { + typedef T value_type; + + void operator()(const value_type* p) const // We use a const argument type in order to be most flexible with what types we accept. + { delete const_cast(p); } + }; + + template <> + struct smart_ptr_deleter + { + typedef void value_type; + + void operator()(const void* p) const + { delete[] (char*)p; } // We don't seem to have much choice but to cast to a scalar type. + }; + + template <> + struct smart_ptr_deleter + { + typedef void value_type; + + void operator()(const void* p) const + { delete[] (char*)p; } // We don't seem to have much choice but to cast to a scalar type. + }; + + + + /// smart_array_deleter + /// + /// Deprecated in favor of the C++11 name: default_delete + /// + template + struct smart_array_deleter + { + typedef T value_type; + + void operator()(const value_type* p) const // We use a const argument type in order to be most flexible with what types we accept. + { delete[] const_cast(p); } + }; + + template <> + struct smart_array_deleter + { + typedef void value_type; + + void operator()(const void* p) const + { delete[] (char*)p; } // We don't seem to have much choice but to cast to a scalar type. + }; + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/thread_support.h b/libs/eastl/include/EASTL/internal/thread_support.h new file mode 100644 index 0000000..84c0538 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/thread_support.h @@ -0,0 +1,256 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_THREAD_SUPPORT_H +#define EASTL_INTERNAL_THREAD_SUPPORT_H + + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif +#include + +#if defined(EA_HAVE_CPP11_MUTEX) && !defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_UNIX) // We stick with platform-specific mutex support to the extent possible, as it's currently more reliably available. + #define EASTL_CPP11_MUTEX_ENABLED 1 +#else + #define EASTL_CPP11_MUTEX_ENABLED 0 +#endif + +#if EASTL_CPP11_MUTEX_ENABLED + #include +#endif + +#if defined(EA_PLATFORM_MICROSOFT) + // Cannot include Windows headers in our headers, as they kill builds with their #defines. +#elif defined(EA_PLATFORM_POSIX) + #include +#endif + + +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4625) // copy constructor could not be generated because a base class copy constructor is inaccessible or deleted. + #pragma warning(disable: 4626) // assignment operator could not be generated because a base class assignment operator is inaccessible or deleted. + #pragma warning(disable: 4275) // non dll-interface class used as base for DLL-interface classkey 'identifier'. +#endif + + +#if defined(EA_PLATFORM_MICROSOFT) + #if defined(EA_PROCESSOR_POWERPC) + extern "C" long __stdcall _InterlockedIncrement(long volatile* Addend); + #pragma intrinsic (_InterlockedIncrement) + + extern "C" long __stdcall _InterlockedDecrement(long volatile* Addend); + #pragma intrinsic (_InterlockedDecrement) + + extern "C" long __stdcall _InterlockedCompareExchange(long volatile* Dest, long Exchange, long Comp); + #pragma intrinsic (_InterlockedCompareExchange) + #else + extern "C" long _InterlockedIncrement(long volatile* Addend); + #pragma intrinsic (_InterlockedIncrement) + + extern "C" long _InterlockedDecrement(long volatile* Addend); + #pragma intrinsic (_InterlockedDecrement) + + extern "C" long _InterlockedCompareExchange(long volatile* Dest, long Exchange, long Comp); + #pragma intrinsic (_InterlockedCompareExchange) + #endif +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// EASTL_THREAD_SUPPORT_AVAILABLE +// +// Defined as 0 or 1, based on existing support. +// Identifies if thread support (e.g. atomics, mutexes) is available for use. +// The large majority of EASTL doesn't use thread support, but a few parts +// of it (e.g. shared_ptr) do. +/////////////////////////////////////////////////////////////////////////////// + +#if !defined(EASTL_THREAD_SUPPORT_AVAILABLE) + #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) + #define EASTL_THREAD_SUPPORT_AVAILABLE 1 + #elif defined(EA_COMPILER_MSVC) + #define EASTL_THREAD_SUPPORT_AVAILABLE 1 + #else + #define EASTL_THREAD_SUPPORT_AVAILABLE 0 + #endif +#endif + + +namespace eastl +{ + namespace Internal + { + /// atomic_increment + /// Returns the new value. + inline int32_t atomic_increment(int32_t* p32) EA_NOEXCEPT + { + #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) + return __sync_add_and_fetch(p32, 1); + #elif defined(EA_COMPILER_MSVC) + static_assert(sizeof(long) == sizeof(int32_t), "unexpected size"); + return _InterlockedIncrement((volatile long*)p32); + #elif defined(EA_COMPILER_GNUC) + int32_t result; + __asm__ __volatile__ ("lock; xaddl %0, %1" + : "=r" (result), "=m" (*p32) + : "0" (1), "m" (*p32) + : "memory" + ); + return result + 1; + #else + EASTL_FAIL_MSG("EASTL thread safety is not implemented yet. See EAThread for how to do this for the given platform."); + return ++*p32; + #endif + } + + /// atomic_decrement + /// Returns the new value. + inline int32_t atomic_decrement(int32_t* p32) EA_NOEXCEPT + { + #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) + return __sync_add_and_fetch(p32, -1); + #elif defined(EA_COMPILER_MSVC) + return _InterlockedDecrement((volatile long*)p32); // volatile long cast is OK because int32_t == long on Microsoft platforms. + #elif defined(EA_COMPILER_GNUC) + int32_t result; + __asm__ __volatile__ ("lock; xaddl %0, %1" + : "=r" (result), "=m" (*p32) + : "0" (-1), "m" (*p32) + : "memory" + ); + return result - 1; + #else + EASTL_FAIL_MSG("EASTL thread safety is not implemented yet. See EAThread for how to do this for the given platform."); + return --*p32; + #endif + } + + + /// atomic_compare_and_swap + /// Safely sets the value to a new value if the original value is equal to + /// a condition value. Returns true if the condition was met and the + /// assignment occurred. The comparison and value setting are done as + /// an atomic operation and thus another thread cannot intervene between + /// the two as would be the case with simple C code. + inline bool atomic_compare_and_swap(int32_t* p32, int32_t newValue, int32_t condition) + { + #if defined(EA_COMPILER_CLANG) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)) + return __sync_bool_compare_and_swap(p32, condition, newValue); + #elif defined(EA_COMPILER_MSVC) + return ((int32_t)_InterlockedCompareExchange((volatile long*)p32, (long)newValue, (long)condition) == condition); + #elif defined(EA_COMPILER_GNUC) + // GCC Inline ASM Constraints + // r <--> Any general purpose register + // a <--> The a register. + // 1 <--> The constraint '1' for operand 2 says that it must occupy the same location as operand 1. + // =a <--> output registers + // =r <--> output registers + + int32_t result; + __asm__ __volatile__( + "lock; cmpxchgl %3, (%1) \n" // Test *p32 against EAX, if same, then *p32 = newValue + : "=a" (result), "=r" (p32) // outputs + : "a" (condition), "r" (newValue), "1" (p32) // inputs + : "memory" // clobbered + ); + return result == condition; + #else + EASTL_FAIL_MSG("EASTL thread safety is not implemented yet. See EAThread for how to do this for the given platform."); + if(*p32 == condition) + { + *p32 = newValue; + return true; + } + return false; + #endif + } + + + // mutex + #if EASTL_CPP11_MUTEX_ENABLED + using std::mutex; + #else + class EASTL_API mutex + { + public: + mutex(); + ~mutex(); + + void lock(); + void unlock(); + + protected: + #if defined(EA_PLATFORM_MICROSOFT) + #if defined(_WIN64) + uint64_t mMutexBuffer[40 / sizeof(uint64_t)]; // CRITICAL_SECTION is 40 bytes on Win64. + #elif defined(_WIN32) + uint32_t mMutexBuffer[24 / sizeof(uint32_t)]; // CRITICAL_SECTION is 24 bytes on Win32. + #endif + #elif defined(EA_PLATFORM_POSIX) + pthread_mutex_t mMutex; + #endif + }; + #endif + + + // auto_mutex + class EASTL_API auto_mutex + { + public: + EA_FORCE_INLINE auto_mutex(mutex& mutex) : pMutex(&mutex) + { pMutex->lock(); } + + EA_FORCE_INLINE ~auto_mutex() + { pMutex->unlock(); } + + protected: + mutex* pMutex; + + #if defined(EA_COMPILER_NO_DELETED_FUNCTIONS) + auto_mutex(const auto_mutex&) : pMutex(NULL) {} + void operator=(const auto_mutex&) {} + #else + auto_mutex(const auto_mutex&) = delete; + void operator=(const auto_mutex&) = delete; + #endif + }; + + + // shared_ptr_auto_mutex + class EASTL_API shared_ptr_auto_mutex : public auto_mutex + { + public: + shared_ptr_auto_mutex(const void* pSharedPtr); + + #if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) + shared_ptr_auto_mutex(const shared_ptr_auto_mutex&) = delete; + void operator=(shared_ptr_auto_mutex&&) = delete; + #endif + }; + + + } // namespace Internal + +} // namespace eastl + + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + + +#endif // Header include guard + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/tuple_fwd_decls.h b/libs/eastl/include/EASTL/internal/tuple_fwd_decls.h new file mode 100644 index 0000000..5b53557 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/tuple_fwd_decls.h @@ -0,0 +1,30 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_TUPLE_FWD_DECLS_H +#define EASTL_TUPLE_FWD_DECLS_H + +#include + +#if EASTL_TUPLE_ENABLED + +namespace eastl +{ + +template +class tuple; + +template +class tuple_size; + +template +class tuple_element; + +template +using tuple_element_t = typename tuple_element::type; +} + +#endif // EASTL_VARIADIC_TEMPLATES_ENABLED + +#endif // EASTL_TUPLE_FWD_DECLS_H diff --git a/libs/eastl/include/EASTL/internal/type_compound.h b/libs/eastl/include/EASTL/internal/type_compound.h new file mode 100644 index 0000000..bf8b346 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/type_compound.h @@ -0,0 +1,626 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_TYPE_COMPOUND_H +#define EASTL_INTERNAL_TYPE_COMPOUND_H + + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + + +// Until we revise the code below to handle EDG warnings, we don't have much choice but to disable them. +#if defined(__EDG_VERSION__) + #pragma diag_suppress=1931 // operand of sizeof is not a type, variable, or dereferenced pointer expression +#endif + + +namespace eastl +{ + + /////////////////////////////////////////////////////////////////////// + // is_array + // + // is_array::value == true if and only if T is an array type, + // including unbounded array types. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_array_CONFORMANCE 1 // is_array is conforming; doesn't make mistakes. + + template + struct is_array : public eastl::false_type {}; + + template + struct is_array : public eastl::true_type {}; + + template + struct is_array : public eastl::true_type {}; + + + /////////////////////////////////////////////////////////////////////// + // is_array_of_known_bounds + // + // Not part of the C++11 Standard. + // is_array_of_known_bounds::value is true if T is an array and is + // of known bounds. is_array_of_unknown_bounds::value == true, + // while is_array_of_unknown_bounds::value = false. + // + /////////////////////////////////////////////////////////////////////// + + template + struct is_array_of_known_bounds + : public eastl::integral_constant::value != 0> {}; + + + /////////////////////////////////////////////////////////////////////// + // is_array_of_unknown_bounds + // + // Not part of the C++11 Standard. + // is_array_of_unknown_bounds::value is true if T is an array but is + // of unknown bounds. is_array_of_unknown_bounds::value == false, + // while is_array_of_unknown_bounds::value = true. + // + /////////////////////////////////////////////////////////////////////// + + template + struct is_array_of_unknown_bounds + : public eastl::integral_constant::value && (eastl::extent::value == 0)> {}; + + + /////////////////////////////////////////////////////////////////////// + // is_member_function_pointer + // + // is_member_function_pointer::value == true if and only if T is a + // pointer to member function type. + // + /////////////////////////////////////////////////////////////////////// + // We detect member functions with 0 to N arguments. We can extend this + // for additional arguments if necessary. + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_member_function_pointer_CONFORMANCE 1 // is_member_function_pointer is conforming; doesn't make mistakes. + + // To do: Revise this to support C++11 variadic templates when possible. + // To do: We can probably also use remove_cv to simply the multitude of types below. + + template struct is_mem_fun_pointer_value : public false_type{}; + + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + template struct is_mem_fun_pointer_value : public true_type{}; + + template + struct is_member_function_pointer : public integral_constant::value>{}; + + + /////////////////////////////////////////////////////////////////////// + // is_member_pointer + // + // is_member_pointer::value == true if and only if: + // is_member_object_pointer::value == true, or + // is_member_function_pointer::value == true + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_member_pointer_CONFORMANCE 1 // is_member_pointer is conforming; doesn't make mistakes. + + template + struct is_member_pointer + : public eastl::integral_constant::value>{}; + + template + struct is_member_pointer + : public eastl::true_type{}; + + + + /////////////////////////////////////////////////////////////////////// + // is_member_object_pointer + // + // is_member_object_pointer::value == true if and only if T is a + // pointer to data member type. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_member_object_pointer_CONFORMANCE 1 // is_member_object_pointer is conforming; doesn't make mistakes. + + template + struct is_member_object_pointer : public eastl::integral_constant::value && + !eastl::is_member_function_pointer::value + > {}; + + + /////////////////////////////////////////////////////////////////////// + // is_pointer + // + // is_pointer::value == true if and only if T is a pointer type. + // This category includes function pointer types, but not pointer to + // member types. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_pointer_CONFORMANCE 1 // is_pointer is conforming; doesn't make mistakes. + + template struct is_pointer_helper : public false_type{}; + + template struct is_pointer_helper : public true_type{}; + template struct is_pointer_helper : public true_type{}; + template struct is_pointer_helper : public true_type{}; + template struct is_pointer_helper : public true_type{}; + + template + struct is_pointer_value : public type_and::value, type_not::value>::value> {}; + + template + struct is_pointer : public integral_constant::value>{}; + + + + /////////////////////////////////////////////////////////////////////// + // is_convertible + // + // Given two (possible identical) types From and To, is_convertible::value == true + // if and only if an lvalue of type From can be implicitly converted to type To, + // or is_void::value == true + // + // An instance of the type predicate holds true if the expression To to = from;, where from is an object of type From, is well-formed. + // + // is_convertible may only be applied to complete types. + // Type To may not be an abstract type. + // If the conversion is ambiguous, the program is ill-formed. + // If either or both of From and To are class types, and the conversion would invoke + // non-public member functions of either From or To (such as a private constructor of To, + // or a private conversion operator of From), the program is ill-formed. + // + // Note that without compiler help, both is_convertible and is_base + // can produce compiler errors if the conversion is ambiguous. + // Example: + // struct A {}; + // struct B : A {}; + // struct C : A {}; + // struct D : B, C {}; + // is_convertible::value; // Generates compiler error. + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_convertible_to))) + #define EASTL_TYPE_TRAIT_is_convertible_CONFORMANCE 1 // is_convertible is conforming. + + // Problem: VC++ reports that int is convertible to short, yet if you construct a short from an int then VC++ generates a warning: + // warning C4242: 'initializing' : conversion from 'int' to 'short', possible loss of data. We can deal with this by making + // is_convertible be false for conversions that could result in loss of data. Or we could make another trait called is_lossless_convertible + // and use that appropriately in our code. Or we could put the onus on the user to work around such warnings. + template + struct is_convertible : public integral_constant{}; + + #elif defined(__GNUC__) && (__GNUC__ <= 2) + #define EASTL_TYPE_TRAIT_is_convertible_CONFORMANCE 0 + + template + struct is_convertible : public false_type{}; + + #elif defined(EA_COMPILER_NO_DECLTYPE) + #define EASTL_TYPE_TRAIT_is_convertible_CONFORMANCE 0 + + // This causes compile failures for some cases and we need to revise it, though the C++11 pathways here are really the future anyway. + // Some variations of EDG generate a warning about the usage below: Test(...) - aggregate type passed through ellipsis (it's not portable to pass a non-POD as ellipsis). + template + struct is_convertible_helper { + static yes_type Test(To); // May need to use __cdecl under VC++. + static no_type Test(...); // May need to use __cdecl under VC++. + static From from; + typedef integral_constant result; + }; + + // void is not convertible to non-void + template + struct is_convertible_helper { typedef false_type result; }; + + // Anything is convertible to void + template + struct is_convertible_helper { typedef true_type result; }; + + template + struct is_convertible : public is_convertible_helper::value, is_void::value>::result {}; + + #else + #define EASTL_TYPE_TRAIT_is_convertible_CONFORMANCE 1 + + template::value || eastl::is_function::value || eastl::is_array::value > + struct is_convertible_helper // Anything is convertible to void. Nothing is convertible to a function or an array. + { static const bool value = eastl::is_void::value; }; + + template + class is_convertible_helper + { + template + static void ToFunction(To1); // We try to call this function with an instance of From. It is valid if From can be converted to To. + + template + static eastl::no_type is(...); + + template + static decltype(ToFunction(eastl::declval()), eastl::yes_type()) is(int); + + public: + static const bool value = sizeof(is(0)) == 1; + }; + + template + struct is_convertible + : public integral_constant::value> {}; + + #endif + + + /////////////////////////////////////////////////////////////////////// + // is_explicitly_convertible + // + // This sometime-seen extension trait is the same as is_constructible + // and so we don't define it. + // + // template + // struct is_explicitly_convertible + // : public is_constructible {}; + /////////////////////////////////////////////////////////////////////// + + + + /////////////////////////////////////////////////////////////////////// + // is_union + // + // is_union::value == true if and only if T is a union type. + // + // There is no way to tell if a type is a union without compiler help. + // As of this writing, only Metrowerks v8+ supports such functionality + // via 'msl::is_union::value'. The user can force something to be + // evaluated as a union via EASTL_DECLARE_UNION. + /////////////////////////////////////////////////////////////////////// + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_union))) + #define EASTL_TYPE_TRAIT_is_union_CONFORMANCE 1 // is_union is conforming. + + template + struct is_union : public integral_constant{}; + #else + #define EASTL_TYPE_TRAIT_is_union_CONFORMANCE 0 // is_union is not fully conforming. + + template struct is_union : public false_type{}; + #endif + + #define EASTL_DECLARE_UNION(T) namespace eastl{ template <> struct is_union : public true_type{}; template <> struct is_union : public true_type{}; } + + + + + /////////////////////////////////////////////////////////////////////// + // is_class + // + // is_class::value == true if and only if T is a class or struct + // type (and not a union type). + // + // Without specific compiler help, it is not possible to + // distinguish between unions and classes. As a result, is_class + // will erroneously evaluate to true for union types. + /////////////////////////////////////////////////////////////////////// + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_class))) + #define EASTL_TYPE_TRAIT_is_class_CONFORMANCE 1 // is_class is conforming. + + template + struct is_class : public integral_constant{}; + #elif defined(__EDG__) + #define EASTL_TYPE_TRAIT_is_class_CONFORMANCE EASTL_TYPE_TRAIT_is_union_CONFORMANCE + + typedef char yes_array_type[1]; + typedef char no_array_type[2]; + template static yes_array_type& is_class_helper(void (U::*)()); + template static no_array_type& is_class_helper(...); + + template + struct is_class : public integral_constant(0)) == sizeof(yes_array_type) && !is_union::value + >{}; + #elif !defined(__GNUC__) || (((__GNUC__ * 100) + __GNUC_MINOR__) >= 304) // Not GCC or GCC 3.4+ + #define EASTL_TYPE_TRAIT_is_class_CONFORMANCE EASTL_TYPE_TRAIT_is_union_CONFORMANCE + + template static yes_type is_class_helper(void (U::*)()); + template static no_type is_class_helper(...); + + template + struct is_class : public integral_constant(0)) == sizeof(yes_type) && !is_union::value + >{}; + #else + #define EASTL_TYPE_TRAIT_is_class_CONFORMANCE 0 // is_class is not fully conforming. + + // GCC 2.x version, due to GCC being broken. + template + struct is_class : public false_type{}; + #endif + + + + /////////////////////////////////////////////////////////////////////// + // is_enum + // + // is_enum::value == true if and only if T is an enumeration type. + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_enum))) + #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming. + + template + struct is_enum : public integral_constant{}; + #else + #define EASTL_TYPE_TRAIT_is_enum_CONFORMANCE 1 // is_enum is conforming. + + struct int_convertible{ int_convertible(int); }; + + template + struct is_enum_helper { template struct nest : public is_convertible{}; }; + + template <> + struct is_enum_helper { template struct nest : public false_type {}; }; + + template + struct is_enum_helper2 + { + typedef type_or::value, is_reference::value, is_class::value> selector; + typedef is_enum_helper helper_t; + typedef typename add_reference::type ref_t; + typedef typename helper_t::template nest result; + }; + + template + struct is_enum : public integral_constant::result::value>{}; + + template <> struct is_enum : public false_type {}; + template <> struct is_enum : public false_type {}; + template <> struct is_enum : public false_type {}; + template <> struct is_enum : public false_type {}; + #endif + + #define EASTL_DECLARE_ENUM(T) namespace eastl{ template <> struct is_enum : public true_type{}; template <> struct is_enum : public true_type{}; } + + + + + /////////////////////////////////////////////////////////////////////// + // is_polymorphic + // + // is_polymorphic::value == true if and only if T is a class or struct + // that declares or inherits a virtual function. is_polymorphic may only + // be applied to complete types. + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_polymorphic))) + #define EASTL_TYPE_TRAIT_is_polymorphic_CONFORMANCE 1 // is_polymorphic is conforming. + + template + struct is_polymorphic : public integral_constant{}; + #else + #define EASTL_TYPE_TRAIT_is_polymorphic_CONFORMANCE 1 // is_polymorphic is conforming. + + template + struct is_polymorphic_imp1 + { + typedef typename remove_cv::type t; + + struct helper_1 : public t + { + helper_1(); + ~helper_1() throw(); + char pad[64]; + }; + + struct helper_2 : public t + { + helper_2(); + virtual ~helper_2() throw(); + #ifndef _MSC_VER + virtual void foo(); + #endif + char pad[64]; + }; + + static const bool value = (sizeof(helper_1) == sizeof(helper_2)); + }; + + template + struct is_polymorphic_imp2{ static const bool value = false; }; + + template + struct is_polymorphic_selector{ template struct rebind{ typedef is_polymorphic_imp2 type; }; }; + + template <> + struct is_polymorphic_selector{ template struct rebind{ typedef is_polymorphic_imp1 type; }; }; + + template + struct is_polymorphic_value{ + typedef is_polymorphic_selector::value> selector; + typedef typename selector::template rebind binder; + typedef typename binder::type imp_type; + static const bool value = imp_type::value; + }; + + template + struct is_polymorphic : public integral_constant::value>{}; + #endif + + + + + /////////////////////////////////////////////////////////////////////// + // is_object + // + // is_object::value == true if and only if: + // is_reference::value == false, and + // is_function::value == false, and + // is_void::value == false + // + // The C++ standard, section 3.9p9, states: "An object type is a + // (possibly cv-qualified) type that is not a function type, not a + // reference type, and not incomplete (except for an incompletely + // defined object type). + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_object_CONFORMANCE (EASTL_TYPE_TRAIT_is_reference_CONFORMANCE && EASTL_TYPE_TRAIT_is_void_CONFORMANCE && EASTL_TYPE_TRAIT_is_function_CONFORMANCE) + + template + struct is_object : public integral_constant::value && !is_void::value && !is_function::value + >{}; + + + /////////////////////////////////////////////////////////////////////// + // is_scalar + // + // is_scalar::value == true if and only if: + // is_arithmetic::value == true, or + // is_enum::value == true, or + // is_pointer::value == true, or + // is_member_pointer::value == true, or + // is_null_pointer::value == true + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_scalar_CONFORMANCE 1 // is_scalar is conforming. + + template + struct is_scalar : public integral_constant::value || is_enum::value || is_member_pointer::value || is_null_pointer::value>{}; + + template struct is_scalar : public true_type {}; + template struct is_scalar : public true_type {}; + template struct is_scalar : public true_type {}; + template struct is_scalar : public true_type {}; + + + /////////////////////////////////////////////////////////////////////// + // is_compound + // + // Compound means anything but fundamental. See C++ standard, section 3.9.2. + // + // is_compound::value == true if and only if: + // is_fundamental::value == false + // + // Thus, is_compound::value == true if and only if: + // is_floating_point::value == false, and + // is_integral::value == false, and + // is_void::value == false + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_compound_CONFORMANCE EASTL_TYPE_TRAIT_is_fundamental_CONFORMANCE + + template + struct is_compound : public integral_constant::value>{}; + + + + /////////////////////////////////////////////////////////////////////// + // decay + // + // Converts the type T to its decayed equivalent. That means doing + // lvalue to rvalue, array to pointer, function to pointer conversions, + // and removal of const and volatile. + // This is the type conversion silently applied by the compiler to + // all function arguments when passed by value. + + #define EASTL_TYPE_TRAIT_decay_CONFORMANCE 1 // decay is conforming. + + template + struct decay + { + typedef typename eastl::remove_reference::type U; + + typedef typename eastl::conditional< + eastl::is_array::value, + typename eastl::remove_extent::type*, + typename eastl::conditional< + eastl::is_function::value, + typename eastl::add_pointer::type, + typename eastl::remove_cv::type + >::type + >::type type; + }; + + + // decay_t is the C++14 using typedef for typename decay::type, though + // it requires only C++11 compiler functionality to implement. + // We provide a backwards-compatible means to access it through a macro for pre-C++11 compilers. + #if defined(EA_COMPILER_NO_TEMPLATE_ALIASES) + #define EASTL_DECAY_T(T) typename decay::type + #else + template + using decay_t = typename decay::type; + #define EASTL_DECAY_T(T) decay_t + #endif + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/type_fundamental.h b/libs/eastl/include/EASTL/internal/type_fundamental.h new file mode 100644 index 0000000..2473dbd --- /dev/null +++ b/libs/eastl/include/EASTL/internal/type_fundamental.h @@ -0,0 +1,259 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_TYPE_FUNDAMENTAL_H +#define EASTL_INTERNAL_TYPE_FUNDAMENTAL_H + + +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +namespace eastl +{ + + + /////////////////////////////////////////////////////////////////////// + // is_void + // + // is_void::value == true if and only if T is one of the following types: + // [const][volatile] void + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_void_CONFORMANCE 1 // is_void is conforming. + + template struct is_void : public false_type{}; + + template <> struct is_void : public true_type{}; + template <> struct is_void : public true_type{}; + template <> struct is_void : public true_type{}; + template <> struct is_void : public true_type{}; + + + + /////////////////////////////////////////////////////////////////////// + // has_void_arg + // + // utility which identifies if any of the given template arguments is void. + /////////////////////////////////////////////////////////////////////// + + #if defined(EA_COMPILER_NO_VARIADIC_TEMPLATES) + + template + struct has_void_arg + { static const bool value = eastl::is_void::value || // If we add more arguments then change this + eastl::is_void::value || // to be a recursive template. + eastl::is_void::value || + eastl::is_void::value || + eastl::is_void::value || + eastl::is_void::value; + }; + #else + template + struct has_void_arg; + + template <> + struct has_void_arg<> + : public eastl::false_type {}; + + template + struct has_void_arg + { static const bool value = (eastl::is_void::value || eastl::has_void_arg::value); }; + #endif + + + /////////////////////////////////////////////////////////////////////// + // is_null_pointer + // + // C++14 type trait. Refers only to nullptr_t and not NULL (0). + // eastl::is_null_pointer::value == true + // eastl::is_null_pointer::value == true + // eastl::is_null_pointer::value == false + // eastl::is_null_pointer::value == [cannot compile] + // + /////////////////////////////////////////////////////////////////////// + + #if defined(EA_COMPILER_CPP11_ENABLED) && !defined(EA_COMPILER_NO_DECLTYPE) && !defined(_MSC_VER) // VC++'s handling of decltype(nullptr) is broken. + #define EASTL_TYPE_TRAIT_is_null_pointer_CONFORMANCE 1 + + template + struct is_null_pointer : public eastl::is_same::type, decltype(nullptr)> {}; // A C++11 compiler defines nullptr, but you need a C++11 standard library to declare std::nullptr_t. So it's safer to compare against decltype(nullptr) than to use std::nullptr_t, because we may have a C++11 compiler but C++98 library (happens with Apple frequently). + #else + #define EASTL_TYPE_TRAIT_is_null_pointer_CONFORMANCE 1 + + template + struct is_null_pointer : public eastl::is_same::type, std::nullptr_t> {}; + #endif + + + + /////////////////////////////////////////////////////////////////////// + // is_integral + // + // is_integral::value == true if and only if T is one of the following types: + // [const] [volatile] bool + // [const] [volatile] char + // [const] [volatile] signed char + // [const] [volatile] unsigned char + // [const] [volatile] wchar_t + // [const] [volatile] short + // [const] [volatile] int + // [const] [volatile] long + // [const] [volatile] long long + // [const] [volatile] unsigned short + // [const] [volatile] unsigned int + // [const] [volatile] unsigned long + // [const] [volatile] unsigned long long + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_integral_CONFORMANCE 1 // is_integral is conforming. + + template struct is_integral_helper : public false_type{}; + + template <> struct is_integral_helper : public true_type{}; + template <> struct is_integral_helper : public true_type{}; + template <> struct is_integral_helper : public true_type{}; + template <> struct is_integral_helper : public true_type{}; + template <> struct is_integral_helper : public true_type{}; + + template <> struct is_integral_helper : public true_type{}; + template <> struct is_integral_helper : public true_type{}; + template <> struct is_integral_helper : public true_type{}; + template <> struct is_integral_helper : public true_type{}; + template <> struct is_integral_helper : public true_type{}; + + template <> struct is_integral_helper : public true_type{}; + template <> struct is_integral_helper : public true_type{}; + #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type which is already handled above... + template <> struct is_integral_helper : public true_type{}; + #endif + + template + struct is_integral : public eastl::is_integral_helper::type>{}; + + #define EASTL_DECLARE_INTEGRAL(T) \ + namespace eastl{ \ + template <> struct is_integral : public true_type{}; \ + template <> struct is_integral : public true_type{}; \ + template <> struct is_integral : public true_type{}; \ + template <> struct is_integral : public true_type{}; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // is_floating_point + // + // is_floating_point::value == true if and only if T is one of the following types: + // [const] [volatile] float + // [const] [volatile] double + // [const] [volatile] long double + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_floating_point_CONFORMANCE 1 // is_floating_point is conforming. + + template struct is_floating_point_helper : public false_type{}; + + template <> struct is_floating_point_helper : public true_type{}; + template <> struct is_floating_point_helper : public true_type{}; + template <> struct is_floating_point_helper : public true_type{}; + + template + struct is_floating_point : public eastl::is_floating_point_helper::type>{}; + + #define EASTL_DECLARE_FLOATING_POINT(T) \ + namespace eastl{ \ + template <> struct is_floating_point : public true_type{}; \ + template <> struct is_floating_point : public true_type{}; \ + template <> struct is_floating_point : public true_type{}; \ + template <> struct is_floating_point : public true_type{}; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // is_arithmetic + // + // is_arithmetic::value == true if and only if: + // is_floating_point::value == true, or + // is_integral::value == true + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_arithmetic_CONFORMANCE 1 // is_arithmetic is conforming. + + template + struct is_arithmetic : public integral_constant::value || is_floating_point::value + >{}; + + + + /////////////////////////////////////////////////////////////////////// + // is_fundamental + // + // is_fundamental::value == true if and only if: + // is_floating_point::value == true, or + // is_integral::value == true, or + // is_void::value == true + // is_null_pointer::value == true + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_fundamental_CONFORMANCE 1 // is_fundamental is conforming. + + template + struct is_fundamental : public integral_constant::value || is_integral::value || is_floating_point::value || is_null_pointer::value + >{}; + + + /////////////////////////////////////////////////////////////////////// + // is_hat_type + // + // is_hat_type::value == true if and only if: + // underlying type is a C++/CX '^' type such as: Foo^ + // meaning the type is heap allocated and ref-counted + /////////////////////////////////////////////////////////////////////// + + template struct is_hat_type_helper : public false_type {}; + + #if (EABASE_VERSION_N > 20607 && defined(EA_COMPILER_WINRTCX_ENABLED)) || defined(__cplusplus_winrt) + template struct is_hat_type_helper : public true_type{}; + #endif + + template + struct is_hat_type : public eastl::is_hat_type_helper {}; + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/type_pod.h b/libs/eastl/include/EASTL/internal/type_pod.h new file mode 100644 index 0000000..d9866b2 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/type_pod.h @@ -0,0 +1,1915 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_TYPE_POD_H +#define EASTL_INTERNAL_TYPE_POD_H + + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include +#include + +namespace eastl +{ + /////////////////////////////////////////////////////////////////////// + // is_empty + // + // is_empty::value == true if and only if T is an empty class or struct. + // is_empty may only be applied to complete types. + // + // is_empty cannot be used with union types until is_union can be made to work. + /////////////////////////////////////////////////////////////////////// + #if (defined(_MSC_VER) && (_MSC_VER >= 1600)) // VS2010 and later. + #define EASTL_TYPE_TRAIT_is_empty_CONFORMANCE 1 // is_empty is conforming. + + template + struct is_empty : public integral_constant{}; + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_empty))) + #define EASTL_TYPE_TRAIT_is_empty_CONFORMANCE 1 // is_empty is conforming. + + template + struct is_empty : public integral_constant{}; + #else + #define EASTL_TYPE_TRAIT_is_empty_CONFORMANCE 1 // is_empty is fully conforming. + + template + struct is_empty_helper_t1 : public T { char m[64]; }; + struct is_empty_helper_t2 { char m[64]; }; + + // The inheritance in empty_helper_t1 will not work with non-class types + template + struct is_empty_helper : public eastl::false_type{}; + + template + struct is_empty_helper : public eastl::integral_constant) == sizeof(is_empty_helper_t2) + >{}; + + template + struct is_empty_helper2 + { + typedef typename eastl::remove_cv::type _T; + typedef eastl::is_empty_helper<_T, eastl::is_class<_T>::value> type; + }; + + template + struct is_empty : public eastl::is_empty_helper2::type {}; + #endif + + + /////////////////////////////////////////////////////////////////////// + // is_pod + // + // is_pod::value == true if and only if, for a given type T: + // - is_scalar::value == true, or + // - T is a class or struct that has no user-defined copy assignment + // operator or destructor, and T has no non-static data members M for + // which is_pod::value == false, and no members of reference type, or + // - T is the type of an array of objects E for which is_pod::value == true + // + // is_pod may only be applied to complete types. + // + // Without some help from the compiler or user, is_pod will not report + // that a struct or class is a POD, but will correctly report that + // built-in types such as int are PODs. The user can help the compiler + // by using the EASTL_DECLARE_POD macro on a class. + /////////////////////////////////////////////////////////////////////// + + #if defined(EA_COMPILER_MSVC) + #define EASTL_TYPE_TRAIT_is_pod_CONFORMANCE 1 // is_pod is conforming. Actually as of VS2008 it is apparently not fully conforming, as it flags the following as a non-pod: struct Pod{ Pod(){} }; + + EA_DISABLE_VC_WARNING(4647) + template // We check for has_trivial_constructor only because the VC++ is_pod does. Is it due to some compiler bug? + struct is_pod : public eastl::integral_constant::value) || eastl::is_void::value || eastl::is_scalar::value>{}; + EA_RESTORE_VC_WARNING() + + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_pod))) + #define EASTL_TYPE_TRAIT_is_pod_CONFORMANCE 1 // is_pod is conforming. + + template + struct is_pod : public eastl::integral_constant::value || eastl::is_scalar::value>{}; + #else + #define EASTL_TYPE_TRAIT_is_pod_CONFORMANCE 0 // is_pod is not conforming. Can return false negatives. + + template // There's not much we can do here without some compiler extension. + struct is_pod : public eastl::integral_constant::value || eastl::is_scalar::type>::value>{}; + #endif + + template + struct is_pod : public is_pod{}; + + template + struct is_POD : public is_pod{}; // Backwards compatibility. + + #define EASTL_DECLARE_IS_POD(T, isPod) \ + namespace eastl { \ + template <> struct is_pod : public eastl::integral_constant { }; \ + template <> struct is_pod : public eastl::integral_constant { }; \ + template <> struct is_pod : public eastl::integral_constant { }; \ + template <> struct is_pod : public eastl::integral_constant { }; \ + } + + // Old style macro, for bacwards compatibility: + #define EASTL_DECLARE_POD(T) namespace eastl{ template <> struct is_pod : public true_type{}; template <> struct is_pod : public true_type{}; } + + + + /////////////////////////////////////////////////////////////////////// + // is_standard_layout + // + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(EA_COMPILER_MSVC) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006)) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_standard_layout))) + #define EASTL_TYPE_TRAIT_is_standard_layout_CONFORMANCE 1 // is_standard_layout is conforming. + + template + struct is_standard_layout : public eastl::integral_constant::value || eastl::is_scalar::value>{}; + #else + #define EASTL_TYPE_TRAIT_is_standard_layout_CONFORMANCE 0 // is_standard_layout is not conforming. Can return false negatives. + + template // There's not much we can do here without some compiler extension. + struct is_standard_layout : public eastl::integral_constant::value || is_scalar::value>{}; + #endif + + #define EASTL_DECLARE_IS_STANDARD_LAYOUT(T, isStandardLayout) \ + namespace eastl { \ + template <> struct is_standard_layout : public eastl::integral_constant { }; \ + template <> struct is_standard_layout : public eastl::integral_constant { }; \ + template <> struct is_standard_layout : public eastl::integral_constant { }; \ + template <> struct is_standard_layout : public eastl::integral_constant { }; \ + } + + // Old style macro, for bacwards compatibility: + #define EASTL_DECLARE_STANDARD_LAYOUT(T) namespace eastl{ template <> struct is_standard_layout : public true_type{}; template <> struct is_standard_layout : public true_type{}; } + + + + /////////////////////////////////////////////////////////////////////// + // has_trivial_constructor + // + // has_trivial_constructor::value == true if and only if T is a class + // or struct that has a trivial constructor. A constructor is trivial if + // - it is implicitly defined by the compiler, and + // - is_polymorphic::value == false, and + // - T has no virtual base classes, and + // - for every direct base class of T, has_trivial_constructor::value == true, + // where B is the type of the base class, and + // - for every nonstatic data member of T that has class type or array + // of class type, has_trivial_constructor::value == true, + // where M is the type of the data member + // + // has_trivial_constructor may only be applied to complete types. + // + // Without from the compiler or user, has_trivial_constructor will not + // report that a class or struct has a trivial constructor. + // The user can use EASTL_DECLARE_TRIVIAL_CONSTRUCTOR to help the compiler. + // + // A default constructor for a class X is a constructor of class X that + // can be called without an argument. + /////////////////////////////////////////////////////////////////////// + + #if defined(_MSC_VER) && (_MSC_VER >= 1600) // VS2010+ + #define EASTL_TYPE_TRAIT_has_trivial_constructor_CONFORMANCE 1 // has_trivial_constructor is conforming. + + template + struct has_trivial_constructor : public eastl::integral_constant::value) && !eastl::is_hat_type::value>{}; + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #define EASTL_TYPE_TRAIT_has_trivial_constructor_CONFORMANCE 1 // has_trivial_constructor is conforming. + + template + struct has_trivial_constructor : public eastl::integral_constant::value>{}; + #else + #define EASTL_TYPE_TRAIT_has_trivial_constructor_CONFORMANCE 0 // has_trivial_constructor is not fully conforming. Can return false negatives. + + // With current compilers, this is all we can do. + template + struct has_trivial_constructor : public eastl::is_pod {}; + #endif + + #define EASTL_DECLARE_HAS_TRIVIAL_CONSTRUCTOR(T, hasTrivialConstructor) \ + namespace eastl { \ + template <> struct has_trivial_constructor : public eastl::integral_constant { }; \ + } + + // Old style macro, for bacwards compatibility: + #define EASTL_DECLARE_TRIVIAL_CONSTRUCTOR(T) namespace eastl{ template <> struct has_trivial_constructor : public true_type{}; template <> struct has_trivial_constructor : public true_type{}; } + + + + + /////////////////////////////////////////////////////////////////////// + // has_trivial_copy + // + // has_trivial_copy::value == true if and only if T is a class or + // struct that has a trivial copy constructor. A copy constructor is + // trivial if + // - it is implicitly defined by the compiler, and + // - is_polymorphic::value == false, and + // - T has no virtual base classes, and + // - for every direct base class of T, has_trivial_copy::value == true, + // where B is the type of the base class, and + // - for every nonstatic data member of T that has class type or array + // of class type, has_trivial_copy::value == true, where M is the + // type of the data member + // + // has_trivial_copy may only be applied to complete types. + // + // Another way of looking at this is: + // A copy constructor for class X is trivial if it is implicitly + // declared and if all the following are true: + // - Class X has no virtual functions (10.3) and no virtual base classes (10.1). + // - Each direct base class of X has a trivial copy constructor. + // - For all the nonstatic data members of X that are of class type + // (or array thereof), each such class type has a trivial copy constructor; + // otherwise the copy constructor is nontrivial. + // + // Without help from the compiler or user, has_trivial_copy will not report + // that a class or struct has a trivial copy constructor. The user can + // use EASTL_DECLARE_TRIVIAL_COPY to help the compiler. + /////////////////////////////////////////////////////////////////////// + + #if defined(_MSC_VER) + #define EASTL_TYPE_TRAIT_has_trivial_copy_CONFORMANCE 1 // has_trivial_copy is conforming. + + template + struct has_trivial_copy : public eastl::integral_constant::value) && !eastl::is_volatile::value && !eastl::is_hat_type::value>{}; + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #define EASTL_TYPE_TRAIT_has_trivial_copy_CONFORMANCE 1 // has_trivial_copy is conforming. + + template + struct has_trivial_copy : public eastl::integral_constant::value) && (!eastl::is_volatile::value && !eastl::is_reference::value)>{}; + #else + #define EASTL_TYPE_TRAIT_has_trivial_copy_CONFORMANCE 0 // has_trivial_copy is not fully conforming. Can return false negatives. + + template + struct has_trivial_copy : public eastl::integral_constant::value && !eastl::is_volatile::value>{}; + #endif + + #define EASTL_DECLARE_HAS_TRIVIAL_COPY(T, hasTrivialCopy) \ + namespace eastl { \ + template <> struct has_trivial_copy : public eastl::integral_constant { }; \ + } + + // Old style macro, for bacwards compatibility: + #define EASTL_DECLARE_TRIVIAL_COPY(T) namespace eastl{ template <> struct has_trivial_copy : public true_type{}; template <> struct has_trivial_copy : public true_type{}; } + + + + + /////////////////////////////////////////////////////////////////////// + // has_trivial_assign + // + // has_trivial_assign::value == true if and only if T is a class or + // struct that has a trivial copy assignment operator. A copy assignment + // operator is trivial if: + // - it is implicitly defined by the compiler, and + // - is_polymorphic::value == false, and + // - T has no virtual base classes, and + // - for every direct base class of T, has_trivial_assign::value == true, + // where B is the type of the base class, and + // - for every nonstatic data member of T that has class type or array + // of class type, has_trivial_assign::value == true, where M is + // the type of the data member. + // + // has_trivial_assign may only be applied to complete types. + // + // Without from the compiler or user, has_trivial_assign will not + // report that a class or struct has trivial assignment. The user + // can use EASTL_DECLARE_TRIVIAL_ASSIGN to help the compiler. + /////////////////////////////////////////////////////////////////////// + + #if defined(_MSC_VER) && (_MSC_VER >= 1600) + #define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 1 // has_trivial_assign is conforming. + + template + struct has_trivial_assign : public integral_constant::value) && !eastl::is_const::value && !eastl::is_volatile::value>{}; + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 1 // has_trivial_assign is conforming. + + template + struct has_trivial_assign : public integral_constant::value) && !eastl::is_const::value && !eastl::is_volatile::value>{}; + #else + #define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 0 // is_pod is not fully conforming. Can return false negatives. + + template + struct has_trivial_assign : public integral_constant::value && !is_const::value && !is_volatile::value + >{}; + #endif + + #define EASTL_DECLARE_HAS_TRIVIAL_ASSIGN(T, hasTrivialAssign) \ + namespace eastl { \ + template <> struct has_trivial_assign : public eastl::integral_constant { }; \ + } + + // Old style macro, for bacwards compatibility: + #define EASTL_DECLARE_TRIVIAL_ASSIGN(T) namespace eastl{ template <> struct has_trivial_assign : public true_type{}; template <> struct has_trivial_assign : public true_type{}; } + + + + + /////////////////////////////////////////////////////////////////////// + // has_trivial_destructor + // + // has_trivial_destructor::value == true if and only if T is a class + // or struct that has a trivial destructor. A destructor is trivial if + // - it is implicitly defined by the compiler, and + // - for every direct base class of T, has_trivial_destructor::value == true, + // where B is the type of the base class, and + // - for every nonstatic data member of T that has class type or + // array of class type, has_trivial_destructor::value == true, + // where M is the type of the data member + // + // has_trivial_destructor may only be applied to complete types. + // + // Without from the compiler or user, has_trivial_destructor will not + // report that a class or struct has a trivial destructor. + // The user can use EASTL_DECLARE_TRIVIAL_DESTRUCTOR to help the compiler. + /////////////////////////////////////////////////////////////////////// + + #if defined(_MSC_VER) && (_MSC_VER >= 1600) + #define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 1 // has_trivial_destructor is conforming. + + template + struct has_trivial_destructor : public eastl::integral_constant::value>{}; + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 1 // has_trivial_destructor is conforming. + + template + struct has_trivial_destructor : public eastl::integral_constant::value>{}; + #else + #define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 0 // is_pod is not fully conforming. Can return false negatives. + + // With current compilers, this is all we can do. + template + struct has_trivial_destructor : public eastl::is_pod{}; + #endif + + #define EASTL_DECLARE_HAS_TRIVIAL_DESTRUCTOR(T, hasTrivialDestructor) \ + namespace eastl { \ + template <> struct has_trivial_destructor : public eastl::integral_constant { }; \ + } + + // Old style macro, for bacwards compatibility: + #define EASTL_DECLARE_TRIVIAL_DESTRUCTOR(T) namespace eastl{ template <> struct has_trivial_destructor : public true_type{}; template <> struct has_trivial_destructor : public true_type{}; } + + + + /////////////////////////////////////////////////////////////////////// + // has_trivial_relocate + // + // This is an EA extension to the type traits standard. + // This trait is deprecated under conforming C++11 compilers, as C++11 + // move functionality supercedes this functionality and we want to + // migrate away from it in the future. + // + // A trivially relocatable object is one that can be safely memmove'd + // to uninitialized memory. construction, assignment, and destruction + // properties are not addressed by this trait. A type that has the + // is_fundamental trait would always have the has_trivial_relocate trait. + // A type that has the has_trivial_constructor, has_trivial_copy or + // has_trivial_assign traits would usally have the has_trivial_relocate + // trait, but this is not strictly guaranteed. + // + // The user can use EASTL_DECLARE_TRIVIAL_RELOCATE to help the compiler. + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_has_trivial_relocate_CONFORMANCE 0 // is_pod is not fully conforming. Can return false negatives. + + // With current compilers, this is all we can do. + template + struct has_trivial_relocate : public eastl::integral_constant::value && !eastl::is_volatile::value>{}; + + #define EASTL_DECLARE_TRIVIAL_RELOCATE(T) namespace eastl{ template <> struct has_trivial_relocate : public true_type{}; template <> struct has_trivial_relocate : public true_type{}; } + + + + + /////////////////////////////////////////////////////////////////////// + // has_nothrow_constructor + // + // has_nothrow_constructor::value == true if and only if T is a + // class or struct whose default constructor has an empty throw specification. + // + // has_nothrow_constructor may only be applied to complete types. + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #define EASTL_TYPE_TRAIT_has_nothrow_constructor_CONFORMANCE 1 + + template + struct has_nothrow_constructor + : public eastl::integral_constant{}; + + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && defined(_MSC_VER) + // Microsoft's implementation of __has_nothrow_constructor is crippled and returns true only if T is a class that has an explicit constructor. + // "Returns true if the default constructor has an empty exception specification." + #define EASTL_TYPE_TRAIT_has_nothrow_constructor_CONFORMANCE 0 + + template // This is mistakenly returning true for an unbounded array of scalar type. + struct has_nothrow_constructor : public eastl::integral_constant::type>::value || eastl::is_reference::value>{}; + + #else + #define EASTL_TYPE_TRAIT_has_nothrow_constructor_CONFORMANCE 0 // has_nothrow_constructor is not fully conforming. Can return false negatives. + + template + struct has_nothrow_constructor // To do: Improve this to include other types that can work. + { static const bool value = eastl::is_scalar::type>::value || eastl::is_reference::value; }; + #endif + + #define EASTL_DECLARE_HAS_NOTHROW_CONSTRUCTOR(T, hasNothrowConstructor) \ + namespace eastl { \ + template <> struct has_nothrow_constructor : public eastl::integral_constant { }; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // has_nothrow_copy + // + // has_nothrow_copy::value == true if and only if T is a class or + // struct whose copy constructor has an empty throw specification. + // + // has_nothrow_copy may only be applied to complete types. + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #define EASTL_TYPE_TRAIT_has_nothrow_copy_CONFORMANCE 1 + + template + struct has_nothrow_copy : public eastl::integral_constant{}; + + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && defined(_MSC_VER) + // Microsoft's implementation of __has_nothrow_copy is crippled and returns true only if T is a class that has a copy constructor. + // "Returns true if the copy constructor has an empty exception specification." + #define EASTL_TYPE_TRAIT_has_nothrow_copy_CONFORMANCE 0 + + template + struct has_nothrow_copy : public eastl::integral_constant::type>::value || eastl::is_reference::value>{}; + + #else + #define EASTL_TYPE_TRAIT_has_nothrow_copy_CONFORMANCE 0 // has_nothrow_copy is not fully conforming. Can return false negatives. + + template + struct has_nothrow_copy // To do: Improve this to include other types that can work. + { static const bool value = eastl::is_scalar::type>::value || eastl::is_reference::value; }; + #endif + + #define EASTL_DECLARE_HAS_NOTHROW_COPY(T, hasNothrowCopy) \ + namespace eastl { \ + template <> struct has_nothrow_copy : public eastl::integral_constant { }; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // has_nothrow_assign + // + // has_nothrow_assign::value == true if and only if T is a class or + // struct whose copy assignment operator has an empty throw specification. + // + // has_nothrow_assign may only be applied to complete types. + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #define EASTL_TYPE_TRAIT_has_nothrow_assign_CONFORMANCE 1 + + template + struct has_nothrow_assign : public eastl::integral_constant{}; + + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && defined(_MSC_VER) + // Microsoft's implementation of __has_nothrow_assign is crippled and returns true only if T is a class that has an assignment operator. + // "Returns true if a copy assignment operator has an empty exception specification." + #define EASTL_TYPE_TRAIT_has_nothrow_assign_CONFORMANCE 0 + + template // This is mistakenly returning true for an unbounded array of scalar type. + struct has_nothrow_assign : public eastl::integral_constant::type>::value || eastl::is_reference::value>{}; + #else + #define EASTL_TYPE_TRAIT_has_nothrow_assign_CONFORMANCE 0 // has_nothrow_assign is not fully conforming. Can return false negatives. + + template + struct has_nothrow_assign // To do: Improve this to include other types that can work. + { static const bool value = eastl::is_scalar::type>::value || eastl::is_reference::value; } ; + #endif + + #define EASTL_DECLARE_HAS_NOTHROW_ASSIGN(T, hasNothrowAssign) \ + namespace eastl { \ + template <> struct has_nothrow_assign : public eastl::integral_constant { }; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // has_virtual_destructor + // + // has_virtual_destructor::value == true if and only if T is a class + // or struct with a virtual destructor. + // + // has_virtual_destructor may only be applied to complete types. + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #define EASTL_TYPE_TRAIT_has_virtual_destructor_CONFORMANCE 1 + + template + struct has_virtual_destructor : public eastl::integral_constant{}; + #else + #define EASTL_TYPE_TRAIT_has_virtual_destructor_CONFORMANCE 0 // has_virtual_destructor is not fully conforming. Can return false negatives. + + template + struct has_virtual_destructor : public eastl::false_type{}; + #endif + + #define EASTL_DECLARE_HAS_VIRTUAL_DESTRUCTOR(T, hasVirtualDestructor) \ + namespace eastl { \ + template <> struct has_virtual_destructor : public eastl::integral_constant { }; \ + template <> struct has_virtual_destructor : public eastl::integral_constant { }; \ + template <> struct has_virtual_destructor : public eastl::integral_constant { }; \ + template <> struct has_virtual_destructor : public eastl::integral_constant { }; \ + } + + + /////////////////////////////////////////////////////////////////////// + // is_literal_type + // + // See the C++11 Standard, section 2.9,p10. + // A type is a literal type if it is: + // - a scalar type; or + // - a reference type referring to a literal type; or + // - an array of literal type; or + // - a class type (Clause 9) that has all of the following properties: + // - it has a trivial destructor, + // - every constructor call and full-expression in the brace-or-equal-initializer s for non-static data members (if any) is a constant expression (5.19), + // - it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template that is not a copy or move constructor, and + // - all of its non-static data members and base classes are of literal types. + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_literal)) + #define EASTL_TYPE_TRAIT_is_literal_type_CONFORMANCE 1 + + template + struct is_literal_type : public eastl::integral_constant{}; + + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006)) || (defined(_MSC_VER) && (_MSC_VER >= 1700))) // VS2012+ + #if defined(EA_COMPILER_GNUC) && (!defined(EA_COMPILER_CPP11_ENABLED) || (EA_COMPILER_VERSION < 4007)) + #define EASTL_TYPE_TRAIT_is_literal_type_CONFORMANCE 0 // It seems that in this case GCC supports the compiler intrinsic but reports it as false when it's true. + #else + #define EASTL_TYPE_TRAIT_is_literal_type_CONFORMANCE 1 + #endif + + template + struct is_literal_type : public eastl::integral_constant{}; + + #else + #define EASTL_TYPE_TRAIT_is_literal_type_CONFORMANCE 0 + + // It's not clear if this trait can be fully implemented without explicit compiler support. + // For now we assume that it can't be but implement something that gets it right at least + // some of the time. Recall that partial positives and false negatives are OK (though not ideal), + // while false positives are not OK for us to generate. + + template // This is not a complete implementation and will be true for only some literal types (the basic ones). + struct is_literal_type : public eastl::integral_constant::type>::type>::value>{}; + #endif + + + + /////////////////////////////////////////////////////////////////////// + // is_abstract + // + // is_abstract::value == true if and only if T is a class or struct + // that has at least one pure virtual function. is_abstract may only + // be applied to complete types. + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_abstract))) + #define EASTL_TYPE_TRAIT_is_abstract_CONFORMANCE 1 // is_abstract is conforming. + + template + struct is_abstract : public integral_constant{}; + #else + #define EASTL_TYPE_TRAIT_is_abstract_CONFORMANCE 0 + + template::value> + class is_abstract_helper + { + template + static eastl::yes_type test(...); + + template + static eastl::no_type test(T1(*)[1]); // The following: 'typedef SomeAbstractClass (*SomeFunctionType)[1];' is invalid (can't have an array of abstract types) and thus doesn't choose this path. + + public: + static const bool value = (sizeof(test(NULL)) == sizeof(eastl::yes_type)); + }; + + template + struct is_abstract_helper + { static const bool value = false; }; + + template + struct is_abstract + : public integral_constant::value> { }; + + #endif + + #define EASTL_DECLARE_IS_ABSTRACT(T, isAbstract) \ + namespace eastl { \ + template <> struct is_abstract : public eastl::integral_constant { }; \ + template <> struct is_abstract : public eastl::integral_constant { }; \ + template <> struct is_abstract : public eastl::integral_constant { }; \ + template <> struct is_abstract : public eastl::integral_constant { }; \ + } + + + /////////////////////////////////////////////////////////////////////// + // is_trivially_copyable + // + // T is a trivially copyable type (3.9) T shall be a complete type, + // (possibly cv-qualified) void, or an array of unknown bound. + // + // 3.9,p3: For any trivially copyable type T, if two pointers to T + // point to distinct T objects obj1 and obj2, where neither obj1 nor + // obj2 is a base-class subobject, if the underlying bytes making + // up obj1 are copied into obj2, obj2 shall subsequently hold the + // same value as obj1. In other words, you can memcpy/memmove it. + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_copyable))) + #define EASTL_TYPE_TRAIT_is_trivially_copyable_CONFORMANCE 1 + + // https://connect.microsoft.com/VisualStudio/feedback/details/808827/c-std-is-trivially-copyable-produces-wrong-result-for-arrays + // + // From Microsoft: + // We're working on fixing this. When overhauling in VC 2013, I incorrectly believed that is_trivially_copyable was a synonym + // for is_trivially_copy_constructible. I've asked the compiler team to provide a compiler hook with 100% accurate answers. (Currently, the + // compiler hook has incorrect answers for volatile scalars, volatile data members, and various scenarios for defaulted/deleted/private + // special member functions - I wrote an exhaustive test case to exercise the complicated Standardese.) When the compiler hook is fixed, + // I'll change to invoke it. + // + // Microsoft broken VS2013 STL implementation: + // template + // struct is_trivially_copyable + // : is_trivially_copy_constructible<_Ty>::type + // { // determine whether _Ty has a trivial copy constructor + // }; + // + + template + struct is_trivially_copyable { static const bool value = __is_trivially_copyable(T); }; + + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_MSVC) || defined(EA_COMPILER_GNUC)) + #define EASTL_TYPE_TRAIT_is_trivially_copyable_CONFORMANCE 1 + + // Micrsoft (prior to VS2012) and GCC have __has_trivial_copy, but it may not be identical with the goals of this type trait. + template + struct is_trivially_copyable : public integral_constant::type>::value) && (!eastl::is_void::value && !eastl::is_volatile::value && !eastl::is_reference::value)>{}; + #else + #define EASTL_TYPE_TRAIT_is_trivially_copyable_CONFORMANCE 0 // Generates false negatives. + + template + struct is_trivially_copyable { static const bool value = eastl::is_scalar::type>::value; }; + #endif + + #define EASTL_DECLARE_IS_TRIVIALLY_COPYABLE(T, isTriviallyCopyable) \ + namespace eastl { \ + template <> struct is_trivially_copyable : public eastl::integral_constant { }; \ + template <> struct is_trivially_copyable : public eastl::integral_constant { }; \ + template <> struct is_trivially_copyable : public eastl::integral_constant { }; \ + template <> struct is_trivially_copyable : public eastl::integral_constant { }; \ + } + + + /////////////////////////////////////////////////////////////////////// + // is_constructible + // + // See the C++11 Standard, section 20.9.4.3,p6. + // + /////////////////////////////////////////////////////////////////////// + + #if defined(EA_COMPILER_NO_VARIADIC_TEMPLATES) || defined(EA_COMPILER_NO_DECLTYPE) || EASTL_NO_RVALUE_REFERENCES + + // We currently take a simplified approach whereby we lump all deficient compilers together here, rather than + // implementing a version for compilers that support rvalue references but not variadic templates. However, + // we should eventually implement such a thing because VS2010 and VS2012 are exactly that: compilers that support + // decltype and rvalue references but not variadic templates. + + #define EASTL_TYPE_TRAIT_is_constructible_CONFORMANCE 0 + + // Start by assuming the type is constructible, then below we subtract types that are known not-constructible. + // This can result in false-positives, which we normally avoid, but the use cases of this trait are such that + // we'd rather have false positives than false negatives. But we can revisit that if you have a problem. + + template + struct is_constructible_helper + { static const bool value = !eastl::is_void::value && !eastl::is_function::value && !eastl::is_abstract::value; }; + + template + struct is_constructible + { static const bool value = eastl::is_constructible_helper::type>::value && + !eastl::is_array_of_unknown_bounds::value && + !eastl::is_reference::value && // references can be copy constructed, but here we are testing for only default construction, which isn't possible for references. + eastl::is_same::value && // We have no way of checking argument matches without decltype support, + eastl::is_same::value; // so disallow them. This will result in cases being potentially false negatives. + }; // (To do:) However, we could easily add support for constructing a scalar from another single scalar or reference from something. + + #else + #define EASTL_TYPE_TRAIT_is_constructible_CONFORMANCE 1 + + // We implement a copy of move here has move_internal. We are currently stuck doing this because our move + // implementation is in and currently #includes us, and so we have a header + // chicken-and-egg problem. To do: Resolve this, probably by putting eastl::move somewhere else. + template + inline typename eastl::remove_reference::type&& move_internal(T&& x) EA_NOEXCEPT + { return ((typename eastl::remove_reference::type&&)x); } + + template + typename first_type_select()...)))>::type is(T&&, Args&& ...); + + template + struct can_construct_scalar_helper + { + static eastl::true_type can(T); + static eastl::false_type can(...); + }; + + template + eastl::false_type is(argument_sink, Args&& ...); + + // Except for scalars and references (handled below), check for constructibility via decltype. + template + struct is_constructible_helper_2 // argument_sink will catch all T that is not constructible from the Args and denote false_type + : public eastl::identity(), eastl::declval()...))>::type {}; + + template + struct is_constructible_helper_2 + : public eastl::is_scalar {}; + + template // We handle the case of multiple arguments below (by disallowing them). + struct is_constructible_helper_2 + : public eastl::identity::can(eastl::declval()))>::type {}; + + // Scalars and references can be constructed only with 0 or 1 argument. e.g the following is an invalid expression: int(17, 23) + template + struct is_constructible_helper_2 + : public eastl::false_type {}; + + template + struct is_constructible_helper_1 + : public is_constructible_helper_2::value || eastl::is_reference::value, T, Args...> {}; + + // Unilaterally dismiss void, abstract, unknown bound arrays, and function types as not constructible. + template + struct is_constructible_helper_1 + : public false_type {}; + + // is_constructible + template + struct is_constructible + : public is_constructible_helper_1<(eastl::is_abstract::type>::value || + eastl::is_array_of_unknown_bounds::value || + eastl::is_function::type>::value || + eastl::has_void_arg::value), + T, Args...> {}; + + // Array types are constructible if constructed with no arguments and if their element type is default-constructible + template + struct is_constructible_helper_2 + : public eastl::is_constructible::type> {}; + + // Arrays with arguments are not constructible. e.g. the following is an invalid expression: int[3](37, 34, 12) + template + struct is_constructible_helper_2 + : public eastl::false_type {}; + + #endif + + // You need to manually declare const/volatile variants individually if you want them. + #define EASTL_DECLARE_IS_CONSTRUCTIBLE(T, U, isConstructible) \ + namespace eastl { \ + template <> struct is_constructible : public eastl::integral_constant { }; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // is_trivially_constructible + // + // is_constructible::value is true and the variable definition + // for is_constructible, as defined below, is known to call no operation + // that is not trivial (3.9, 12). T and all types in the parameter pack + // Args shall be complete types, (possibly cv-qualified) void, or arrays + // of unknown bound. + // + // Note: + // C++11's is_trivially_constructible sounds the same as the pre-standard + // has_trivial_constructor type trait (which we also support here). However, + // the definition of has_trivial_constructor has never been formally standardized + // and so we can't just blindly equate the two to each other. Since we are + // moving forward with C++11 and deprecating the old type traits, we leave + // the old ones as-is, though we defer to them in cases where we don't seem + // to have a good alternative. + // + /////////////////////////////////////////////////////////////////////// + + #if defined(EA_COMPILER_NO_VARIADIC_TEMPLATES) + + #define EASTL_TYPE_TRAIT_is_trivially_constructible_CONFORMANCE 0 + + // In this version we allow only zero or one argument (Arg). We can add more arguments + // by creating a number of extra specializations. It's probably not possible to + // simplify the implementation with recursive templates because ctor argument + // presence is specific. + // + // To consider: we can fold the two implementations below by making a macro that's defined + // has __is_trivially_constructible(T) or eastl::has_trivial_copy::value, depending on + // whether the __is_trivially_constructible compiler intrinsic is available. + + // If the compiler has this trait built-in (which ideally all compilers would have since it's necessary for full conformance) use it. + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) + + template + struct is_trivially_constructible + : public eastl::false_type {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant {}; + + #else + + template + struct is_trivially_constructible + : public eastl::false_type {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant::value && eastl::has_trivial_constructor::type>::value> {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant::value && eastl::has_trivial_copy::value> {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant::value && eastl::has_trivial_copy::value> {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant::value && eastl::has_trivial_copy::value> {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant::value && eastl::has_trivial_copy::value> {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant::value && eastl::has_trivial_copy::value> {}; + + #endif + + #else + + // If the compiler has this trait built-in (which ideally all compilers would have since it's necessary for full conformance) use it. + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_constructible)) + #define EASTL_TYPE_TRAIT_is_trivially_constructible_CONFORMANCE 1 + + // We have a problem with clang here as of clang 3.4: __is_trivially_constructible(int[]) is false, yet I believe it should be true. + // Until it gets resolved, what we do is check for is_constructible along with __is_trivially_constructible(). + template + struct is_trivially_constructible + : public eastl::integral_constant::value && __is_trivially_constructible(T, Args...)> {}; + + #else + + #define EASTL_TYPE_TRAIT_is_trivially_constructible_CONFORMANCE 0 // This is 0 but in fact it will work for most real-world cases due to the has_trivial_constructor specialization below. + + template + struct is_trivially_constructible + : public eastl::false_type {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant::value && eastl::has_trivial_constructor::type>::value> {}; + + // It's questionable whether we can use has_trivial_copy here, as it could theoretically create a false-positive. + template + struct is_trivially_constructible + : public eastl::integral_constant::value && eastl::has_trivial_copy::value> {}; + + #if !EASTL_NO_RVALUE_REFERENCES + template + struct is_trivially_constructible + : public eastl::integral_constant::value && eastl::has_trivial_copy::value> {}; + #endif + + template + struct is_trivially_constructible + : public eastl::integral_constant::value && eastl::has_trivial_copy::value> {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant::value && eastl::has_trivial_copy::value> {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant::value && eastl::has_trivial_copy::value> {}; + + template + struct is_trivially_constructible + : public eastl::integral_constant::value && eastl::has_trivial_copy::value> {}; + + #endif + + #endif + + + #define EASTL_DECLARE_IS_TRIVIALLY_CONSTRUCTIBLE(T, isTriviallyConstructible) \ + namespace eastl { \ + template <> struct is_trivially_constructible : public eastl::integral_constant { }; \ + template <> struct is_trivially_constructible : public eastl::integral_constant { }; \ + template <> struct is_trivially_constructible : public eastl::integral_constant { }; \ + template <> struct is_trivially_constructible : public eastl::integral_constant { }; \ + } + + + /////////////////////////////////////////////////////////////////////// + // is_trivially_default_constructible + // + // is_trivially_constructible::value is true. + // This is thus identical to is_trivially_constructible. + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_trivially_default_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_trivially_constructible_CONFORMANCE + + template + struct is_trivially_default_constructible + : public eastl::is_trivially_constructible {}; + + + + /////////////////////////////////////////////////////////////////////// + // is_trivial + // + // is_trivial::value == true if T is a scalar type, a trivially copyable + // class with a trivial default constructor, or array of such type/class, + // possibly cv-qualified), provides the member constant value equal true. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_trivial_CONFORMANCE ((EASTL_TYPE_TRAIT_is_trivially_default_constructible_CONFORMANCE && EASTL_TYPE_TRAIT_is_trivially_copyable_CONFORMANCE) ? 1 : 0) + + #if defined(_MSC_VER) && _MSC_VER == 1800 + template + struct is_trivial_helper + : public eastl::integral_constant::value && eastl::is_trivially_default_constructible::value>{}; + + template + struct is_trivial_helper + : public false_type{}; + + template + struct is_trivial + : public is_trivial_helper<(EA_ALIGN_OF(T) > EA_PLATFORM_MIN_MALLOC_ALIGNMENT), T>::type{}; + #else + // All other compilers seem to be able to handle aligned types passed as value + template + struct is_trivial + : public eastl::integral_constant::value && eastl::is_trivially_default_constructible::value> {}; + #endif + + /////////////////////////////////////////////////////////////////////// + // is_nothrow_constructible + // + // is_constructible::value is true and the variable definition + // for is_constructible, as defined below, is known not to throw any + // exceptions (5.3.7). T and all types in the parameter pack Args shall + // be complete types, (possibly cv-qualified) void, or arrays of unknown bound. + // + /////////////////////////////////////////////////////////////////////// + + #if defined(EA_COMPILER_NO_VARIADIC_TEMPLATES) + + #define EASTL_TYPE_TRAIT_is_nothrow_constructible_CONFORMANCE 0 + + template + struct is_nothrow_constructible + : public eastl::false_type {}; + + template + struct is_nothrow_constructible + : public eastl::integral_constant::value> {}; + + template + struct is_nothrow_constructible + : public eastl::integral_constant::value> {}; + + template + struct is_nothrow_constructible + : public eastl::integral_constant::value> {}; + + template + struct is_nothrow_constructible + : public eastl::integral_constant::value> {}; + + #else + + #if defined(EA_COMPILER_NO_NOEXCEPT) + + #define EASTL_TYPE_TRAIT_is_nothrow_constructible_CONFORMANCE 0 + + template + struct is_nothrow_constructible + : public eastl::false_type {}; + + template + struct is_nothrow_constructible + : public eastl::integral_constant::value> {}; + + template + struct is_nothrow_constructible + : public eastl::integral_constant::value> {}; + + template + struct is_nothrow_constructible + : public eastl::integral_constant::value> {}; + + template + struct is_nothrow_constructible + : public eastl::integral_constant::value> {}; + + #if !EASTL_NO_RVALUE_REFERENCES + template + struct is_nothrow_constructible + : public eastl::integral_constant::value> {}; + #endif + + #else + + #if defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION < 4008) + #define EASTL_TYPE_TRAIT_is_nothrow_constructible_CONFORMANCE 0 // GCC up to v4.7's noexcept is broken and fails to generate true for the case of compiler-generated constructors. + #else + #define EASTL_TYPE_TRAIT_is_nothrow_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_constructible_CONFORMANCE + #endif + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // *_noexcept_wrapper implements a workaround for VS2015 preview. A standards conforming noexcept operator allows variadic template expansion. + // There appears to be an issue with VS2015 preview that prevents variadic template expansion into a noexcept operator that is passed directly + // to a template parameter. + // + // The fix hoists the noexcept expression into a separate struct and caches the result of the expression. This result is then passed to integral_constant. + // + // Example code from Clang libc++ + // template + // struct __libcpp_is_nothrow_constructible<[>is constructible*/true, /*is reference<]false, _Tp, _Args...> + // : public integral_constant()...))> { }; + // + + template + struct is_nothrow_constructible_helper_noexcept_wrapper + { static const bool value = noexcept(T(eastl::declval()...)); }; + + template + struct is_nothrow_constructible_helper; + + template + struct is_nothrow_constructible_helper + : public eastl::integral_constant::value> {}; + + template + struct is_nothrow_constructible_helper + : public eastl::integral_constant()))> {}; + + template + struct is_nothrow_constructible_helper + : public eastl::integral_constant {}; + + template + struct is_nothrow_constructible_helper + : public eastl::false_type {}; + + template + struct is_nothrow_constructible + : public eastl::is_nothrow_constructible_helper::value, T, Args...> {}; + + template + struct is_nothrow_constructible + : public eastl::is_nothrow_constructible_helper::value, T> {}; + + #endif + + #endif + + #define EASTL_DECLARE_IS_NOTHROW_CONSTRUCTIBLE(T, isNothrowConstructible) \ + namespace eastl{ \ + template <> struct is_nothrow_constructible : public eastl::integral_constant { }; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // is_default_constructible + // + // is_constructible::value is true. + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_default_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_constructible_CONFORMANCE + + template + struct is_default_constructible + : public eastl::is_constructible {}; + + + + /////////////////////////////////////////////////////////////////////// + // is_copy_constructible + // + // is_constructible::value is true. + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_copy_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_constructible_CONFORMANCE + + template + struct is_copy_constructible + : public eastl::is_constructible::type>::type> {}; + + + + + /////////////////////////////////////////////////////////////////////// + // is_trivially_copy_constructible + // + // is_trivially_constructible::value is true. + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_trivially_copy_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_trivially_constructible_CONFORMANCE + + template struct is_trivially_copy_constructible + : public eastl::is_trivially_constructible::type>::type> {}; + + + + /////////////////////////////////////////////////////////////////////// + // is_nothrow_copy_constructible + // + // is_nothrow_-constructible::value is true. + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_nothrow_copy_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_nothrow_constructible_CONFORMANCE + + template + struct is_nothrow_copy_constructible + : public is_nothrow_constructible::type>::type> {}; + + + + /////////////////////////////////////////////////////////////////////// + // is_move_constructible + // + // is_constructible::value is true. + /////////////////////////////////////////////////////////////////////// + + #if EASTL_NO_RVALUE_REFERENCES + #define EASTL_TYPE_TRAIT_is_move_constructible_CONFORMANCE 0 + + template + struct is_move_constructible + : public eastl::is_copy_constructible {}; + #else + #define EASTL_TYPE_TRAIT_is_move_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_constructible_CONFORMANCE + + template + struct is_move_constructible + : public eastl::is_constructible::type> {}; + #endif + + + + /////////////////////////////////////////////////////////////////////// + // is_trivially_move_constructible + // + // is_trivially_constructible::value is true. + // T shall be a complete type, (possibly cv-qualified) void, or an + // array of unknown bound. + /////////////////////////////////////////////////////////////////////// + + #if EASTL_NO_RVALUE_REFERENCES + #define EASTL_TYPE_TRAIT_is_trivially_move_constructible_CONFORMANCE 0 + + template + struct is_trivially_move_constructible + : public eastl::is_trivially_copy_constructible {}; + #else + #define EASTL_TYPE_TRAIT_is_trivially_move_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_trivially_constructible_CONFORMANCE + + template + struct is_trivially_move_constructible + : public eastl::is_trivially_constructible::type> {}; + #endif + + #define EASTL_DECLARE_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE(T, isTrivallyMoveConstructible) \ + namespace eastl{ \ + template <> struct is_trivially_move_constructible : public eastl::integral_constant { }; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // is_assignable + // + // The expression declval() = declval() is well-formed when treated as an unevaluated operand. + // Access checking is performed as if in a context unrelated to T and U. Only the validity of + // the immediate context of the assignment expression is considered. The compilation of the expression + // can result in side effects such as the instantiation of class template specializations and function + // template specializations, the generation of implicitly-defined functions, and so on. Such side + // effects are not in the "immediate context" and can result in the program being ill-formed. + // + // Note: + // This type trait has a misleading and counter-intuitive name. It does not indicate whether an instance + // of U can be assigned to an instance of T (e.g. t = u). Instead it indicates whether the assignment can be + // done after adding rvalue references to both, as in add_rvalue_reference::type = add_rvalue_reference::type. + // A counterintuitive result of this is that is_assignable::value == false. The is_copy_assignable + // trait indicates if a type can be assigned to its own type, though there isn't a standard C++ way to tell + // if an arbitrary type is assignable to another type. + // http://stackoverflow.com/questions/19920213/why-is-stdis-assignable-counter-intuitive + // + // Note: + // A true is_assignable value doesn't guarantee that the expression is compile-able, the compiler checks + // only that the assignment matches before compilation. In particular, if you have templated operator= + // for a class, the compiler will always say is_assignable is true, regardless of what's being tested + // on the right hand side of the expression. It may actually turn out during compilation that the + // templated operator= fails to compile because in practice it doesn't accept every possible type for + // the right hand side of the expression. + // + // Expected results: + // is_assignable::value == false + // is_assignable::value == true + // is_assignable::value == false + // is_assignable::value == false + // is_assignable::value == false + // is_assignable::value == false + // is_assignable::value == false + // is_assignable::value == false + // is_assignable::value == false + // is_assignable::value == false + // is_assignable::value == false + // is_assignable::value == true + // is_assignable::value == false + // + // Note: + // Our implementation here yields different results than does the std::is_assignable from Dinkumware-based Standard + // Libraries, but yields similar results to the std::is_assignable from GCC's libstdc++ and clang's libc++. It may + // possibly be that the Dinkumware results are intentionally different for some practical purpose or because they + // represent the spirit or the Standard but not the letter of the Standard. + // + /////////////////////////////////////////////////////////////////////// + + #if (defined(EA_COMPILER_NO_DECLTYPE) && !EASTL_TYPE_TRAIT_declval_CONFORMANCE) || defined(_MSC_VER) // VS2012 mis-compiles the conforming code below and so must be placed here. + #define EASTL_TYPE_TRAIT_is_assignable_CONFORMANCE 0 + + // It's impossible to do this correctly without declval or some other compiler help. + // is_assignable is defined in terms of add_rvalue_reference::type instead of T alone, + // and so we will need to have two fallback implementations: one for compilers with rvalue + // support and one for compilers without it. + + // Version for compilers without rvalue support: + template + struct is_assignable_helper + { + typedef typename eastl::remove_reference::type T1; + typedef typename eastl::remove_reference::type U1; + + // Do not decay the types, as a decayed array (pointer) can be assigned but an array cannot. + static const bool eitherIsArray = (eastl::is_array::value || eastl::is_array::value); + static const bool isArithmetic = (eastl::is_arithmetic::value && eastl::is_arithmetic::value); + static const bool isSameScalar = (eastl::is_same::value && eastl::is_scalar::value && eastl::is_scalar::value); + static const bool isTConst = eastl::is_const::value; + + EA_DISABLE_VC_WARNING(6285) + static const bool value = (isArithmetic || isSameScalar) && !eitherIsArray && !isTConst; + EA_RESTORE_VC_WARNING() + }; + #else + #define EASTL_TYPE_TRAIT_is_assignable_CONFORMANCE 1 + + template + struct is_assignable_helper + { + template + static eastl::no_type is(...); + + template + static decltype(eastl::declval() = eastl::declval(), eastl::yes_type()) is(int); + + static const bool value = (sizeof(is(0)) == sizeof(eastl::yes_type)); + }; + #endif + + template + struct is_assignable : + public eastl::integral_constant::value> {}; + + // The main purpose of this function is to help the non-conforming case above. + // Note: We don't handle const/volatile variations here, as we expect the user to + // manually specify any such variations via this macro. + // Example usage: + // EASTL_DECLARE_IS_ASSIGNABLE(int, int, false) + // + #define EASTL_DECLARE_IS_ASSIGNABLE(T, U, isAssignable) \ + namespace eastl { \ + template <> struct is_assignable : public eastl::integral_constant { }; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // is_lvalue_assignable + // + // This is an EASTL extension function which is like is_assignable but + // works for arbitrary assignments and not just rvalue assignments. + // This function provides an intuitive assignability test, as opposed + // to is_assignable. + // + // Note: is_lvalue_assignable === is_copy_assignable + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_lvalue_assignable_CONFORMANCE EASTL_TYPE_TRAIT_is_assignable_CONFORMANCE + + template + struct is_lvalue_assignable + : public eastl::is_assignable::type, + typename eastl::add_lvalue_reference::type>::type> {}; + + #define EASTL_DECLARE_IS_LVALUE_ASSIGNABLE(T, U, isLvalueAssignable) \ + namespace eastl { \ + template <> struct is_lvalue_assignable : public eastl::integral_constant { }; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // is_trivially_assignable + // + // is_assignable::value is true and the assignment, as defined by + // is_assignable, is known to call no operation that is not trivial (3.9, 12). + // T and U shall be complete types, (possibly cv-qualified) void, or + // arrays of unknown bound + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_trivially_assignable)) + #define EASTL_TYPE_TRAIT_is_trivially_assignable_CONFORMANCE 1 + + template + struct is_trivially_assignable + : eastl::integral_constant {}; + + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) && (_MSC_VER >= 1800)) + #define EASTL_TYPE_TRAIT_is_trivially_assignable_CONFORMANCE EASTL_TYPE_TRAIT_is_assignable_CONFORMANCE + + // This code path is attempting to work around the issue with VS2013 __is_trivially_assignable compiler intrinsic documented in the link + // below. todo: Re-evaluate in VS2014. + // + // https://connect.microsoft.com/VisualStudio/feedback/details/806233/std-is-trivially-copyable-const-int-n-and-std-is-trivially-copyable-int-n-incorrect + + template + struct is_trivially_assignable_helper; + + template + struct is_trivially_assignable_helper : eastl::integral_constant{}; + + template + struct is_trivially_assignable_helper : false_type{}; + + template + struct is_trivially_assignable + : eastl::integral_constant::value, T, U >::value> {}; + + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_MSVC) || defined(EA_COMPILER_GNUC)) + #define EASTL_TYPE_TRAIT_is_trivially_assignable_CONFORMANCE EASTL_TYPE_TRAIT_is_assignable_CONFORMANCE + + // Micrsoft (up till at least VS2012) and GCC have __has_trivial_assign, but it may not be identical with the goals of this type trait. + // The Microsoft type trait headers suggest that a future version of VS will have a __is_trivially_assignable intrinsic, but we + // need to come up with something in the meantime. To do: Re-evalulate this for VS2013+ when it becomes available. + template + struct is_trivially_assignable + : eastl::integral_constant::value && + (eastl::is_pod::type>::value || __has_trivial_assign(typename eastl::remove_reference::type))> {}; + #else + + #define EASTL_TYPE_TRAIT_is_trivially_assignable_CONFORMANCE 0 // Generates false negatives. + + template + struct is_trivially_assignable + : public eastl::false_type {}; + + template + struct is_trivially_assignable + : public eastl::integral_constant::value> {}; + + template + struct is_trivially_assignable + : public eastl::integral_constant::value> {}; + + template + struct is_trivially_assignable + : public eastl::integral_constant::value> {}; + + #if !EASTL_NO_RVALUE_REFERENCES + template + struct is_trivially_assignable + : public eastl::integral_constant::value> {}; + #endif + + #endif + + // The main purpose of this function is to help the non-conforming case above. + // Note: We don't handle const/volatile variations here, as we expect the user to + // manually specify any such variations via this macro. + // Example usage: + // EASTL_DECLARE_IS_TRIVIALLY_ASSIGNABLE(int, int, false) + // + #define EASTL_DECLARE_IS_TRIVIALLY_ASSIGNABLE(T, U, isTriviallyAssignable) \ + namespace eastl { \ + template <> struct is_trivially_assignable : public eastl::integral_constant { }; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // is_nothrow_assignable + // + // is_assignable::value is true and the assignment is known + // not to throw any exceptions (5.3.7). T and U shall be complete + // types, (possibly cv-qualified) void, or arrays of unknown bound. + // + /////////////////////////////////////////////////////////////////////// + + #if defined(_MSC_VER) && (_MSC_VER >= 1800) // VS2013+ + #define EASTL_TYPE_TRAIT_is_nothrow_assignable_CONFORMANCE 1 + + template + struct is_nothrow_assignable + : eastl::integral_constant {}; + + #elif defined(EA_COMPILER_NO_NOEXCEPT) || defined(__EDG_VERSION__) // EDG mis-compiles the conforming code below and so must be placed here. + #define EASTL_TYPE_TRAIT_is_nothrow_assignable_CONFORMANCE 0 + + template + struct is_nothrow_assignable + : public false_type {}; + + // Note that the following are crippled in that they support only assignment of T types to other T types. + template + struct is_nothrow_assignable + : public eastl::integral_constant::value> {}; + + template + struct is_nothrow_assignable + : public eastl::integral_constant::value> {}; + + template + struct is_nothrow_assignable + : public eastl::integral_constant::value> {}; + + #else + #define EASTL_TYPE_TRAIT_is_nothrow_assignable_CONFORMANCE 1 + + template + struct is_nothrow_assignable_helper; + + template + struct is_nothrow_assignable_helper + : public false_type {}; + + template + struct is_nothrow_assignable_helper // Set to true if the assignment (same as is_assignable) cannot generate an exception. + : public eastl::integral_constant() = eastl::declval()) > + { + }; + + template + struct is_nothrow_assignable + : public eastl::is_nothrow_assignable_helper::value, T, U> + { + }; + #endif + + #define EASTL_DECLARE_IS_NOTHROW_ASSIGNABLE(T, isNothrowAssignable) \ + namespace eastl{ \ + template <> struct is_nothrow_assignable : public eastl::integral_constant { }; \ + template <> struct is_nothrow_assignable : public eastl::integral_constant { }; \ + template <> struct is_nothrow_assignable : public eastl::integral_constant { }; \ + template <> struct is_nothrow_assignable : public eastl::integral_constant { }; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // is_copy_assignable + // + // is_assignable::value is true. T shall be a complete type, + // (possibly cv -qualified) void, or an array of unknown bound. + // + // This (and not is_assignable) is the type trait you use to tell if you + // can do an arbitrary assignment. is_assignable tells if you can do an + // assignment specifically to an rvalue and not in general. + // http://stackoverflow.com/a/19921030/725009 + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_copy_assignable_CONFORMANCE EASTL_TYPE_TRAIT_is_assignable_CONFORMANCE + + template + struct is_copy_assignable + : public eastl::is_assignable::type, + typename eastl::add_lvalue_reference::type>::type> {}; + + + + /////////////////////////////////////////////////////////////////////// + // is_trivially_copy_assignable + // + // is_trivially_assignable::value is true. T shall be a + // complete type, (possibly cv-qualified) void, or an array of unknown bound. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_trivially_copy_assignable_CONFORMANCE EASTL_TYPE_TRAIT_is_trivially_assignable_CONFORMANCE + +#if EASTL_TYPE_TRAIT_is_trivially_copy_assignable_CONFORMANCE + template + struct is_trivially_copy_assignable + : public eastl::is_trivially_assignable::type, + typename eastl::add_lvalue_reference::type>::type> {}; +#else + template + struct is_trivially_copy_assignable + : public integral_constant::value || eastl::is_pod::value || eastl::is_trivially_assignable::type, typename eastl::add_lvalue_reference::type>::type>::value + > {}; +#endif + + #define EASTL_DECLARE_IS_TRIVIALLY_COPY_ASSIGNABLE(T, isTriviallyCopyAssignable) \ + namespace eastl { \ + template <> struct is_trivially_copy_assignable : public eastl::integral_constant { }; \ + } + + /////////////////////////////////////////////////////////////////////// + // is_nothrow_copy_assignable + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_nothrow_copy_assignable_CONFORMANCE EASTL_TYPE_TRAIT_is_nothrow_assignable_CONFORMANCE + + template + struct is_nothrow_copy_assignable + : public eastl::is_nothrow_assignable::type, + typename eastl::add_lvalue_reference::type>::type> {}; + + + + /////////////////////////////////////////////////////////////////////// + // is_move_assignable + // + // is_assignable::value is true. T shall be a complete type, + // (possibly cv -qualified) void, or an array of unknown bound. + /////////////////////////////////////////////////////////////////////// + + #if EASTL_NO_RVALUE_REFERENCES + #define EASTL_TYPE_TRAIT_is_move_assignable_CONFORMANCE 0 + + template + struct is_move_assignable : public is_copy_assignable{}; + #else + #define EASTL_TYPE_TRAIT_is_move_assignable_CONFORMANCE EASTL_TYPE_TRAIT_is_assignable_CONFORMANCE + + template + struct is_move_assignable + : public eastl::is_assignable::type, + typename eastl::add_rvalue_reference::type> {}; + #endif + + #define EASTL_DECLARE_IS_MOVE_ASSIGNABLE(T, isMoveAssignable) \ + namespace eastl{ \ + template <> struct is_move_assignable : public eastl::integral_constant { }; \ + template <> struct is_move_assignable : public eastl::integral_constant { }; \ + template <> struct is_move_assignable : public eastl::integral_constant { }; \ + template <> struct is_move_assignable : public eastl::integral_constant { }; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // is_trivially_move_assignable + // + // is_trivially_-assignable::value is true. T shall be a complete type, + // (possibly cv-qualified) void, or an array of unknown bound. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_trivially_move_assignable_CONFORMANCE EASTL_TYPE_TRAIT_is_trivially_assignable_CONFORMANCE + + template + struct is_trivially_move_assignable + : public eastl::is_trivially_assignable::type, + typename eastl::add_rvalue_reference::type> {}; + + + + /////////////////////////////////////////////////////////////////////// + // is_nothrow_move_assignable + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_nothrow_move_assignable_CONFORMANCE EASTL_TYPE_TRAIT_is_nothrow_assignable_CONFORMANCE + + template + struct is_nothrow_move_assignable + : public eastl::is_nothrow_assignable::type, + typename eastl::add_rvalue_reference::type> {}; + + + + /////////////////////////////////////////////////////////////////////// + // is_destructible + // + // For a complete type T and given + // template + // struct test { U u; }; + // test::test() is not deleted (C++11 "= delete"). + // T shall be a complete type, (possibly cv-qualified) void, or an array of unknown bound. + // + /////////////////////////////////////////////////////////////////////// + + #if 0 // defined(_MSC_VER) && (_MSC_VER >= 1800) // VS2013+ -- Disabled due to __is_destructible being broken in VC++ versions up to at least VS2013. A ticket will be submitted for this + #define EASTL_TYPE_TRAIT_is_destructible_CONFORMANCE 1 + + template + struct is_destructible + : integral_constant {}; + + #elif defined(EA_COMPILER_NO_DECLTYPE) || defined(EA_COMPILER_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS) || defined(_MSC_VER) || defined(__EDG_VERSION__) // VS2012 and EDG mis-compile the conforming code below and so must be placed here. + #define EASTL_TYPE_TRAIT_is_destructible_CONFORMANCE 0 + + // This implementation works for almost all cases, with the primary exception being the + // case that the user declared the destructor as deleted. To deal with that case the + // user needs to use EASTL_DECLARE_IS_NOT_DESTRUCTIBLE to cause is_destructible::value + // to be false. + + template + struct is_destructible + : public eastl::integral_constant::value && + !eastl::is_void::value && + !eastl::is_function::value && + !eastl::is_abstract::value> {}; + #else + #define EASTL_TYPE_TRAIT_is_destructible_CONFORMANCE 1 + + template + struct destructible_test_helper{ U u; }; + + template + eastl::false_type destructible_test_function(...); + + template >().~destructible_test_helper())> + eastl::true_type destructible_test_function(int); + + template ::value || // Exclude these types from being considered destructible. + eastl::is_void::value || + eastl::is_function::value || + eastl::is_abstract::value> + struct is_destructible_helper + : public eastl::identity(0))>::type {}; // Need to wrap decltype with identity because some compilers otherwise don't like the bare decltype usage. + + template + struct is_destructible_helper + : public eastl::false_type {}; + + template + struct is_destructible + : public is_destructible_helper {}; + + #endif + + #define EASTL_DECLARE_IS_DESTRUCTIBLE(T, isDestructible) \ + namespace eastl{ \ + template <> struct is_destructible : public eastl::integral_constant{}; \ + template <> struct is_destructible : public eastl::integral_constant{}; \ + template <> struct is_destructible : public eastl::integral_constant{}; \ + template <> struct is_destructible : public eastl::integral_constant{}; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // is_trivially_destructible + // + // is_destructible::value is true and the indicated destructor is + // known to be trivial. T shall be a complete type, (possibly cv-qualified) + // void, or an array of unknown bound. + // + // A destructor is trivial if it is not user-provided and if: + // - the destructor is not virtual, + // - all of the direct base classes of its class have trivial destructors, and + // - for all of the non-static data members of its class that are of + // class type (or array thereof), each such class has a trivial destructor. + // + /////////////////////////////////////////////////////////////////////// + + #if 0 // defined(_MSC_VER) && (_MSC_VER >= 1800) // VS2013+ -- Disabled due to __is_trivially_destructible being broken in VC++ versions up to at least VS2013. A ticket will be submitted for this + #define EASTL_TYPE_TRAIT_is_trivially_destructible_CONFORMANCE 1 + + template + struct is_trivially_destructible + : integral_constant {}; + + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #define EASTL_TYPE_TRAIT_is_trivially_destructible_CONFORMANCE EASTL_TYPE_TRAIT_is_destructible_CONFORMANCE + + template + struct is_trivially_destructible // Can't use just __has_trivial_destructor(T) because some compilers give it slightly different meaning, and are just plain broken, such as VC++'s __has_trivial_destructor, which says false for fundamental types. + : public integral_constant::value && ((__has_trivial_destructor(T) && !eastl::is_hat_type::value)|| eastl::is_scalar::type>::value)> {}; + + #else + #define EASTL_TYPE_TRAIT_is_trivially_destructible_CONFORMANCE 0 + + template + struct is_trivially_destructible_helper + : public integral_constant::value || eastl::is_scalar::value || eastl::is_reference::value) && !eastl::is_void::value> {}; + + template + struct is_trivially_destructible + : public eastl::is_trivially_destructible_helper::type> {}; + #endif + + #define EASTL_DECLARE_IS_TRIVIALLY_DESTRUCTIBLE(T, isTriviallyDestructible) \ + namespace eastl{ \ + template <> struct is_trivially_destructible : public eastl::integral_constant{}; \ + template <> struct is_trivially_destructible : public eastl::integral_constant{}; \ + template <> struct is_trivially_destructible : public eastl::integral_constant{}; \ + template <> struct is_trivially_destructible : public eastl::integral_constant{}; \ + } + + + + + /////////////////////////////////////////////////////////////////////// + // is_nothrow_destructible + // + // is_destructible::value is true and the indicated destructor is + // known not to throw any exceptions (5.3.7). T shall be a complete type, + // (possibly cv-qualified) void, or an array of unknown bound. + // + /////////////////////////////////////////////////////////////////////// + + #if 0 // defined(_MSC_VER) && (_MSC_VER >= 1800) // VS2013+ -- Disabled due to __is_nothrow_destructible being broken in VC++ versions up to at least VS2013. A ticket will be submitted for this + #define EASTL_TYPE_TRAIT_is_nothrow_destructible_CONFORMANCE ((_MSC_VER >= 1900) ? 1 : 0) // VS2013 (1800) doesn't support noexcept and so can't support all usage of this properly (in particular default exception specifications defined in [C++11 Standard, 15.4 paragraph 14]. + + template + struct is_nothrow_destructible + : integral_constant {}; + + #elif defined(EA_COMPILER_NO_NOEXCEPT) || defined(EA_COMPILER_NO_DECLTYPE) + #define EASTL_TYPE_TRAIT_is_nothrow_destructible_CONFORMANCE 0 + + template + struct is_nothrow_destructible_helper + : public eastl::integral_constant::value || eastl::is_reference::value> {}; + + template + struct is_nothrow_destructible + : public eastl::is_nothrow_destructible_helper::type> {}; + + #else + #if defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION < 4008) + #define EASTL_TYPE_TRAIT_is_nothrow_destructible_CONFORMANCE 0 // GCC up to v4.7's noexcept is broken and fails to generate true for the case of compiler-generated destructors. + #else + #define EASTL_TYPE_TRAIT_is_nothrow_destructible_CONFORMANCE EASTL_TYPE_TRAIT_is_destructible_CONFORMANCE + #endif + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // *_noexcept_wrapper implements a workaround for VS2015. A standards conforming noexcept operator allows variadic template expansion. + // There appears to be an issue with VS2015 that prevents variadic template expansion into a noexcept operator that is passed directly + // to a template parameter. + // + // The fix hoists the noexcept expression into a separate struct and caches the result of the expression. This result is then passed to integral_constant. + // + // Example code from Clang libc++ + // template + // struct __libcpp_is_nothrow_constructible<[>is constructible*/true, /*is reference<]false, _Tp, _Args...> + // : public integral_constant()...))> { }; + // + + template + struct is_nothrow_destructible_helper_noexcept_wrapper + { static const bool value = noexcept(eastl::declval().~T()); }; + + template + struct is_nothrow_destructible_helper; + + template + struct is_nothrow_destructible_helper + : public eastl::false_type {}; + + template + struct is_nothrow_destructible_helper // If the expression T::~T is a noexcept expression then it's nothrow. + : public eastl::integral_constant::value > {}; + + template + struct is_nothrow_destructible // A type needs to at least be destructible before it could be nothrow destructible. + : public eastl::is_nothrow_destructible_helper::value> {}; + + template // An array is nothrow destructible if its element type is nothrow destructible. + struct is_nothrow_destructible // To consider: Replace this with a remove_all_extents pathway. + : public eastl::is_nothrow_destructible {}; + + template + struct is_nothrow_destructible // A reference type cannot throw while being destructed. It's just a reference. + : public eastl::true_type {}; + + #if !EASTL_NO_RVALUE_REFERENCES + template + struct is_nothrow_destructible // An rvalue reference type cannot throw while being destructed. + : public eastl::true_type {}; + #endif + + #endif + + #define EASTL_DECLARE_IS_NOTHROW_DESTRUCTIBLE(T, isNoThrowDestructible) \ + namespace eastl{ \ + template <> struct is_nothrow_destructible { static const bool value = isNoThrowDestructible; }; \ + template <> struct is_nothrow_destructible { static const bool value = isNoThrowDestructible; }; \ + template <> struct is_nothrow_destructible { static const bool value = isNoThrowDestructible; }; \ + template <> struct is_nothrow_destructible { static const bool value = isNoThrowDestructible; }; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // is_nothrow_default_constructible + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_nothrow_default_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_nothrow_constructible_CONFORMANCE + + template + struct is_nothrow_default_constructible + : public eastl::is_nothrow_constructible {}; + + + + /////////////////////////////////////////////////////////////////////// + // is_nothrow_move_constructible + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_NO_RVALUE_REFERENCES + #define EASTL_TYPE_TRAIT_is_nothrow_move_constructible_CONFORMANCE 0 + + template + struct is_nothrow_move_constructible + : public eastl::is_nothrow_copy_constructible {}; + #else + #define EASTL_TYPE_TRAIT_is_nothrow_move_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_nothrow_constructible_CONFORMANCE + + template + struct is_nothrow_move_constructible + : public eastl::is_nothrow_constructible::type> {}; + #endif + + + +} // namespace eastl + + +#endif // Header include guard diff --git a/libs/eastl/include/EASTL/internal/type_properties.h b/libs/eastl/include/EASTL/internal/type_properties.h new file mode 100644 index 0000000..7c0b88d --- /dev/null +++ b/libs/eastl/include/EASTL/internal/type_properties.h @@ -0,0 +1,453 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_TYPE_PROPERTIES_H +#define EASTL_INTERNAL_TYPE_PROPERTIES_H + + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include + + +namespace eastl +{ + + + /////////////////////////////////////////////////////////////////////// + // underlying_type + // + // Defines a member typedef type of type that is the underlying type for the enumeration T. + // Requires explicit compiler support to implement. + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1700)) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)) || defined(EA_COMPILER_CLANG)) // VS2012+ + #define EASTL_TYPE_TRAIT_underlying_type_CONFORMANCE 1 // underlying_type is conforming. + + template + struct underlying_type{ typedef __underlying_type(T) type; }; + + #else + #define EASTL_TYPE_TRAIT_underlying_type_CONFORMANCE 0 + + template + struct underlying_type{ typedef int type; }; // This is of course wrong, but we emulate libstdc++ and typedef it as int. + #endif + + + + + /////////////////////////////////////////////////////////////////////// + // is_signed + // + // is_signed::value == true if and only if T is one of the following types: + // [const] [volatile] char (maybe) + // [const] [volatile] signed char + // [const] [volatile] short + // [const] [volatile] int + // [const] [volatile] long + // [const] [volatile] long long + // [const] [volatile] float + // [const] [volatile] double + // [const] [volatile] long double + // + // Used to determine if a integral type is signed or unsigned. + // Given that there are some user-made classes which emulate integral + // types, we provide the EASTL_DECLARE_SIGNED macro to allow you to + // set a given class to be identified as a signed type. + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_signed_CONFORMANCE 1 // is_signed is conforming. + + template struct is_signed_helper : public false_type{}; + + template <> struct is_signed_helper : public true_type{}; + template <> struct is_signed_helper : public true_type{}; + template <> struct is_signed_helper : public true_type{}; + template <> struct is_signed_helper : public true_type{}; + template <> struct is_signed_helper : public true_type{}; + template <> struct is_signed_helper : public true_type{}; + template <> struct is_signed_helper : public true_type{}; + template <> struct is_signed_helper : public true_type{}; + + #if (CHAR_MAX == SCHAR_MAX) + template <> struct is_signed_helper : public true_type{}; + #endif + #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type... + #if defined(__WCHAR_MAX__) && ((__WCHAR_MAX__ == 2147483647) || (__WCHAR_MAX__ == 32767)) // GCC defines __WCHAR_MAX__ for most platforms. + template <> struct is_signed_helper : public true_type{}; + #endif + #endif + + template + struct is_signed : public eastl::is_signed_helper::type>{}; + + + #define EASTL_DECLARE_SIGNED(T) \ + namespace eastl{ \ + template <> struct is_signed : public true_type{}; \ + template <> struct is_signed : public true_type{}; \ + template <> struct is_signed : public true_type{}; \ + template <> struct is_signed : public true_type{}; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // is_unsigned + // + // is_unsigned::value == true if and only if T is one of the following types: + // [const] [volatile] char (maybe) + // [const] [volatile] unsigned char + // [const] [volatile] unsigned short + // [const] [volatile] unsigned int + // [const] [volatile] unsigned long + // [const] [volatile] unsigned long long + // + // Used to determine if a integral type is signed or unsigned. + // Given that there are some user-made classes which emulate integral + // types, we provide the EASTL_DECLARE_UNSIGNED macro to allow you to + // set a given class to be identified as an unsigned type. + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_unsigned_CONFORMANCE 1 // is_unsigned is conforming. + + template struct is_unsigned_helper : public false_type{}; + + template <> struct is_unsigned_helper : public true_type{}; + template <> struct is_unsigned_helper : public true_type{}; + template <> struct is_unsigned_helper : public true_type{}; + template <> struct is_unsigned_helper : public true_type{}; + template <> struct is_unsigned_helper : public true_type{}; + + #if (CHAR_MAX == UCHAR_MAX) + template <> struct is_unsigned_helper : public true_type{}; + #endif + #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type... + #if defined(_MSC_VER) || (defined(__WCHAR_MAX__) && ((__WCHAR_MAX__ == 4294967295U) || (__WCHAR_MAX__ == 65535))) // GCC defines __WCHAR_MAX__ for most platforms. + template <> struct is_unsigned_helper : public true_type{}; + #endif + #endif + + template + struct is_unsigned : public eastl::is_unsigned_helper::type>{}; + + #define EASTL_DECLARE_UNSIGNED(T) \ + namespace eastl{ \ + template <> struct is_unsigned : public true_type{}; \ + template <> struct is_unsigned : public true_type{}; \ + template <> struct is_unsigned : public true_type{}; \ + template <> struct is_unsigned : public true_type{}; \ + } + + + + /////////////////////////////////////////////////////////////////////// + // alignment_of + // + // alignment_of::value is an integral value representing, in bytes, + // the memory alignment of objects of type T. + // + // alignment_of may only be applied to complete types. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_alignment_of_CONFORMANCE 1 // alignment_of is conforming. + + template + struct alignment_of_value{ static const size_t value = EASTL_ALIGN_OF(T); }; + + template + struct alignment_of : public integral_constant::value>{}; + + + + /////////////////////////////////////////////////////////////////////// + // is_aligned + // + // Defined as true if the type has alignment requirements greater + // than default alignment, which is taken to be 8. This allows for + // doing specialized object allocation and placement for such types. + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_aligned_CONFORMANCE 1 // is_aligned is conforming. + + template + struct is_aligned_value{ static const bool value = (EASTL_ALIGN_OF(T) > 8); }; + + template + struct is_aligned : public integral_constant::value>{}; + + + + /////////////////////////////////////////////////////////////////////// + // rank + // + // rank::value is an integral value representing the number of + // dimensions possessed by an array type. For example, given a + // multi-dimensional array type T[M][N], std::tr1::rank::value == 2. + // For a given non-array type T, std::tr1::rank::value == 0. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_rank_CONFORMANCE 1 // rank is conforming. + + template + struct rank : public eastl::integral_constant {}; + + template + struct rank : public eastl::integral_constant::value + 1> {}; + + template + struct rank : public eastl::integral_constant::value + 1> {}; + + + + /////////////////////////////////////////////////////////////////////// + // extent + // + // extent::value is an integral type representing the number of + // elements in the Ith dimension of array type T. + // + // For a given array type T[N], extent::value == N. + // For a given multi-dimensional array type T[M][N], extent::value == N. + // For a given multi-dimensional array type T[M][N], extent::value == M. + // For a given array type T and a given dimension I where I >= rank::value, extent::value == 0. + // For a given array type of unknown extent T[], extent::value == 0. + // For a given non-array type T and an arbitrary dimension I, extent::value == 0. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_extent_CONFORMANCE 1 // extent is conforming. + + template + struct extent_help : public eastl::integral_constant {}; + + template + struct extent_help : public eastl::integral_constant {}; + + template + struct extent_help : public eastl::extent_help { }; + + template + struct extent_help : public eastl::extent_help {}; + + template // extent uses unsigned instead of size_t. + struct extent : public eastl::extent_help { }; + + + + /////////////////////////////////////////////////////////////////////// + // is_base_of + // + // Given two (possibly identical) types Base and Derived, is_base_of::value == true + // if and only if Base is a direct or indirect base class of Derived, + // or Base and Derived are the same type. + // + // is_base_of may only be applied to complete types. + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || (defined(EA_COMPILER_CLANG) && EA_COMPILER_HAS_FEATURE(is_base_of))) + #define EASTL_TYPE_TRAIT_is_base_of_CONFORMANCE 1 // is_base_of is conforming. + + template + struct is_base_of : public eastl::integral_constant::value>{}; + #else + // Not implemented yet. + // This appears to be implementable. + #define EASTL_TYPE_TRAIT_is_base_of_CONFORMANCE 0 + #endif + + + + /////////////////////////////////////////////////////////////////////// + // is_lvalue_reference + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_is_lvalue_reference_CONFORMANCE 1 // is_lvalue_reference is conforming. + + template struct is_lvalue_reference : public eastl::false_type {}; + template struct is_lvalue_reference : public eastl::true_type {}; + + + /////////////////////////////////////////////////////////////////////// + // is_rvalue_reference + // + /////////////////////////////////////////////////////////////////////// + + #if EASTL_NO_RVALUE_REFERENCES + #define EASTL_TYPE_TRAIT_is_rvalue_reference_CONFORMANCE 0 // Given that the compiler doesn't support rvalue references, maybe the conformance here should be 1, since the result of this is always correct. + + template struct is_rvalue_reference : public eastl::false_type {}; + #else + #define EASTL_TYPE_TRAIT_is_rvalue_reference_CONFORMANCE 1 // is_rvalue_reference is conforming. + + template struct is_rvalue_reference : public eastl::false_type {}; + template struct is_rvalue_reference : public eastl::true_type {}; + #endif + + + /////////////////////////////////////////////////////////////////////// + // result_of + // + /////////////////////////////////////////////////////////////////////// + + #if defined(EA_COMPILER_NO_VARIADIC_TEMPLATES) || defined(EA_COMPILER_NO_DECLTYPE) + // To do: come up with the best possible alternative. + #define EASTL_TYPE_TRAIT_result_of_CONFORMANCE 0 + #else + #define EASTL_TYPE_TRAIT_result_of_CONFORMANCE 1 // result_of is conforming. + + template struct result_of; + + template + struct result_of + { typedef decltype(eastl::declval()(eastl::declval()...)) type; }; + + + // result_of_t is the C++14 using typedef for typename result_of::type. + // We provide a backwards-compatible means to access it through a macro for pre-C++11 compilers. + #if defined(EA_COMPILER_NO_TEMPLATE_ALIASES) + #define EASTL_RESULT_OF_T(T) typename result_of::type + #else + template + using result_of_t = typename result_of::type; + #define EASTL_RESULT_OF_T(T) result_of_t + #endif + + #endif + + + /////////////////////////////////////////////////////////////////////// + // common_type + // + // Determines the common type among all types T..., that is the type all T... + // can be implicitly converted to. + // + // It is intended that this be specialized by the user for cases where it + // is useful to do so. Example specialization: + // template + // struct common_type{ typedef MyBaseClassB type; }; + // + // The member typedef type shall be defined as set out in 20.9.7.6,p3. All types in + // the parameter pack T shall be complete or (possibly cv) void. A program may + // specialize this trait if at least one template parameter in the specialization + // is a user-defined type. Note: Such specializations are needed when only + // explicit conversions are desired among the template arguments. + /////////////////////////////////////////////////////////////////////// + + #if defined(EA_COMPILER_NO_DECLTYPE) + #define EASTL_TYPE_TRAIT_common_type_CONFORMANCE 0 + + // Perhaps we can do better. On the other hand, compilers that don't support variadic + // templates and decltype probably won't need the common_type trait anyway. + template + struct common_type + { typedef void type; }; + + template + struct common_type + { typedef void type; }; + + template + struct common_type + { typedef T type; }; + + template + struct common_type + { typedef T type; }; + + #elif defined(EA_COMPILER_NO_VARIADIC_TEMPLATES) + #define EASTL_TYPE_TRAIT_common_type_CONFORMANCE 0 + + template + struct common_type + { typedef typename eastl::common_type::type, V>::type type; }; + + template + struct common_type + { typedef T type; }; + + template + class common_type + { + #if EASTL_NO_RVALUE_REFERENCES + static T t(); + static U u(); + #else + static T&& t(); + static U&& u(); + #endif + + public: + typedef typename eastl::remove_reference::type type; + }; + + #else + #define EASTL_TYPE_TRAIT_common_type_CONFORMANCE 1 // common_type is conforming. + + template + struct common_type; + + template + struct common_type + { typedef T type; }; // Question: Should we use T or decay_t here? The C++11 Standard specifically (20.9.7.6,p3) specifies that it be without decay, but libc++ uses decay. + + template + struct common_type + { + static T&& t(); + static U&& u(); + typedef decltype(true ? t() : u()) type; // The type of a tertiary expression is set by the compiler to be the common type of the two result types. + }; + + template + struct common_type + { typedef typename common_type::type, V...>::type type; }; + + + // common_type_t is the C++14 using typedef for typename common_type::type. + // We provide a backwards-compatible means to access it through a macro for pre-C++11 compilers. + #if defined(EA_COMPILER_NO_TEMPLATE_ALIASES) + #define EASTL_COMMON_TYPE_T(...) typename common_type<__VA_ARGS__>::type + #else + template + using common_type_t = typename common_type::type; + #define EASTL_COMMON_TYPE_T(...) common_type_t<__VA_ARGS__> + #endif + + #endif + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/internal/type_transformations.h b/libs/eastl/include/EASTL/internal/type_transformations.h new file mode 100644 index 0000000..561e069 --- /dev/null +++ b/libs/eastl/include/EASTL/internal/type_transformations.h @@ -0,0 +1,567 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTERNAL_TYPE_TRANFORMATIONS_H +#define EASTL_INTERNAL_TYPE_TRANFORMATIONS_H + + +#include +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + +#include + + +namespace eastl +{ + + /////////////////////////////////////////////////////////////////////// + // add_const + // + // Add const to a type. + // + // Tor a given type T, add_const::type is equivalent to T + // const if is_const::value == false, and + // - is_void::value == true, or + // - is_object::value == true. + // + // Otherwise, add_const::type is equivalent to T. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_add_const_CONFORMANCE 1 // add_const is conforming. + + template ::value || eastl::is_reference::value || eastl::is_function::value> + struct add_const_helper + { typedef T type; }; + + template + struct add_const_helper + { typedef const T type; }; + + template + struct add_const + { typedef typename eastl::add_const_helper::type type; }; + + // add_const_t is the C++17 using typedef for typename add_const::type. + // We provide a backwards-compatible means to access it through a macro for pre-C++11 compilers. + #if defined(EA_COMPILER_NO_TEMPLATE_ALIASES) + #define EASTL_ADD_CONST_T(T) typename add_const::type + #else + template + using add_const_t = typename add_const::type; + #define EASTL_ADD_CONST_T(T) add_const_t + #endif + + + /////////////////////////////////////////////////////////////////////// + // add_volatile + // + // Add volatile to a type. + // + // For a given type T, add_volatile::type is equivalent to T volatile + // if is_volatile::value == false, and + // - is_void::value == true, or + // - is_object::value == true. + // + // Otherwise, add_volatile::type is equivalent to T. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_add_volatile_CONFORMANCE 1 // add_volatile is conforming. + + template ::value || eastl::is_reference::value || eastl::is_function::value> + struct add_volatile_helper + { typedef T type; }; + + template + struct add_volatile_helper + { typedef volatile T type; }; + + template struct add_volatile + { typedef typename eastl::add_volatile_helper::type type; }; + + + + /////////////////////////////////////////////////////////////////////// + // add_cv + // + // The add_cv transformation trait adds const and volatile qualification + // to the type to which it is applied. For a given type T, + // add_volatile::type is equivalent to add_const::type>::type. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_add_cv_CONFORMANCE 1 // add_cv is conforming. + + template + struct add_cv + { + typedef typename add_const::type>::type type; + }; + + + + /////////////////////////////////////////////////////////////////////// + // make_signed + // + // Used to convert an integral type to its signed equivalent, if not already. + // T shall be a (possibly const and/or volatile-qualified) integral type + // or enumeration but not a bool type.; + // + // The user can define their own make_signed overrides for their own + // types by making a template specialization like done below and adding + // it to the user's code. + /////////////////////////////////////////////////////////////////////// + + // To do: This implementation needs to be updated to support C++11 conformance (recognition of enums) and + // to support volatile-qualified types. It will probably be useful to have it fail for unsupported types. + #define EASTL_TYPE_TRAIT_make_signed_CONFORMANCE 0 // make_signed is only partially conforming. + + template struct make_signed { typedef T type; }; + + template <> struct make_signed { typedef signed char type; }; + template <> struct make_signed { typedef const signed char type; }; + template <> struct make_signed { typedef signed short type; }; + template <> struct make_signed { typedef const signed short type; }; + template <> struct make_signed { typedef signed int type; }; + template <> struct make_signed { typedef const signed int type; }; + template <> struct make_signed { typedef signed long type; }; + template <> struct make_signed { typedef const signed long type; }; + template <> struct make_signed { typedef signed long long type; }; + template <> struct make_signed { typedef const signed long long type; }; + + #if (defined(CHAR_MAX) && defined(UCHAR_MAX) && (CHAR_MAX == UCHAR_MAX)) // If char is unsigned, we convert char to signed char. However, if char is signed then make_signed returns char itself and not signed char. + template <> struct make_signed { typedef signed char type; }; + template <> struct make_signed { typedef signed char type; }; + #endif + + #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type... + #if (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 4294967295U)) // If wchar_t is a 32 bit unsigned value... + template<> + struct make_signed + { typedef int32_t type; }; + #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 65535)) // If wchar_t is a 16 bit unsigned value... + template<> + struct make_signed + { typedef int16_t type; }; + #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ == 255)) // If wchar_t is an 8 bit unsigned value... + template<> + struct make_signed + { typedef int8_t type; }; + #endif + #endif + + + /////////////////////////////////////////////////////////////////////// + // add_signed + // + // This is not a C++11 type trait, and is here for backwards compatibility + // only. Use the C++11 make_unsigned type trait instead. + /////////////////////////////////////////////////////////////////////// + + template + struct add_signed : public make_signed + { typedef typename eastl::make_signed::type type; }; + + + + + /////////////////////////////////////////////////////////////////////// + // make_unsigned + // + // Used to convert an integral type to its signed equivalent, if not already. + // T shall be a (possibly const and/or volatile-qualified) integral type + // or enumeration but not a bool type.; + // + // The user can define their own make_signed overrides for their own + // types by making a template specialization like done below and adding + // it to the user's code. + /////////////////////////////////////////////////////////////////////// + + // To do: This implementation needs to be updated to support C++11 conformance (recognition of enums) and + // to support volatile-qualified types. It will probably be useful to have it fail for unsupported types. + #define EASTL_TYPE_TRAIT_make_unsigned_CONFORMANCE 0 // make_unsigned is only partially conforming. + + template struct make_unsigned { typedef T type; }; + + template <> struct make_unsigned { typedef unsigned char type; }; + template <> struct make_unsigned { typedef const unsigned char type; }; + template <> struct make_unsigned { typedef unsigned short type; }; + template <> struct make_unsigned { typedef const unsigned short type; }; + template <> struct make_unsigned { typedef unsigned int type; }; + template <> struct make_unsigned { typedef const unsigned int type; }; + template <> struct make_unsigned { typedef unsigned long type; }; + template <> struct make_unsigned { typedef const unsigned long type; }; + template <> struct make_unsigned { typedef unsigned long long type; }; + template <> struct make_unsigned { typedef const unsigned long long type; }; + + #if (CHAR_MIN < 0) // If char is signed, we convert char to unsigned char. However, if char is unsigned then make_unsigned returns char itself and not unsigned char. + template <> struct make_unsigned { typedef unsigned char type; }; + template <> struct make_unsigned { typedef unsigned char type; }; + #endif + + #ifndef EA_WCHAR_T_NON_NATIVE // If wchar_t is a native type instead of simply a define to an existing type... + #if (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 4294967295U)) // If wchar_t is a 32 bit signed value... + template<> + struct make_unsigned + { typedef uint32_t type; }; + #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 65535)) // If wchar_t is a 16 bit signed value... + template<> + struct make_unsigned + { typedef uint16_t type; }; + #elif (defined(__WCHAR_MAX__) && (__WCHAR_MAX__ != 255)) // If wchar_t is an 8 bit signed value... + template<> + struct make_unsigned + { typedef uint8_t type; }; + #endif + #endif + + + + /////////////////////////////////////////////////////////////////////// + // add_unsigned + // + // This is not a C++11 type trait, and is here for backwards compatibility + // only. Use the C++11 make_unsigned type trait instead. + // + // Adds unsigned-ness to the given type. + // Modifies only integral values; has no effect on others. + // add_unsigned::type is unsigned int + // add_unsigned::type is unsigned int + // + /////////////////////////////////////////////////////////////////////// + + template + struct add_unsigned : public make_unsigned + { typedef typename eastl::make_signed::type type; }; + + + + /////////////////////////////////////////////////////////////////////// + // remove_pointer + // + // Remove pointer from a type. + // + // The remove_pointer transformation trait removes top-level indirection + // by pointer (if any) from the type to which it is applied. Pointers to + // members are not affected. For a given type T, remove_pointer::type + // is equivalent to T. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_remove_pointer_CONFORMANCE 1 + + template struct remove_pointer { typedef T type; }; + template struct remove_pointer { typedef T type; }; + template struct remove_pointer { typedef T type; }; + template struct remove_pointer { typedef T type; }; + template struct remove_pointer { typedef T type; }; + + + + /////////////////////////////////////////////////////////////////////// + // add_pointer + // + // Add pointer to a type. + // Provides the member typedef type which is the type T*. If T is a + // reference type, then type is a pointer to the referred type. + // + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_add_pointer_CONFORMANCE 1 + + template + struct add_pointer { typedef typename eastl::remove_reference::type* type; }; + + + + /////////////////////////////////////////////////////////////////////// + // remove_extent + // + // The remove_extent transformation trait removes a dimension from an array. + // For a given non-array type T, remove_extent::type is equivalent to T. + // For a given array type T[N], remove_extent::type is equivalent to T. + // For a given array type const T[N], remove_extent::type is equivalent to const T. + // For example, given a multi-dimensional array type T[M][N], remove_extent::type is equivalent to T[N]. + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_remove_extent_CONFORMANCE 1 // remove_extent is conforming. + + template struct remove_extent { typedef T type; }; + template struct remove_extent { typedef T type; }; + template struct remove_extent { typedef T type; }; + + + + /////////////////////////////////////////////////////////////////////// + // remove_all_extents + // + // The remove_all_extents transformation trait removes all dimensions from an array. + // For a given non-array type T, remove_all_extents::type is equivalent to T. + // For a given array type T[N], remove_all_extents::type is equivalent to T. + // For a given array type const T[N], remove_all_extents::type is equivalent to const T. + // For example, given a multi-dimensional array type T[M][N], remove_all_extents::type is equivalent to T. + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_remove_all_extents_CONFORMANCE 1 // remove_all_extents is conforming. + + template struct remove_all_extents { typedef T type; }; + template struct remove_all_extents { typedef typename eastl::remove_all_extents::type type; }; + template struct remove_all_extents { typedef typename eastl::remove_all_extents::type type; }; + + + + /////////////////////////////////////////////////////////////////////// + // aligned_storage + // + // The aligned_storage transformation trait provides a type that is + // suitably aligned to store an object whose size is does not exceed length + // and whose alignment is a divisor of alignment. When using aligned_storage, + // length must be non-zero, and alignment must >= alignment_of::value + // for some type T. We require the alignment value to be a power-of-two. + // + // GCC versions prior to 4.4 don't properly support this with stack-based + // variables. The EABase EA_ALIGN_MAX_AUTOMATIC define identifies the + // extent to which stack (automatic) variables can be aligned for the + // given compiler/platform combination. + // + // Example usage: + // aligned_storage::type widget; + // Widget* pWidget = new(&widget) Widget; + // + // aligned_storage::type widgetAlignedTo64; + // Widget* pWidget = new(&widgetAlignedTo64) Widget; + // + // aligned_storage::type widgetArray[37]; + // Widget* pWidgetArray = new(widgetArray) Widget[37]; + /////////////////////////////////////////////////////////////////////// + + #define EASTL_TYPE_TRAIT_aligned_storage_CONFORMANCE 1 // aligned_storage is conforming. + + #if defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4008) + // New versions of GCC do not support using 'alignas' with a value greater than 128. + // However, this code using the GNU standard alignment attribute works properly. + template + struct aligned_storage + { + struct type { unsigned char mCharData[N]; } EA_ALIGN(Align); + }; + #elif (EABASE_VERSION_N >= 20040) && !defined(EA_COMPILER_NO_ALIGNAS) // If C++11 alignas is supported... + template + struct aligned_storage + { + typedef struct { + alignas(Align) unsigned char mCharData[N]; + } type; + }; + + #elif defined(EA_COMPILER_MSVC) || (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION < 4007)) || defined(EA_COMPILER_EDG) // At some point GCC fixed their attribute(align) to support non-literals, though it's not clear what version aside from being no later than 4.7 and no earlier than 4.2. + // Some compilers don't allow you to to use EA_ALIGNED with anything by a numeric literal, + // so we can't use the simpler code like we do further below for other compilers. We support + // only up to so much of an alignment value here. + template + struct aligned_storage_helper { struct type{ unsigned char mCharData[N]; }; }; + + template struct aligned_storage_helper { struct EA_ALIGN( 2) type{ unsigned char mCharData[N]; }; }; + template struct aligned_storage_helper { struct EA_ALIGN( 4) type{ unsigned char mCharData[N]; }; }; + template struct aligned_storage_helper { struct EA_ALIGN( 8) type{ unsigned char mCharData[N]; }; }; + template struct aligned_storage_helper { struct EA_ALIGN( 16) type{ unsigned char mCharData[N]; }; }; + template struct aligned_storage_helper { struct EA_ALIGN( 32) type{ unsigned char mCharData[N]; }; }; + template struct aligned_storage_helper { struct EA_ALIGN( 64) type{ unsigned char mCharData[N]; }; }; + template struct aligned_storage_helper { struct EA_ALIGN( 128) type{ unsigned char mCharData[N]; }; }; + template struct aligned_storage_helper { struct EA_ALIGN( 256) type{ unsigned char mCharData[N]; }; }; + template struct aligned_storage_helper { struct EA_ALIGN( 512) type{ unsigned char mCharData[N]; }; }; + template struct aligned_storage_helper { struct EA_ALIGN(1024) type{ unsigned char mCharData[N]; }; }; + template struct aligned_storage_helper { struct EA_ALIGN(2048) type{ unsigned char mCharData[N]; }; }; + template struct aligned_storage_helper { struct EA_ALIGN(4096) type{ unsigned char mCharData[N]; }; }; + + template + struct aligned_storage + { + typedef typename aligned_storage_helper::type type; + }; + + #else + template + struct aligned_storage + { + union type + { + unsigned char mCharData[N]; + struct EA_ALIGN(Align) mStruct{ }; + }; + }; + #endif + + #if defined(EA_COMPILER_NO_TEMPLATE_ALIASES) + #define EASTL_ALIGNED_STORAGE_T(N, Align) typename eastl::aligned_storage_t::type + #else + template + using aligned_storage_t = typename aligned_storage::type; + #define EASTL_ALIGNED_STORAGE_T(N, Align) eastl::aligned_storage_t + #endif + + + + /////////////////////////////////////////////////////////////////////// + // aligned_union + // + // The member typedef type shall be a POD type suitable for use as + // uninitialized storage for any object whose type is listed in Types; + // its size shall be at least Len. The static member alignment_value + // shall be an integral constant of type std::size_t whose value is + // the strictest alignment of all types listed in Types. + // Note that the resulting type is not a C/C++ union, but simply memory + // block (of pod type) that can be used to placement-new an actual + // C/C++ union of the types. The actual union you declare can be a non-POD union. + // + // Example usage: + // union MyUnion { + // char c; + // int i; + // float f; + // + // MyUnion(float fValue) : f(fValue) {} + // }; + // + // aligned_union::type myUnionStorage; + // MyUnion* pMyUnion = new(&myUnionStorage) MyUnion(21.4f); + // pMyUnion->i = 37; + // + /////////////////////////////////////////////////////////////////////// + + #if defined(EA_COMPILER_NO_VARIADIC_TEMPLATES) || !EASTL_TYPE_TRAIT_static_max_CONFORMANCE + #define EASTL_TYPE_TRAIT_aligned_union_CONFORMANCE 0 // aligned_union is not conforming, as it supports only a two-member unions. + + // To consider: Expand this to include more possible types. We may want to convert this to be a recursive + // template instead of like below. + template + struct aligned_union + { + static const size_t size0 = eastl::static_max::value; + static const size_t size1 = eastl::static_max::value; + static const size_t size2 = eastl::static_max::value; + static const size_t size = eastl::static_max::value; + + static const size_t alignment0 = eastl::static_max::value; + static const size_t alignment1 = eastl::static_max::value; + static const size_t alignment_value = eastl::static_max::value; + + typedef typename eastl::aligned_storage::type type; + }; + + #if defined(EA_COMPILER_NO_TEMPLATE_ALIASES) + // To do: define macro. + #else + template + using aligned_union_t = typename aligned_union::type; + #endif + #else + #define EASTL_TYPE_TRAIT_aligned_union_CONFORMANCE 1 // aligned_union is conforming. + + template + struct aligned_union + { + static const size_t size = eastl::static_max::value; + static const size_t alignment_value = eastl::static_max::value; + + typedef typename eastl::aligned_storage::type type; + }; + + #if defined(EA_COMPILER_NO_TEMPLATE_ALIASES) + // To do: define macro. + #else + template + using aligned_union_t = typename aligned_union::type; + #endif + + #endif + + + /////////////////////////////////////////////////////////////////////// + // union_cast + // + // Safely converts between unrelated types that have a binary equivalency. + // This appoach is required by strictly conforming C++ compilers because + // directly using a C or C++ cast between unrelated types is fraught with + // the possibility of undefined runtime behavior due to type aliasing. + // The Source and Dest types must be POD types due to the use of a union + // in C++ versions prior to C++11. C++11 relaxes the definition of a POD + // such that it allows a classes with trivial default constructors whereas + // previous versions did not, so beware of this when writing portable code. + // + // Example usage: + // float f32 = 1.234f; + // uint32_t n32 = union_cast(f32); + // + // Example possible mis-usage: + // The following is valid only if you are aliasing the pointer value and + // not what it points to. Most of the time the user intends the latter, + // which isn't strictly possible. + // Widget* pWidget = CreateWidget(); + // Foo* pFoo = union_cast(pWidget); + /////////////////////////////////////////////////////////////////////// + + template + DestType union_cast(SourceType sourceValue) + { + EASTL_CT_ASSERT((sizeof(DestType) == sizeof(SourceType)) && + (EA_ALIGN_OF(DestType) == EA_ALIGN_OF(SourceType))); // To support differening alignments, we would need to use a memcpy-based solution or find a way to make the two union members align with each other. + //EASTL_CT_ASSERT(is_pod::value && is_pod::value); // Disabled because we don't want to restrict what the user can do, as some compiler's definitions of is_pod aren't up to C++11 Standards. + //EASTL_CT_ASSERT(!is_pointer::value && !is_pointer::value); // Disabled because it's valid to alias pointers as long as you are aliasong the pointer value and not what it points to. + + union { + SourceType sourceValue; + DestType destValue; + } u; + u.sourceValue = sourceValue; + + return u.destValue; + } + + + + /////////////////////////////////////////////////////////////////////// + // void_t + // + // Maps a sequence of any types to void. This utility class is used in + // template meta programming to simplify compile time reflection mechanisms + // required by the standard library. + // + // http://en.cppreference.com/w/cpp/types/void_t + /////////////////////////////////////////////////////////////////////// + #if EASTL_VARIABLE_TEMPLATES_ENABLED + template + using void_t = void; + #endif + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/intrusive_hash_map.h b/libs/eastl/include/EASTL/intrusive_hash_map.h new file mode 100644 index 0000000..37f1618 --- /dev/null +++ b/libs/eastl/include/EASTL/intrusive_hash_map.h @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_INTRUSIVE_HASH_MAP_H +#define EASTL_INTRUSIVE_HASH_MAP_H + + +#include +#include +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// intrusive_hash_map + /// + /// Template parameters: + /// Key The key object (key in the key/value pair). T must contain a member of type Key named mKey. + /// T The type of object the map holds (a.k.a. value). + /// bucketCount The number of buckets to use. Best if it's a prime number. + /// Hash Hash function. See functional.h for examples of hash functions. + /// Equal Equality testing predicate; tells if two elements are equal. + /// + template , typename Equal = eastl::equal_to > + class intrusive_hash_map : public intrusive_hashtable + { + public: + typedef intrusive_hashtable base_type; + typedef intrusive_hash_map this_type; + + public: + explicit intrusive_hash_map(const Hash& h = Hash(), const Equal& eq = Equal()) + : base_type(h, eq) + { + // Empty + } + + // To consider: Is this feasible, given how initializer_list works by creating a temporary array? Even if it is feasible, is it a good idea? + //intrusive_hash_map(std::initializer_list ilist); + + }; // intrusive_hash_map + + + + + /// intrusive_hash_multimap + /// + /// Implements a intrusive_hash_multimap, which is the same thing as a intrusive_hash_map + /// except that contained elements need not be unique. See the documentation + /// for intrusive_hash_map for details. + /// + /// Template parameters: + /// Key The key object (key in the key/value pair). T must contain a member of type Key named mKey. + /// T The type of object the map holds (a.k.a. value). + /// bucketCount The number of buckets to use. Best if it's a prime number. + /// Hash Hash function. See functional.h for examples of hash functions. + /// Equal Equality testing predicate; tells if two elements are equal. + /// + template , typename Equal = eastl::equal_to > + class intrusive_hash_multimap : public intrusive_hashtable + { + public: + typedef intrusive_hashtable base_type; + typedef intrusive_hash_multimap this_type; + + public: + explicit intrusive_hash_multimap(const Hash& h = Hash(), const Equal& eq = Equal()) + : base_type(h, eq) + { + // Empty + } + + // To consider: Is this feasible, given how initializer_list works by creating a temporary array? Even if it is feasible, is it a good idea? + //intrusive_hash_multimap(std::initializer_list ilist); + + }; // intrusive_hash_multimap + + + + +} // namespace eastl + + +#endif // Header include guard + + + + + + diff --git a/libs/eastl/include/EASTL/intrusive_hash_set.h b/libs/eastl/include/EASTL/intrusive_hash_set.h new file mode 100644 index 0000000..a25d03a --- /dev/null +++ b/libs/eastl/include/EASTL/intrusive_hash_set.h @@ -0,0 +1,100 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_INTRUSIVE_HASH_SET_H +#define EASTL_INTRUSIVE_HASH_SET_H + + +#include +#include +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// intrusive_hash_set + /// + /// Template parameters: + /// T The type of object the set holds (a.k.a. value). + /// bucketCount The number of buckets to use. Best if it's a prime number. + /// Hash Hash function. See functional.h for examples of hash functions. + /// Equal Equality testing predicate; tells if two elements are equal. + /// + template , typename Equal = eastl::equal_to > + class intrusive_hash_set : public intrusive_hashtable + { + public: + typedef intrusive_hashtable base_type; + typedef intrusive_hash_set this_type; + + public: + explicit intrusive_hash_set(const Hash& h = Hash(), const Equal& eq = Equal()) + : base_type(h, eq) + { + // Empty + } + + // To consider: Is this feasible, given how initializer_list works by creating a temporary array? Even if it is feasible, is it a good idea? + //intrusive_hash_set(std::initializer_list ilist); + + }; // intrusive_hash_set + + + + + /// intrusive_hash_multiset + /// + /// Implements a intrusive_hash_multiset, which is the same thing as a intrusive_hash_set + /// except that contained elements need not be unique. See the documentation + /// for intrusive_hash_set for details. + /// + /// Template parameters: + /// T The type of object the set holds (a.k.a. value). + /// bucketCount The number of buckets to use. Best if it's a prime number. + /// Hash Hash function. See functional.h for examples of hash functions. + /// Equal Equality testing predicate; tells if two elements are equal. + /// + template , typename Equal = eastl::equal_to > + class intrusive_hash_multiset : public intrusive_hashtable + { + public: + typedef intrusive_hashtable base_type; + typedef intrusive_hash_multiset this_type; + + public: + explicit intrusive_hash_multiset(const Hash& h = Hash(), const Equal& eq = Equal()) + : base_type(h, eq) + { + // Empty + } + + // To consider: Is this feasible, given how initializer_list works by creating a temporary array? Even if it is feasible, is it a good idea? + //intrusive_hash_multiset(std::initializer_list ilist); + + }; // intrusive_hash_multiset + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/intrusive_list.h b/libs/eastl/include/EASTL/intrusive_list.h new file mode 100644 index 0000000..738de3f --- /dev/null +++ b/libs/eastl/include/EASTL/intrusive_list.h @@ -0,0 +1,1315 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// The intrusive list container is similar to a list, with the primary +// different being that intrusive lists allow you to control memory +// allocation. +// +// * Intrusive lists store the nodes directly in the data items. This +// is done by deriving the object from intrusive_list_node. +// +// * The container does no memory allocation -- it works entirely with +// the submitted nodes. This does mean that it is the client's job to +// free the nodes in an intrusive list, though. +// +// * Valid node pointers can be converted back to iterators in O(1). +// This is because objects in the list are also nodes in the list. +// +// * intrusive_list does not support copy construction or assignment; +// the push, pop, and insert operations take ownership of the +// passed object. +// +// Usage notes: +// +// * You can use an intrusive_list directly with the standard nodes +// if you have some other way of converting the node pointer back +// to your data pointer. +// +// * Remember that the list destructor doesn't deallocate nodes -- it can't. +// +// * The size is not cached; this makes size() linear time but splice() is +// constant time. This does mean that you can remove() an element without +// having to figure out which list it is in, however. +// +// * You can insert a node into multiple intrusive_lists. One way to do so +// is to (ab)use inheritance: +// +// struct NodeA : public intrusive_list_node {}; +// struct NodeB : public intrusive_list_node {}; +// struct Object : public NodeA, nodeB {}; +// +// intrusive_list listA; +// intrusive_list listB; +// +// listA.push_back(obj); +// listB.push_back(obj); +// +// * find() vs. locate() +// The find(v) algorithm returns an iterator p such that *p == v; intrusive_list::locate(v) +// returns an iterator p such that &*p == &v. intrusive_list<> doesn't have find() mainly +// because list<> doesn't have it either, but there's no reason it couldn't. intrusive_list +// uses the name 'find' because: +// - So as not to confuse the member function with the well-defined free function from algorithm.h. +// - Because it is not API-compatible with eastl::find(). +// - Because it simply locates an object within the list based on its node entry and doesn't p[erform before any value-based searches or comparisons. +// +// Differences between intrusive_list and std::list: +// +// Issue std::list intrusive_list +// -------------------------------------------------------------- +// Automatic node ctor/dtor Yes No +// Can memmove() container Maybe* No +// Same item in list twice Yes(copy/byref) No +// Can store non-copyable items No Yes +// size() O(1) or O(n) O(n) +// clear() O(n) O(1) +// erase(range) O(n) O(1) +// splice(range) O(1) or O(n) O(1) +// Convert reference to iterator No O(1) +// Remove without container No O(1) +// Nodes in mixed allocators No Yes +// +// *) Not required by standard but can be done with some STL implementations. +// +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTRUSIVE_LIST_H +#define EASTL_INTRUSIVE_LIST_H + + +#include +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// intrusive_list_node + /// + /// By design this must be a POD, as user structs will be inheriting from + /// it and they may wish to remain POD themselves. However, if the + /// EASTL_VALIDATE_INTRUSIVE_LIST option is enabled + /// + struct intrusive_list_node + { + intrusive_list_node* mpNext; + intrusive_list_node* mpPrev; + + #if EASTL_VALIDATE_INTRUSIVE_LIST + intrusive_list_node() // Implemented inline because GCC can't deal with member functions + { // of may-alias classes being defined outside the declaration. + mpNext = mpPrev = NULL; + } + + ~intrusive_list_node() + { + #if EASTL_ASSERT_ENABLED + if(mpNext || mpPrev) + EASTL_FAIL_MSG("~intrusive_list_node(): List is non-empty."); + #endif + } + #endif + } EASTL_MAY_ALIAS; // It's not clear if this really should be needed. An old GCC compatible compiler is generating some crashing optimized code when strict aliasing is enabled, but analysis of it seems to blame the compiler. However, this topic can be tricky. + + + + /// intrusive_list_iterator + /// + template + class intrusive_list_iterator + { + public: + typedef intrusive_list_iterator this_type; + typedef intrusive_list_iterator iterator; + typedef intrusive_list_iterator const_iterator; + typedef T value_type; + typedef T node_type; + typedef ptrdiff_t difference_type; + typedef Pointer pointer; + typedef Reference reference; + typedef EASTL_ITC_NS::bidirectional_iterator_tag iterator_category; + + public: + pointer mpNode; // Needs to be public for operator==() to work + + public: + intrusive_list_iterator(); + explicit intrusive_list_iterator(pointer pNode); // Note that you can also construct an iterator from T via this, since value_type == node_type. + intrusive_list_iterator(const iterator& x); + + reference operator*() const; + pointer operator->() const; + + intrusive_list_iterator& operator++(); + intrusive_list_iterator& operator--(); + + intrusive_list_iterator operator++(int); + intrusive_list_iterator operator--(int); + + }; // class intrusive_list_iterator + + + + /// intrusive_list_base + /// + class intrusive_list_base + { + public: + typedef eastl_size_t size_type; // See config.h for the definition of this, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + + protected: + intrusive_list_node mAnchor; ///< Sentinel node (end). All data nodes are linked in a ring from this node. + + public: + intrusive_list_base(); + ~intrusive_list_base(); + + bool empty() const EA_NOEXCEPT; + eastl_size_t size() const EA_NOEXCEPT; ///< Returns the number of elements in the list; O(n). + void clear() EA_NOEXCEPT; ///< Clears the list; O(1). No deallocation occurs. + void pop_front(); ///< Removes an element from the front of the list; O(1). The element must exist, but is not deallocated. + void pop_back(); ///< Removes an element from the back of the list; O(1). The element must exist, but is not deallocated. + EASTL_API void reverse() EA_NOEXCEPT; ///< Reverses a list so that front and back are swapped; O(n). + + EASTL_API bool validate() const; ///< Scans a list for linkage inconsistencies; O(n) time, O(1) space. Returns false if errors are detected, such as loops or branching. + + }; // class intrusive_list_base + + + + /// intrusive_list + /// + /// Example usage: + /// struct IntNode : public eastl::intrusive_list_node { + /// int mX; + /// IntNode(int x) : mX(x) { } + /// }; + /// + /// IntNode nodeA(0); + /// IntNode nodeB(1); + /// + /// intrusive_list intList; + /// intList.push_back(nodeA); + /// intList.push_back(nodeB); + /// intList.remove(nodeA); + /// + template + class intrusive_list : public intrusive_list_base + { + public: + typedef intrusive_list this_type; + typedef intrusive_list_base base_type; + typedef T node_type; + typedef T value_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef intrusive_list_iterator iterator; + typedef intrusive_list_iterator const_iterator; + typedef eastl::reverse_iterator reverse_iterator; + typedef eastl::reverse_iterator const_reverse_iterator; + + public: + intrusive_list(); ///< Creates an empty list. + intrusive_list(const this_type& x); ///< Creates an empty list; ignores the argument. + //intrusive_list(std::initializer_list ilist); To consider: Is this feasible, given how initializer_list works by creating a temporary array? Even if it is feasible, is it a good idea? + + this_type& operator=(const this_type& x); ///< Clears the list; ignores the argument. + void swap(this_type&); ///< Swaps the contents of two intrusive lists; O(1). + + iterator begin() EA_NOEXCEPT; ///< Returns an iterator pointing to the first element in the list. + const_iterator begin() const EA_NOEXCEPT; ///< Returns a const_iterator pointing to the first element in the list. + const_iterator cbegin() const EA_NOEXCEPT; ///< Returns a const_iterator pointing to the first element in the list. + + iterator end() EA_NOEXCEPT; ///< Returns an iterator pointing one-after the last element in the list. + const_iterator end() const EA_NOEXCEPT; ///< Returns a const_iterator pointing one-after the last element in the list. + const_iterator cend() const EA_NOEXCEPT; ///< Returns a const_iterator pointing one-after the last element in the list. + + reverse_iterator rbegin() EA_NOEXCEPT; ///< Returns a reverse_iterator pointing at the end of the list (start of the reverse sequence). + const_reverse_iterator rbegin() const EA_NOEXCEPT; ///< Returns a const_reverse_iterator pointing at the end of the list (start of the reverse sequence). + const_reverse_iterator crbegin() const EA_NOEXCEPT; ///< Returns a const_reverse_iterator pointing at the end of the list (start of the reverse sequence). + + reverse_iterator rend() EA_NOEXCEPT; ///< Returns a reverse_iterator pointing at the start of the list (end of the reverse sequence). + const_reverse_iterator rend() const EA_NOEXCEPT; ///< Returns a const_reverse_iterator pointing at the start of the list (end of the reverse sequence). + const_reverse_iterator crend() const EA_NOEXCEPT; ///< Returns a const_reverse_iterator pointing at the start of the list (end of the reverse sequence). + + reference front(); ///< Returns a reference to the first element. The list must be non-empty. + const_reference front() const; ///< Returns a const reference to the first element. The list must be non-empty. + reference back(); ///< Returns a reference to the last element. The list must be non-empty. + const_reference back() const; ///< Returns a const reference to the last element. The list must be non-empty. + + void push_front(value_type& x); ///< Adds an element to the front of the list; O(1). The element is not copied. The element must not be in any other list. + void push_back(value_type& x); ///< Adds an element to the back of the list; O(1). The element is not copied. The element must not be in any other list. + + bool contains(const value_type& x) const; ///< Returns true if the given element is in the list; O(n). Equivalent to (locate(x) != end()). + + iterator locate(value_type& x); ///< Converts a reference to an object in the list back to an iterator, or returns end() if it is not part of the list. O(n) + const_iterator locate(const value_type& x) const; ///< Converts a const reference to an object in the list back to a const iterator, or returns end() if it is not part of the list. O(n) + + iterator insert(const_iterator pos, value_type& x); ///< Inserts an element before the element pointed to by the iterator. O(1) + iterator erase(const_iterator pos); ///< Erases the element pointed to by the iterator. O(1) + iterator erase(const_iterator pos, const_iterator last); ///< Erases elements within the iterator range [pos, last). O(1) + + reverse_iterator erase(const_reverse_iterator pos); + reverse_iterator erase(const_reverse_iterator pos, const_reverse_iterator last); + + static void remove(value_type& value); ///< Erases an element from a list; O(1). Note that this is static so you don't need to know which list the element, although it must be in some list. + + void splice(const_iterator pos, value_type& x); + ///< Moves the given element into this list before the element pointed to by pos; O(1). + ///< Required: x must be in some list or have first/next pointers that point it itself. + + void splice(const_iterator pos, intrusive_list& x); + ///< Moves the contents of a list into this list before the element pointed to by pos; O(1). + ///< Required: &x != this (same as std::list). + + void splice(const_iterator pos, intrusive_list& x, const_iterator i); + ///< Moves the given element pointed to i within the list x into the current list before + ///< the element pointed to by pos; O(1). + + void splice(const_iterator pos, intrusive_list& x, const_iterator first, const_iterator last); + ///< Moves the range of elements [first, last) from list x into the current list before + ///< the element pointed to by pos; O(1). + ///< Required: pos must not be in [first, last). (same as std::list). + + public: + // Sorting functionality + // This is independent of the global sort algorithms, as lists are + // linked nodes and can be sorted more efficiently by moving nodes + // around in ways that global sort algorithms aren't privy to. + + void merge(this_type& x); + + template + void merge(this_type& x, Compare compare); + + void unique(); + + template + void unique(BinaryPredicate); + + void sort(); + + template + void sort(Compare compare); + + public: + // bool validate() const; // Inherited from parent. + int validate_iterator(const_iterator i) const; + + }; // intrusive_list + + + + + /////////////////////////////////////////////////////////////////////// + // intrusive_list_node + /////////////////////////////////////////////////////////////////////// + + // Moved to be inline within the class because the may-alias attribute is + // triggering what appears to be a bug in GCC that effectively requires + // may-alias structs to implement inline member functions within the class + // declaration. We don't have a .cpp file for + // #if EASTL_VALIDATE_INTRUSIVE_LIST + // inline intrusive_list_node::intrusive_list_node() + // { + // mpNext = mpPrev = NULL; + // } + // + // inline intrusive_list_node::~intrusive_list_node() + // { + // #if EASTL_ASSERT_ENABLED + // if(mpNext || mpPrev) + // EASTL_FAIL_MSG("~intrusive_list_node(): List is non-empty."); + // #endif + // } + // #endif + + + /////////////////////////////////////////////////////////////////////// + // intrusive_list_iterator + /////////////////////////////////////////////////////////////////////// + + template + inline intrusive_list_iterator::intrusive_list_iterator() + { + #if EASTL_DEBUG + mpNode = NULL; + #endif + } + + + template + inline intrusive_list_iterator::intrusive_list_iterator(pointer pNode) + : mpNode(pNode) + { + // Empty + } + + + template + inline intrusive_list_iterator::intrusive_list_iterator(const iterator& x) + : mpNode(x.mpNode) + { + // Empty + } + + + template + inline typename intrusive_list_iterator::reference + intrusive_list_iterator::operator*() const + { + return *mpNode; + } + + + template + inline typename intrusive_list_iterator::pointer + intrusive_list_iterator::operator->() const + { + return mpNode; + } + + + template + inline typename intrusive_list_iterator::this_type& + intrusive_list_iterator::operator++() + { + mpNode = static_cast(mpNode->mpNext); + return *this; + } + + + template + inline typename intrusive_list_iterator::this_type + intrusive_list_iterator::operator++(int) + { + intrusive_list_iterator it(*this); + mpNode = static_cast(mpNode->mpNext); + return it; + } + + + template + inline typename intrusive_list_iterator::this_type& + intrusive_list_iterator::operator--() + { + mpNode = static_cast(mpNode->mpPrev); + return *this; + } + + + template + inline typename intrusive_list_iterator::this_type + intrusive_list_iterator::operator--(int) + { + intrusive_list_iterator it(*this); + mpNode = static_cast(mpNode->mpPrev); + return it; + } + + + // The C++ defect report #179 requires that we support comparisons between const and non-const iterators. + // Thus we provide additional template paremeters here to support this. The defect report does not + // require us to support comparisons between reverse_iterators and const_reverse_iterators. + template + inline bool operator==(const intrusive_list_iterator& a, + const intrusive_list_iterator& b) + { + return a.mpNode == b.mpNode; + } + + + template + inline bool operator!=(const intrusive_list_iterator& a, + const intrusive_list_iterator& b) + { + return a.mpNode != b.mpNode; + } + + + // We provide a version of operator!= for the case where the iterators are of the + // same type. This helps prevent ambiguity errors in the presence of rel_ops. + template + inline bool operator!=(const intrusive_list_iterator& a, + const intrusive_list_iterator& b) + { + return a.mpNode != b.mpNode; + } + + + + + /////////////////////////////////////////////////////////////////////// + // intrusive_list_base + /////////////////////////////////////////////////////////////////////// + + inline intrusive_list_base::intrusive_list_base() + { + mAnchor.mpNext = mAnchor.mpPrev = &mAnchor; + } + + inline intrusive_list_base::~intrusive_list_base() + { + #if EASTL_VALIDATE_INTRUSIVE_LIST + clear(); + mAnchor.mpNext = mAnchor.mpPrev = NULL; + #endif + } + + + inline bool intrusive_list_base::empty() const EA_NOEXCEPT + { + return mAnchor.mpPrev == &mAnchor; + } + + + inline intrusive_list_base::size_type intrusive_list_base::size() const EA_NOEXCEPT + { + const intrusive_list_node* p = &mAnchor; + size_type n = (size_type)-1; + + do { + ++n; + p = p->mpNext; + } while(p != &mAnchor); + + return n; + } + + + inline void intrusive_list_base::clear() EA_NOEXCEPT + { + #if EASTL_VALIDATE_INTRUSIVE_LIST + // Need to clear out all the next/prev pointers in the elements; + // this makes this operation O(n) instead of O(1). + intrusive_list_node* pNode = mAnchor.mpNext; + + while(pNode != &mAnchor) + { + intrusive_list_node* const pNextNode = pNode->mpNext; + pNode->mpNext = pNode->mpPrev = NULL; + pNode = pNextNode; + } + #endif + + mAnchor.mpNext = mAnchor.mpPrev = &mAnchor; + } + + + inline void intrusive_list_base::pop_front() + { + #if EASTL_VALIDATE_INTRUSIVE_LIST + intrusive_list_node* const pNode = mAnchor.mpNext; + #endif + + mAnchor.mpNext->mpNext->mpPrev = &mAnchor; + mAnchor.mpNext = mAnchor.mpNext->mpNext; + + #if EASTL_VALIDATE_INTRUSIVE_LIST + if(pNode != &mAnchor) + pNode->mpNext = pNode->mpPrev = NULL; + #if EASTL_ASSERT_ENABLED + else + EASTL_FAIL_MSG("intrusive_list::pop_front(): empty list."); + #endif + #endif + } + + + inline void intrusive_list_base::pop_back() + { + #if EASTL_VALIDATE_INTRUSIVE_LIST + intrusive_list_node* const pNode = mAnchor.mpPrev; + #endif + + mAnchor.mpPrev->mpPrev->mpNext = &mAnchor; + mAnchor.mpPrev = mAnchor.mpPrev->mpPrev; + + #if EASTL_VALIDATE_INTRUSIVE_LIST + if(pNode != &mAnchor) + pNode->mpNext = pNode->mpPrev = NULL; + #if EASTL_ASSERT_ENABLED + else + EASTL_FAIL_MSG("intrusive_list::pop_back(): empty list."); + #endif + #endif + } + + + + + /////////////////////////////////////////////////////////////////////// + // intrusive_list + /////////////////////////////////////////////////////////////////////// + + template + inline intrusive_list::intrusive_list() + { + } + + + template + inline intrusive_list::intrusive_list(const this_type& /*x*/) + : intrusive_list_base() + { + // We intentionally ignore argument x. + // To consider: Shouldn't this function simply not exist? Is there a useful purpose for having this function? + // There should be a comment here about it, though my first guess is that this exists to quell VC++ level 4/-Wall compiler warnings. + } + + + template + inline typename intrusive_list::this_type& intrusive_list::operator=(const this_type& /*x*/) + { + // We intentionally ignore argument x. + // See notes above in the copy constructor about questioning the existence of this function. + return *this; + } + + + template + inline typename intrusive_list::iterator intrusive_list::begin() EA_NOEXCEPT + { + return iterator(static_cast(mAnchor.mpNext)); + } + + + template + inline typename intrusive_list::const_iterator intrusive_list::begin() const EA_NOEXCEPT + { + return const_iterator(static_cast(mAnchor.mpNext)); + } + + + template + inline typename intrusive_list::const_iterator intrusive_list::cbegin() const EA_NOEXCEPT + { + return const_iterator(static_cast(mAnchor.mpNext)); + } + + + template + inline typename intrusive_list::iterator intrusive_list::end() EA_NOEXCEPT + { + return iterator(static_cast(&mAnchor)); + } + + + template + inline typename intrusive_list::const_iterator intrusive_list::end() const EA_NOEXCEPT + { + return const_iterator(static_cast(&mAnchor)); + } + + + template + inline typename intrusive_list::const_iterator intrusive_list::cend() const EA_NOEXCEPT + { + return const_iterator(static_cast(&mAnchor)); + } + + + template + inline typename intrusive_list::reverse_iterator intrusive_list::rbegin() EA_NOEXCEPT + { + return reverse_iterator(iterator(static_cast(&mAnchor))); + } + + + template + inline typename intrusive_list::const_reverse_iterator intrusive_list::rbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(const_iterator(static_cast(&mAnchor))); + } + + + template + inline typename intrusive_list::const_reverse_iterator intrusive_list::crbegin() const EA_NOEXCEPT + { + return const_reverse_iterator(const_iterator(static_cast(&mAnchor))); + } + + + template + inline typename intrusive_list::reverse_iterator intrusive_list::rend() EA_NOEXCEPT + { + return reverse_iterator(iterator(static_cast(mAnchor.mpNext))); + } + + + template + inline typename intrusive_list::const_reverse_iterator intrusive_list::rend() const EA_NOEXCEPT + { + return const_reverse_iterator(const_iterator(static_cast(mAnchor.mpNext))); + } + + + template + inline typename intrusive_list::const_reverse_iterator intrusive_list::crend() const EA_NOEXCEPT + { + return const_reverse_iterator(const_iterator(static_cast(mAnchor.mpNext))); + } + + + template + inline typename intrusive_list::reference intrusive_list::front() + { + #if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED + if(mAnchor.mpNext == &mAnchor) + EASTL_FAIL_MSG("intrusive_list::front(): empty list."); + #endif + + return *static_cast(mAnchor.mpNext); + } + + + template + inline typename intrusive_list::const_reference intrusive_list::front() const + { + #if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED + if(mAnchor.mpNext == &mAnchor) + EASTL_FAIL_MSG("intrusive_list::front(): empty list."); + #endif + + return *static_cast(mAnchor.mpNext); + } + + + template + inline typename intrusive_list::reference intrusive_list::back() + { + #if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED + if(mAnchor.mpNext == &mAnchor) + EASTL_FAIL_MSG("intrusive_list::back(): empty list."); + #endif + + return *static_cast(mAnchor.mpPrev); + } + + + template + inline typename intrusive_list::const_reference intrusive_list::back() const + { + #if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED + if(mAnchor.mpNext == &mAnchor) + EASTL_FAIL_MSG("intrusive_list::back(): empty list."); + #endif + + return *static_cast(mAnchor.mpPrev); + } + + + template + inline void intrusive_list::push_front(value_type& x) + { + #if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED + if(x.mpNext || x.mpPrev) + EASTL_FAIL_MSG("intrusive_list::push_front(): element already on a list."); + #endif + + x.mpNext = mAnchor.mpNext; + x.mpPrev = &mAnchor; + mAnchor.mpNext = &x; + x.mpNext->mpPrev = &x; + } + + + template + inline void intrusive_list::push_back(value_type& x) + { + #if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED + if(x.mpNext || x.mpPrev) + EASTL_FAIL_MSG("intrusive_list::push_back(): element already on a list."); + #endif + + x.mpPrev = mAnchor.mpPrev; + x.mpNext = &mAnchor; + mAnchor.mpPrev = &x; + x.mpPrev->mpNext = &x; + } + + + template + inline bool intrusive_list::contains(const value_type& x) const + { + for(const intrusive_list_node* p = mAnchor.mpNext; p != &mAnchor; p = p->mpNext) + { + if(p == &x) + return true; + } + + return false; + } + + + template + inline typename intrusive_list::iterator intrusive_list::locate(value_type& x) + { + for(intrusive_list_node* p = (T*)mAnchor.mpNext; p != &mAnchor; p = p->mpNext) + { + if(p == &x) + return iterator(static_cast(p)); + } + + return iterator((T*)&mAnchor); + } + + + template + inline typename intrusive_list::const_iterator intrusive_list::locate(const value_type& x) const + { + for(const intrusive_list_node* p = mAnchor.mpNext; p != &mAnchor; p = p->mpNext) + { + if(p == &x) + return const_iterator(static_cast(p)); + } + + return const_iterator((T*)&mAnchor); + } + + + template + inline typename intrusive_list::iterator intrusive_list::insert(const_iterator pos, value_type& x) + { + #if EASTL_VALIDATE_INTRUSIVE_LIST && EASTL_ASSERT_ENABLED + if(x.mpNext || x.mpPrev) + EASTL_FAIL_MSG("intrusive_list::insert(): element already on a list."); + #endif + + node_type& next = *const_cast(pos.mpNode); + node_type& prev = *static_cast(next.mpPrev); + prev.mpNext = next.mpPrev = &x; + x.mpPrev = &prev; + x.mpNext = &next; + + return iterator(&x); + } + + + template + inline typename intrusive_list::iterator + intrusive_list::erase(const_iterator pos) + { + node_type& prev = *static_cast(pos.mpNode->mpPrev); + node_type& next = *static_cast(pos.mpNode->mpNext); + prev.mpNext = &next; + next.mpPrev = &prev; + + #if EASTL_VALIDATE_INTRUSIVE_LIST + iterator ii(const_cast(pos.mpNode)); + ii.mpNode->mpPrev = ii.mpNode->mpNext = NULL; + #endif + + return iterator(&next); + } + + + template + inline typename intrusive_list::iterator + intrusive_list::erase(const_iterator first, const_iterator last) + { + node_type& prev = *static_cast(first.mpNode->mpPrev); + node_type& next = *const_cast(last.mpNode); + + #if EASTL_VALIDATE_INTRUSIVE_LIST + // need to clear out all the next/prev pointers in the elements; + // this makes this operation O(n) instead of O(1), sadly, although + // it's technically amortized O(1) since you could count yourself + // as paying this cost with each insert. + intrusive_list_node* pCur = const_cast(first.mpNode); + + while(pCur != &next) + { + intrusive_list_node* const pCurNext = pCur->mpNext; + pCur->mpPrev = pCur->mpNext = NULL; + pCur = pCurNext; + } + #endif + + prev.mpNext = &next; + next.mpPrev = &prev; + + return iterator(const_cast(last.mpNode)); + } + + + template + inline typename intrusive_list::reverse_iterator + intrusive_list::erase(const_reverse_iterator position) + { + return reverse_iterator(erase((++position).base())); + } + + + template + inline typename intrusive_list::reverse_iterator + intrusive_list::erase(const_reverse_iterator first, const_reverse_iterator last) + { + // Version which erases in order from first to last. + // difference_type i(first.base() - last.base()); + // while(i--) + // first = erase(first); + // return first; + + // Version which erases in order from last to first, but is slightly more efficient: + return reverse_iterator(erase((++last).base(), (++first).base())); + } + + + template + void intrusive_list::swap(intrusive_list& x) + { + // swap anchors + intrusive_list_node temp(mAnchor); + mAnchor = x.mAnchor; + x.mAnchor = temp; + + // Fixup node pointers into the anchor, since the addresses of + // the anchors must stay the same with each list. + if(mAnchor.mpNext == &x.mAnchor) + mAnchor.mpNext = mAnchor.mpPrev = &mAnchor; + else + mAnchor.mpNext->mpPrev = mAnchor.mpPrev->mpNext = &mAnchor; + + if(x.mAnchor.mpNext == &mAnchor) + x.mAnchor.mpNext = x.mAnchor.mpPrev = &x.mAnchor; + else + x.mAnchor.mpNext->mpPrev = x.mAnchor.mpPrev->mpNext = &x.mAnchor; + + #if EASTL_VALIDATE_INTRUSIVE_LIST + temp.mpPrev = temp.mpNext = NULL; + #endif + } + + + template + void intrusive_list::splice(const_iterator pos, value_type& value) + { + // Note that splice(pos, x, pos) and splice(pos+1, x, pos) + // are valid and need to be handled correctly. + + if(pos.mpNode != &value) + { + // Unlink item from old list. + intrusive_list_node& oldNext = *value.mpNext; + intrusive_list_node& oldPrev = *value.mpPrev; + oldNext.mpPrev = &oldPrev; + oldPrev.mpNext = &oldNext; + + // Relink item into new list. + intrusive_list_node& newNext = *const_cast(pos.mpNode); + intrusive_list_node& newPrev = *newNext.mpPrev; + + newPrev.mpNext = &value; + newNext.mpPrev = &value; + value.mpPrev = &newPrev; + value.mpNext = &newNext; + } + } + + + template + void intrusive_list::splice(const_iterator pos, intrusive_list& x) + { + // Note: &x == this is prohibited, so self-insertion is not a problem. + if(x.mAnchor.mpNext != &x.mAnchor) // If the list 'x' isn't empty... + { + node_type& next = *const_cast(pos.mpNode); + node_type& prev = *static_cast(next.mpPrev); + node_type& insertPrev = *static_cast(x.mAnchor.mpNext); + node_type& insertNext = *static_cast(x.mAnchor.mpPrev); + + prev.mpNext = &insertPrev; + insertPrev.mpPrev = &prev; + insertNext.mpNext = &next; + next.mpPrev = &insertNext; + x.mAnchor.mpPrev = x.mAnchor.mpNext = &x.mAnchor; + } + } + + + template + void intrusive_list::splice(const_iterator pos, intrusive_list& /*x*/, const_iterator i) + { + // Note: &x == this is prohibited, so self-insertion is not a problem. + + // Note that splice(pos, x, pos) and splice(pos + 1, x, pos) + // are valid and need to be handled correctly. + + // We don't need to check if the source list is empty, because + // this function expects a valid iterator from the source list, + // and thus the list cannot be empty in such a situation. + + iterator ii(const_cast(i.mpNode)); // Make a temporary non-const version. + + if(pos != ii) + { + // Unlink item from old list. + intrusive_list_node& oldNext = *ii.mpNode->mpNext; + intrusive_list_node& oldPrev = *ii.mpNode->mpPrev; + oldNext.mpPrev = &oldPrev; + oldPrev.mpNext = &oldNext; + + // Relink item into new list. + intrusive_list_node& newNext = *const_cast(pos.mpNode); + intrusive_list_node& newPrev = *newNext.mpPrev; + + newPrev.mpNext = ii.mpNode; + newNext.mpPrev = ii.mpNode; + ii.mpNode->mpPrev = &newPrev; + ii.mpNode->mpNext = &newNext; + } + } + + + template + void intrusive_list::splice(const_iterator pos, intrusive_list& /*x*/, const_iterator first, const_iterator last) + { + // Note: &x == this is prohibited, so self-insertion is not a problem. + if(first != last) + { + node_type& insertPrev = *const_cast(first.mpNode); + node_type& insertNext = *static_cast(last.mpNode->mpPrev); + + // remove from old list + insertNext.mpNext->mpPrev = insertPrev.mpPrev; + insertPrev.mpPrev->mpNext = insertNext.mpNext; + + // insert into this list + node_type& next = *const_cast(pos.mpNode); + node_type& prev = *static_cast(next.mpPrev); + + prev.mpNext = &insertPrev; + insertPrev.mpPrev = &prev; + insertNext.mpNext = &next; + next.mpPrev = &insertNext; + } + } + + + template + inline void intrusive_list::remove(value_type& value) + { + intrusive_list_node& prev = *value.mpPrev; + intrusive_list_node& next = *value.mpNext; + prev.mpNext = &next; + next.mpPrev = &prev; + + #if EASTL_VALIDATE_INTRUSIVE_LIST + value.mpPrev = value.mpNext = NULL; + #endif + } + + + template + void intrusive_list::merge(this_type& x) + { + if(this != &x) + { + iterator first(begin()); + iterator firstX(x.begin()); + const iterator last(end()); + const iterator lastX(x.end()); + + while((first != last) && (firstX != lastX)) + { + if(*firstX < *first) + { + iterator next(firstX); + + splice(first, x, firstX, ++next); + firstX = next; + } + else + ++first; + } + + if(firstX != lastX) + splice(last, x, firstX, lastX); + } + } + + + template + template + void intrusive_list::merge(this_type& x, Compare compare) + { + if(this != &x) + { + iterator first(begin()); + iterator firstX(x.begin()); + const iterator last(end()); + const iterator lastX(x.end()); + + while((first != last) && (firstX != lastX)) + { + if(compare(*firstX, *first)) + { + iterator next(firstX); + + splice(first, x, firstX, ++next); + firstX = next; + } + else + ++first; + } + + if(firstX != lastX) + splice(last, x, firstX, lastX); + } + } + + + template + void intrusive_list::unique() + { + iterator first(begin()); + const iterator last(end()); + + if(first != last) + { + iterator next(first); + + while(++next != last) + { + if(*first == *next) + erase(next); + else + first = next; + next = first; + } + } + } + + + template + template + void intrusive_list::unique(BinaryPredicate predicate) + { + iterator first(begin()); + const iterator last(end()); + + if(first != last) + { + iterator next(first); + + while(++next != last) + { + if(predicate(*first, *next)) + erase(next); + else + first = next; + next = first; + } + } + } + + + template + void intrusive_list::sort() + { + // We implement the algorithm employed by Chris Caulfield whereby we use recursive + // function calls to sort the list. The sorting of a very large list may fail due to stack overflow + // if the stack is exhausted. The limit depends on the platform and the avaialble stack space. + + // Easier-to-understand version of the 'if' statement: + // iterator i(begin()); + // if((i != end()) && (++i != end())) // If the size is >= 2 (without calling the more expensive size() function)... + + // Faster, more inlinable version of the 'if' statement: + if((static_cast(mAnchor.mpNext) != &mAnchor) && + (static_cast(mAnchor.mpNext) != static_cast(mAnchor.mpPrev))) + { + // Split the array into 2 roughly equal halves. + this_type leftList; // This should cause no memory allocation. + this_type rightList; + + // We find an iterator which is in the middle of the list. The fastest way to do + // this is to iterate from the base node both forwards and backwards with two + // iterators and stop when they meet each other. Recall that our size() function + // is not O(1) but is instead O(n), at least when EASTL_LIST_SIZE_CACHE is disabled. + #if EASTL_LIST_SIZE_CACHE + iterator mid(begin()); + eastl::advance(mid, size() / 2); + #else + iterator mid(begin()), tail(end()); + + while((mid != tail) && (++mid != tail)) + --tail; + #endif + + // Move the left half of this into leftList and the right half into rightList. + leftList.splice(leftList.begin(), *this, begin(), mid); + rightList.splice(rightList.begin(), *this); + + // Sort the sub-lists. + leftList.sort(); + rightList.sort(); + + // Merge the two halves into this list. + splice(begin(), leftList); + merge(rightList); + } + } + + + template + template + void intrusive_list::sort(Compare compare) + { + // We implement the algorithm employed by Chris Caulfield whereby we use recursive + // function calls to sort the list. The sorting of a very large list may fail due to stack overflow + // if the stack is exhausted. The limit depends on the platform and the avaialble stack space. + + // Easier-to-understand version of the 'if' statement: + // iterator i(begin()); + // if((i != end()) && (++i != end())) // If the size is >= 2 (without calling the more expensive size() function)... + + // Faster, more inlinable version of the 'if' statement: + if((static_cast(mAnchor.mpNext) != &mAnchor) && + (static_cast(mAnchor.mpNext) != static_cast(mAnchor.mpPrev))) + { + // Split the array into 2 roughly equal halves. + this_type leftList; // This should cause no memory allocation. + this_type rightList; + + // We find an iterator which is in the middle of the list. The fastest way to do + // this is to iterate from the base node both forwards and backwards with two + // iterators and stop when they meet each other. Recall that our size() function + // is not O(1) but is instead O(n), at least when EASTL_LIST_SIZE_CACHE is disabled. + #if EASTL_LIST_SIZE_CACHE + iterator mid(begin()); + eastl::advance(mid, size() / 2); + #else + iterator mid(begin()), tail(end()); + + while((mid != tail) && (++mid != tail)) + --tail; + #endif + + // Move the left half of this into leftList and the right half into rightList. + leftList.splice(leftList.begin(), *this, begin(), mid); + rightList.splice(rightList.begin(), *this); + + // Sort the sub-lists. + leftList.sort(compare); + rightList.sort(compare); + + // Merge the two halves into this list. + splice(begin(), leftList); + merge(rightList, compare); + } + } + + + template + inline int intrusive_list::validate_iterator(const_iterator i) const + { + // To do: Come up with a more efficient mechanism of doing this. + + for(const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp) + { + if(temp == i) + return (isf_valid | isf_current | isf_can_dereference); + } + + if(i == end()) + return (isf_valid | isf_current); + + return isf_none; + } + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + bool operator==(const intrusive_list& a, const intrusive_list& b) + { + // If we store an mSize member for intrusive_list, we want to take advantage of it here. + typename intrusive_list::const_iterator ia = a.begin(); + typename intrusive_list::const_iterator ib = b.begin(); + typename intrusive_list::const_iterator enda = a.end(); + typename intrusive_list::const_iterator endb = b.end(); + + while((ia != enda) && (ib != endb) && (*ia == *ib)) + { + ++ia; + ++ib; + } + return (ia == enda) && (ib == endb); + } + + template + bool operator!=(const intrusive_list& a, const intrusive_list& b) + { + return !(a == b); + } + + template + bool operator<(const intrusive_list& a, const intrusive_list& b) + { + return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); + } + + template + bool operator>(const intrusive_list& a, const intrusive_list& b) + { + return b < a; + } + + template + bool operator<=(const intrusive_list& a, const intrusive_list& b) + { + return !(b < a); + } + + template + bool operator>=(const intrusive_list& a, const intrusive_list& b) + { + return !(a < b); + } + + template + void swap(intrusive_list& a, intrusive_list& b) + { + a.swap(b); + } + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/intrusive_ptr.h b/libs/eastl/include/EASTL/intrusive_ptr.h new file mode 100644 index 0000000..12f838d --- /dev/null +++ b/libs/eastl/include/EASTL/intrusive_ptr.h @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_INTRUSIVE_PTR_H +#define EASTL_INTRUSIVE_PTR_H + + +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + // We provide default implementations of AddRef and Release in the eastl namespace. + // The user can override these on a per-class basis by defining their own specialized + // intrusive_ptr_add_ref and intrusive_ptr_release functions. User-defined specializations + // do not need to exist in the eastl namespace, but should preferably be in the namespace + // of the templated class T. + template + void intrusive_ptr_add_ref(T* p) + { + p->AddRef(); + } + + template + void intrusive_ptr_release(T* p) + { + p->Release(); + } + + + ////////////////////////////////////////////////////////////////////////////// + /// intrusive_ptr + /// + /// This is a class that acts like the C++ auto_ptr class except that instead + /// of deleting its member data when it goes out of scope, it Releases its + /// member data when it goes out of scope. This class thus requires that the + /// templated data type have an AddRef and Release function (or whatever is + /// configured to be the two refcount functions). + /// + /// This class is useful for automatically releasing an object when this + /// class goes out of scope. See below for some usage. + /// You should be careful about putting instances of this class as members of + /// another class. If you do so, then the intrusive_ptr destructor will only + /// be called if the object that owns it is destructed. This creates a potential + /// chicken-and-egg situation. What if the intrusive_ptr member contains a + /// pointer to an object that has a reference on the object that owns the + /// intrusive_ptr member? The answer is that the neither object can ever be + /// destructed. The solution is to: + /// 1) Be very careful about what objects you put into member intrusive_ptr objects. + /// 2) Clear out your intrusive_ptr members in your shutdown function. + /// 3) Simply don't use intrusive_ptr objects as class members. + /// + /// Example usage: + /// intrusive_ptr pWidget = new Widget; + /// pWidget = new Widget; + /// pWidget->Reset(); + /// + template + class intrusive_ptr + { + + protected: + // Friend declarations. + template friend class intrusive_ptr; + typedef intrusive_ptr this_type; + + T* mpObject; + + public: + /// element_type + /// This typedef is present for consistency with the C++ standard library + /// auto_ptr template. It allows users to refer to the templated type via + /// a typedef. This is sometimes useful to be able to do. + /// + /// Example usage: + /// intrusive_ptr ip; + /// void DoSomething(intrusive_ptr::element_type someType); + /// + typedef T element_type; + + /// intrusive_ptr + /// Default constructor. The member object is set to NULL. + intrusive_ptr() + : mpObject(NULL) + { + // Empty + } + + /// intrusive_ptr + /// Provides a constructor which takes ownership of a pointer. + /// The incoming pointer is AddRefd. + /// + /// Example usage: + /// intrusive_ptr pWidget(new Widget); + intrusive_ptr(T* p, bool bAddRef = true) + : mpObject(p) + { + if(mpObject && bAddRef) + intrusive_ptr_add_ref(mpObject); // Intentionally do not prefix the call with eastl:: but instead allow namespace lookup to resolve the namespace. + } + + /// intrusive_ptr + /// Construction from self type. + intrusive_ptr(const intrusive_ptr& ip) + : mpObject(ip.mpObject) + { + if(mpObject) + intrusive_ptr_add_ref(mpObject); + } + + /// intrusive_ptr + /// Provides a constructor which copies a pointer from another intrusive_ptr. + /// The incoming pointer is AddRefd. The source intrusive_ptr object maintains + /// its AddRef on the pointer. + /// + /// Example usage: + /// intrusive_ptr pWidget1; + /// intrusive_ptr pWidget2(pWidget1); + template + intrusive_ptr(const intrusive_ptr& ip) + : mpObject(ip.mpObject) + { + if(mpObject) + intrusive_ptr_add_ref(mpObject); + } + + /// intrusive_ptr + /// Releases the owned pointer. + ~intrusive_ptr() + { + if(mpObject) + intrusive_ptr_release(mpObject); + } + + + /// operator = + /// Assignment to self type. + intrusive_ptr& operator=(const intrusive_ptr& ip) + { + return operator=(ip.mpObject); + } + + + /// operator = + /// Assigns an intrusive_ptr object to this intrusive_ptr object. + /// The incoming pointer is AddRefd. The source intrusive_ptr object + /// maintains its AddRef on the pointer. If there is an existing member + /// pointer, it is Released before the incoming pointer is assigned. + /// If the incoming pointer is equal to the existing pointer, no + /// action is taken. The incoming pointer is AddRefd before any + /// member pointer is Released. + template + intrusive_ptr& operator=(const intrusive_ptr& ip) + { + return operator=(ip.mpObject); + } + + /// operator= + /// Assigns an intrusive_ptr object to this intrusive_ptr object. + /// The incoming pointer is AddRefd. If there is an existing member + /// pointer, it is Released before the incoming pointer is assigned. + /// If the incoming pointer is equal to the existing pointer, no + /// action is taken. The incoming pointer is AddRefd before any + /// member pointer is Released. + intrusive_ptr& operator=(T* pObject) + { + if(pObject != mpObject) + { + T* const pTemp = mpObject; // Create temporary to prevent possible problems with re-entrancy. + if(pObject) + intrusive_ptr_add_ref(pObject); + mpObject = pObject; + if(pTemp) + intrusive_ptr_release(pTemp); + } + return *this; + } + + /// operator * + /// Returns a reference to the contained object. + T& operator *() const + { + return *mpObject; + } + + /// operator * + /// Returns a pointer to the contained object, allowing the + /// user to use this container as if it were contained pointer itself. + T* operator ->() const + { + return mpObject; + } + + /// get() + /// Returns a pointer to the contained object. + T* get() const + { + return mpObject; + } + + /// reset + /// Releases the owned object and clears our reference to it. + void reset() + { + T* const pTemp = mpObject; + mpObject = NULL; + if(pTemp) + intrusive_ptr_release(pTemp); + } + + /// swap + /// Exchanges the owned pointer beween two intrusive_ptr objects. + void swap(this_type& ip) + { + T* const pTemp = mpObject; + mpObject = ip.mpObject; + ip.mpObject = pTemp; + } + + /// attach + /// Sets an intrusive_ptr pointer without calling AddRef() on + /// the pointed object. The intrusive_ptr thus eventually only does a + /// Release() on the object. This is useful for assuming a reference + /// that someone else has handed you and making sure it is always + /// released, even if you return in the middle of a function or an + /// exception is thrown. + /// + void attach(T* pObject) + { + T* const pTemp = mpObject; + mpObject = pObject; + if(pTemp) + intrusive_ptr_release(pTemp); + } + + /// detach + /// Surrenders the reference held by an intrusive_ptr pointer -- + /// it returns the current reference and nulls the pointer. If the returned + /// pointer is non-null it must be released. This is useful in functions + /// that must return a reference while possibly being aborted by a return + /// or thrown exception: + /// + /// bool GetFoo(T** pp){ + /// intrusive_ptr p(PrivateGetFoo()); + /// if(p->Method()) + /// return false; + /// *pp = p.detach(); + /// return true; + /// } + T* detach() + { + T* const pTemp = mpObject; + mpObject = NULL; + return pTemp; + } + + /// Implicit operator bool + /// Allows for using a intrusive_ptr as a boolean. + /// Example usage: + /// intrusive_ptr ptr = new Widget; + /// if(ptr) + /// ++*ptr; + /// + /// Note that below we do not use operator bool(). The reason for this + /// is that booleans automatically convert up to short, int, float, etc. + /// The result is that this: if(intrusivePtr == 1) would yield true (bad). + typedef T* (this_type::*bool_)() const; + operator bool_() const + { + if(mpObject) + return &this_type::get; + return NULL; + } + + /// operator! + /// This returns the opposite of operator bool; it returns true if + /// the owned pointer is null. Some compilers require this and some don't. + /// intrusive_ptr ptr = new Widget; + /// if(!ptr) + /// assert(false); + bool operator!() const + { + return (mpObject == NULL); + } + + }; // class intrusive_ptr + + + /// get_pointer + /// returns intrusive_ptr::get() via the input intrusive_ptr. + template + inline T* get_pointer(const intrusive_ptr& intrusivePtr) + { + return intrusivePtr.get(); + } + + /// swap + /// Exchanges the owned pointer beween two intrusive_ptr objects. + /// This non-member version is useful for compatibility of intrusive_ptr + /// objects with the C++ Standard Library and other libraries. + template + inline void swap(intrusive_ptr& intrusivePtr1, intrusive_ptr& intrusivePtr2) + { + intrusivePtr1.swap(intrusivePtr2); + } + + + template + bool operator==(intrusive_ptr const& iPtr1, intrusive_ptr const& iPtr2) + { + return (iPtr1.get() == iPtr2.get()); + } + + template + bool operator!=(intrusive_ptr const& iPtr1, intrusive_ptr const& iPtr2) + { + return (iPtr1.get() != iPtr2.get()); + } + + template + bool operator==(intrusive_ptr const& iPtr1, T* p) + { + return (iPtr1.get() == p); + } + + template + bool operator!=(intrusive_ptr const& iPtr1, T* p) + { + return (iPtr1.get() != p); + } + + template + bool operator==(T* p, intrusive_ptr const& iPtr2) + { + return (p == iPtr2.get()); + } + + template + bool operator!=(T* p, intrusive_ptr const& iPtr2) + { + return (p != iPtr2.get()); + } + + template + bool operator<(intrusive_ptr const& iPtr1, intrusive_ptr const& iPtr2) + { + return ((uintptr_t)iPtr1.get() < (uintptr_t)iPtr2.get()); + } + + + /// static_pointer_cast + /// Returns an intrusive_ptr static-casted from a intrusive_ptr. + template + intrusive_ptr static_pointer_cast(const intrusive_ptr& intrusivePtr) + { + return static_cast(intrusivePtr.get()); + } + + + #if EASTL_RTTI_ENABLED + + /// dynamic_pointer_cast + /// Returns an intrusive_ptr dynamic-casted from a intrusive_ptr. + template + intrusive_ptr dynamic_pointer_cast(const intrusive_ptr& intrusivePtr) + { + return dynamic_cast(intrusivePtr.get()); + } + + #endif + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/iterator.h b/libs/eastl/include/EASTL/iterator.h new file mode 100644 index 0000000..f660b69 --- /dev/null +++ b/libs/eastl/include/EASTL/iterator.h @@ -0,0 +1,1303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_ITERATOR_H +#define EASTL_ITERATOR_H + + +#include +#include +#include + +#ifdef _MSC_VER + #pragma warning(push, 0) +#endif + +#include + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +// If the user has specified that we use std iterator +// categories instead of EASTL iterator categories, +// then #include . +#if EASTL_STD_ITERATOR_CATEGORY_ENABLED + #ifdef _MSC_VER + #pragma warning(push, 0) + #endif + #include + #ifdef _MSC_VER + #pragma warning(pop) + #endif +#endif + + +#ifdef _MSC_VER + #pragma warning(push) // VC++ generates a bogus warning that you cannot code away. + #pragma warning(disable: 4619) // There is no warning number 'number'. + #pragma warning(disable: 4217) // Member template functions cannot be used for copy-assignment or copy-construction. +#endif + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + /// iterator_status_flag + /// + /// Defines the validity status of an iterator. This is primarily used for + /// iterator validation in debug builds. These are implemented as OR-able + /// flags (as opposed to mutually exclusive values) in order to deal with + /// the nature of iterator status. In particular, an iterator may be valid + /// but not dereferencable, as in the case with an iterator to container end(). + /// An iterator may be valid but also dereferencable, as in the case with an + /// iterator to container begin(). + /// + enum iterator_status_flag + { + isf_none = 0x00, /// This is called none and not called invalid because it is not strictly the opposite of invalid. + isf_valid = 0x01, /// The iterator is valid, which means it is in the range of [begin, end]. + isf_current = 0x02, /// The iterator is valid and points to the same element it did when created. For example, if an iterator points to vector::begin() but an element is inserted at the front, the iterator is valid but not current. Modification of elements in place do not make iterators non-current. + isf_can_dereference = 0x04 /// The iterator is dereferencable, which means it is in the range of [begin, end). It may or may not be current. + }; + + + + // The following declarations are taken directly from the C++ standard document. + // input_iterator_tag, etc. + // iterator + // iterator_traits + // reverse_iterator + + // Iterator categories + // Every iterator is defined as belonging to one of the iterator categories that + // we define here. These categories come directly from the C++ standard. + #if !EASTL_STD_ITERATOR_CATEGORY_ENABLED // If we are to use our own iterator category definitions... + struct input_iterator_tag { }; + struct output_iterator_tag { }; + struct forward_iterator_tag : public input_iterator_tag { }; + struct bidirectional_iterator_tag : public forward_iterator_tag { }; + struct random_access_iterator_tag : public bidirectional_iterator_tag { }; + struct contiguous_iterator_tag : public random_access_iterator_tag { }; // Extension to the C++ standard. Contiguous ranges are more than random access, they are physically contiguous. + #endif + + + // struct iterator + template + struct iterator + { + typedef Category iterator_category; + typedef T value_type; + typedef Distance difference_type; + typedef Pointer pointer; + typedef Reference reference; + }; + + + // struct iterator_traits + template + struct iterator_traits + { + typedef typename Iterator::iterator_category iterator_category; + typedef typename Iterator::value_type value_type; + typedef typename Iterator::difference_type difference_type; + typedef typename Iterator::pointer pointer; + typedef typename Iterator::reference reference; + }; + + template + struct iterator_traits + { + typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category; // To consider: Change this to contiguous_iterator_tag for the case that + typedef T value_type; // EASTL_ITC_NS is "eastl" instead of "std". + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; + }; + + template + struct iterator_traits + { + typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category; + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef const T* pointer; + typedef const T& reference; + }; + + + + + /// is_iterator_wrapper + /// + /// Tells if an Iterator type is a wrapper type as opposed to a regular type. + /// Relies on the class declaring a typedef called wrapped_iterator_type. + /// + /// Examples of wrapping iterators: + /// reverse_iterator + /// generic_iterator + /// move_iterator + /// Examples of non-wrapping iterators: + /// iterator + /// list::iterator + /// char* + /// + /// Example behavior: + /// is_iterator_wrapper(int*)::value => false + /// is_iterator_wrapper(eastl::array*)::value => false + /// is_iterator_wrapper(eastl::vector::iterator)::value => false + /// is_iterator_wrapper(eastl::generic_iterator)::value => true + /// is_iterator_wrapper(eastl::move_iterator::iterator>)::value => true + /// + template + class is_iterator_wrapper + { + template + static eastl::no_type test(...); + + template + static eastl::yes_type test(typename U::wrapped_iterator_type*, typename eastl::enable_if::value>::type* = 0); + + public: + EA_DISABLE_VC_WARNING(6334) + static const bool value = (sizeof(test(NULL)) == sizeof(eastl::yes_type)); + EA_RESTORE_VC_WARNING() + }; + + + /// unwrap_iterator + /// + /// Takes a wrapper Iterator (e.g. move_iterator, reverse_iterator, generic_iterator) instance + /// and returns the wrapped iterator type. If Iterator is not a wrapper (including being a pointer), + /// or is not an iterator, then this function returns it as-is. + /// unwrap_iterator unwraps only a single layer of iterator at a time. You need to call it twice, + /// for example, to unwrap two layers of iterators. + /// + /// Example usage: + /// int* pInt = unwrap_iterator(&pIntArray[15]); + /// int* pInt = unwrap_iterator(generic_iterator(&pIntArray[15])); + /// MyVector::iterator it = unwrap_iterator(myVector.begin()); + /// MyVector::iterator it = unwrap_iterator(move_iterator(myVector.begin())); + /// + template + struct is_iterator_wrapper_helper + { + typedef Iterator iterator_type; + + static iterator_type get_base(Iterator it) + { return it; } + }; + + + template + struct is_iterator_wrapper_helper + { + typedef typename Iterator::iterator_type iterator_type; + + static iterator_type get_base(Iterator it) + { return it.base(); } + }; + + template + inline typename is_iterator_wrapper_helper::value>::iterator_type unwrap_iterator(Iterator it) + { return eastl::is_iterator_wrapper_helper::value>::get_base(it); } + + + + /// reverse_iterator + /// + /// From the C++ standard: + /// Bidirectional and random access iterators have corresponding reverse + /// iterator adaptors that iterate through the data structure in the + /// opposite direction. They have the same signatures as the corresponding + /// iterators. The fundamental relation between a reverse iterator and its + /// corresponding iterator i is established by the identity: + /// &*(reverse_iterator(i)) == &*(i - 1). + /// This mapping is dictated by the fact that while there is always a pointer + /// past the end of an array, there might not be a valid pointer before the + /// beginning of an array. + /// + template + class reverse_iterator : public iterator::iterator_category, + typename eastl::iterator_traits::value_type, + typename eastl::iterator_traits::difference_type, + typename eastl::iterator_traits::pointer, + typename eastl::iterator_traits::reference> + { + public: + typedef Iterator iterator_type; + typedef iterator_type wrapped_iterator_type; // This is not in the C++ Standard; it's used by use to identify it as a wrapping iterator type. + typedef typename eastl::iterator_traits::pointer pointer; + typedef typename eastl::iterator_traits::reference reference; + typedef typename eastl::iterator_traits::difference_type difference_type; + + protected: + Iterator mIterator; + + public: + reverse_iterator() // It's important that we construct mIterator, because if Iterator + : mIterator() { } // is a pointer, there's a difference between doing it and not. + + explicit reverse_iterator(iterator_type i) + : mIterator(i) { } + + reverse_iterator(const reverse_iterator& ri) + : mIterator(ri.mIterator) { } + + template + reverse_iterator(const reverse_iterator& ri) + : mIterator(ri.base()) { } + + // This operator= isn't in the standard, but the the C++ + // library working group has tentatively approved it, as it + // allows const and non-const reverse_iterators to interoperate. + template + reverse_iterator& operator=(const reverse_iterator& ri) + { mIterator = ri.base(); return *this; } + + iterator_type base() const + { return mIterator; } + + reference operator*() const + { + iterator_type i(mIterator); + return *--i; + } + + pointer operator->() const + { return &(operator*()); } + + reverse_iterator& operator++() + { --mIterator; return *this; } + + reverse_iterator operator++(int) + { + reverse_iterator ri(*this); + --mIterator; + return ri; + } + + reverse_iterator& operator--() + { ++mIterator; return *this; } + + reverse_iterator operator--(int) + { + reverse_iterator ri(*this); + ++mIterator; + return ri; + } + + reverse_iterator operator+(difference_type n) const + { return reverse_iterator(mIterator - n); } + + reverse_iterator& operator+=(difference_type n) + { mIterator -= n; return *this; } + + reverse_iterator operator-(difference_type n) const + { return reverse_iterator(mIterator + n); } + + reverse_iterator& operator-=(difference_type n) + { mIterator += n; return *this; } + + // http://cplusplus.github.io/LWG/lwg-defects.html#386, + // http://llvm.org/bugs/show_bug.cgi?id=17883 + // random_access_iterator operator[] is merely required to return something convertible to reference. + // reverse_iterator operator[] can't necessarily know what to return as the underlying iterator + // operator[] may return something other than reference. + // reference operator[](difference_type n) const + // { return mIterator[-n - 1]; } + + reference operator[](difference_type n) const + { return *(*this + n); } + }; + + + // The C++ library working group has tentatively approved the usage of two + // template parameters (Iterator1 and Iterator2) in order to allow reverse_iterators + // and const_reverse iterators to be comparable. This is a similar issue to the + // C++ defect report #179 regarding comparison of container iterators and const_iterators. + // + // libstdc++ reports that std::relops breaks the usage of two iterator types and if we + // want to support relops then we need to also make versions of each of below with + // a single template parameter to placate std::relops. But relops is hardly used due to + // the troubles it causes and so we are avoiding support here until somebody complains about it. + template + inline bool + operator==(const reverse_iterator& a, const reverse_iterator& b) + { return a.base() == b.base(); } + + + template + inline bool + operator<(const reverse_iterator& a, const reverse_iterator& b) + { return a.base() > b.base(); } + + + template + inline bool + operator!=(const reverse_iterator& a, const reverse_iterator& b) + { return a.base() != b.base(); } + + + template + inline bool + operator>(const reverse_iterator& a, const reverse_iterator& b) + { return a.base() < b.base(); } + + + template + inline bool + operator<=(const reverse_iterator& a, const reverse_iterator& b) + { return a.base() >= b.base(); } + + + template + inline bool + operator>=(const reverse_iterator& a, const reverse_iterator& b) + { return a.base() <= b.base(); } + + + template + inline typename reverse_iterator::difference_type + operator-(const reverse_iterator& a, const reverse_iterator& b) + { return b.base() - a.base(); } + + + template + inline reverse_iterator + operator+(typename reverse_iterator::difference_type n, const reverse_iterator& a) + { return reverse_iterator(a.base() - n); } + + + /// is_reverse_iterator + /// + /// This is a type traits extension utility. + /// Given an iterator, tells if it's a reverse_iterator vs anything else. + /// If it's a reverse iterator wrapped by another iterator then value is false. + /// To consider: Detect that if it's a move_iterator and unwrap + /// move_iterator so we can detect that underneath it's reverse_iterator. + /// + template + struct is_reverse_iterator + : public eastl::false_type {}; + + template + struct is_reverse_iterator< eastl::reverse_iterator > + : public eastl::true_type {}; + + + + /// unwrap_reverse_iterator + /// + /// Returns Iterator::get_base() if it's a reverse_iterator, else returns Iterator as-is. + /// + /// Example usage: + /// vector intVector; + /// eastl::reverse_iterator::iterator> reverseIterator(intVector.begin()); + /// vector::iterator it = unwrap_reverse_iterator(reverseIterator); + /// + /// Disabled until there is considered a good use for it. + /// template + /// inline typename eastl::is_iterator_wrapper_helper::value>::iterator_type unwrap_reverse_iterator(Iterator it) + /// { return eastl::is_iterator_wrapper_helper::value>::get_base(it); } + + + + #if EASTL_MOVE_SEMANTICS_ENABLED + /// move_iterator + /// + /// From the C++11 Standard, section 24.5.3.1: + /// Class template move_iterator is an iterator adaptor with the same behavior as the underlying iterator + /// except that its dereference operator implicitly converts the value returned by the underlying iterator's + /// dereference operator to an rvalue reference. Some generic algorithms can be called with move iterators to + /// replace copying with moving. + + template + class move_iterator // Don't inherit from iterator. + { + public: + typedef Iterator iterator_type; + typedef iterator_type wrapped_iterator_type; // This is not in the C++ Standard; it's used by use to identify it as a wrapping iterator type. + typedef iterator_traits traits_type; + typedef typename traits_type::iterator_category iterator_category; + typedef typename traits_type::value_type value_type; + typedef typename traits_type::difference_type difference_type; + typedef Iterator pointer; + typedef value_type&& reference; + + protected: + iterator_type mIterator; + + public: + move_iterator() + : mIterator() + { + } + + explicit move_iterator(iterator_type mi) + : mIterator(mi) { } + + template + move_iterator(const move_iterator& mi) + : mIterator(mi.base()) + { + } + + iterator_type base() const + { return mIterator; } + + reference operator*() const + { return eastl::move(*mIterator); } + + pointer operator->() const + { return mIterator; } + + move_iterator& operator++() + { + ++mIterator; + return *this; + } + + move_iterator operator++(int) + { + move_iterator tempMoveIterator = *this; + ++tempMoveIterator; + return tempMoveIterator; + } + + move_iterator& operator--() + { + --mIterator; + return *this; + } + + move_iterator operator--(int) + { + move_iterator tempMoveIterator = *this; + --tempMoveIterator; + return tempMoveIterator; + } + + move_iterator operator+(difference_type n) const + { return move_iterator(mIterator + n); } + + move_iterator& operator+=(difference_type n) + { + mIterator += n; + return *this; + } + + move_iterator operator-(difference_type n) const + { return move_iterator(mIterator - n); } + + move_iterator& operator-=(difference_type n) + { + mIterator -= n; + return *this; + } + + reference operator[](difference_type n) const + { return eastl::move(mIterator[n]); } + }; + + template + inline bool + operator==(const move_iterator& a, const move_iterator& b) + { return a.base() == b.base(); } + + + template + inline bool + operator!=(const move_iterator& a, const move_iterator& b) + { return !(a == b); } + + + template + inline bool + operator<(const move_iterator& a, const move_iterator& b) + { return a.base() < b.base(); } + + + template + inline bool + operator<=(const move_iterator& a, const move_iterator& b) + { return !(b < a); } + + + template + inline bool + operator>(const move_iterator& a, const move_iterator& b) + { return b < a; } + + + template + inline bool + operator>=(const move_iterator& a, const move_iterator& b) + { return !(a < b); } + + + template + inline auto + operator-(const move_iterator& a, const move_iterator& b) -> decltype(a.base() - b.base()) + { return a.base() - b.base(); } + + + template + inline move_iterator + operator+(typename move_iterator::difference_type n, const move_iterator& a) + { return a + n; } + + + template + inline move_iterator make_move_iterator(Iterator i) + { return move_iterator(i); } + + + // make_move_if_noexcept_iterator returns move_iterator if the Iterator is of a noexcept type; + // otherwise returns Iterator as-is. The point of this is to be able to avoid moves that can generate exceptions and instead + // fall back to copies or whatever the default IteratorType::operator* returns for use by copy/move algorithms. + // To consider: merge the conditional expression usage here with the one used by move_if_noexcept, as they are the same condition. + #if EASTL_EXCEPTIONS_ENABLED + #if defined(EA_COMPILER_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS) + namespace Internal + { + template + struct mminei_helper_1 + { + typedef eastl::move_iterator ReturnType; + static inline ReturnType mminei(Iterator i) + { return eastl::move_iterator(i); } + }; + template + struct mminei_helper_1 + { + typedef Iterator ReturnType; + static inline ReturnType mminei(Iterator i) + { return eastl::move_iterator(i); } + }; + + template + struct mminei_helper + { + static const bool is_noexcept = eastl::is_nothrow_move_constructible::value_type>::value || !eastl::is_copy_constructible::value_type>::value; + typedef typename mminei_helper_1::ReturnType ReturnType; + }; + } + + template + inline typename Internal::mminei_helper::ReturnType + make_move_if_noexcept_iterator(Iterator i) + { + return Internal::mminei_helper_1::is_noexcept>::mminei(i); + } + #else + template ::value_type>::value || + !eastl::is_copy_constructible::value_type>::value, + eastl::move_iterator, Iterator>::type> + inline IteratorType make_move_if_noexcept_iterator(Iterator i) + { return IteratorType(i); } + #endif + #else + // Else there are no exceptions and thus we always return a move_iterator. + template + inline eastl::move_iterator make_move_if_noexcept_iterator(Iterator i) + { return eastl::move_iterator(i); } + #endif + #else + + // To consider: Should we make a dummy move_iterator that does nothing new? + // It could be a subclass of generic_iterator. + + #endif // #if EASTL_MOVE_SEMANTICS_ENABLED + + + + /// is_move_iterator + /// + /// This is a type traits extension utility. + /// Given an iterator, tells if it's a move iterator vs anything else. + /// Example usage (though somewhat useless): + /// template + /// bool IsMoveIterator() { return typename eastl::is_move_iterator::value; } + /// + template + struct is_move_iterator + : public eastl::false_type {}; + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + struct is_move_iterator< eastl::move_iterator > + : public eastl::true_type {}; + #endif + + + /// unwrap_move_iterator + /// + /// Returns Iterator::get_base() if it's a move_iterator, else returns Iterator as-is. + /// + /// Example usage: + /// vector intVector; + /// eastl::move_iterator::iterator> moveIterator(intVector.begin()); + /// vector::iterator it = unwrap_move_iterator(moveIterator); + /// + template + inline typename eastl::is_iterator_wrapper_helper::value>::iterator_type unwrap_move_iterator(Iterator it) + { return eastl::is_iterator_wrapper_helper::value>::get_base(it); } + + + + + /// back_insert_iterator + /// + /// A back_insert_iterator is simply a class that acts like an iterator but when you + /// assign a value to it, it calls push_back on the container with the value. + /// + template + class back_insert_iterator : public iterator + { + public: + typedef back_insert_iterator this_type; + typedef Container container_type; + typedef typename Container::const_reference const_reference; + + protected: + Container& container; + + public: + //back_insert_iterator(); // Not valid. Must construct with a Container. + + //back_insert_iterator(const this_type& x) // Compiler-implemented + // : container(x.container) { } + + explicit back_insert_iterator(Container& x) + : container(x) { } + + back_insert_iterator& operator=(const_reference value) + { container.push_back(value); return *this; } + + back_insert_iterator& operator*() + { return *this; } + + back_insert_iterator& operator++() + { return *this; } // This is by design. + + back_insert_iterator operator++(int) + { return *this; } // This is by design. + + protected: + void operator=(const this_type&){} // Declared to avoid compiler warnings about inability to generate this function. + }; + + + /// back_inserter + /// + /// Creates an instance of a back_insert_iterator. + /// + template + inline back_insert_iterator + back_inserter(Container& x) + { return back_insert_iterator(x); } + + + + + /// front_insert_iterator + /// + /// A front_insert_iterator is simply a class that acts like an iterator but when you + /// assign a value to it, it calls push_front on the container with the value. + /// + template + class front_insert_iterator : public iterator + { + public: + typedef front_insert_iterator this_type; + typedef Container container_type; + typedef typename Container::const_reference const_reference; + + protected: + Container& container; + + public: + //front_insert_iterator(); // Not valid. Must construct with a Container. + + //front_insert_iterator(const this_type& x) // Compiler-implemented + // : container(x.container) { } + + explicit front_insert_iterator(Container& x) + : container(x) { } + + front_insert_iterator& operator=(const_reference value) + { container.push_front(value); return *this; } + + front_insert_iterator& operator*() + { return *this; } + + front_insert_iterator& operator++() + { return *this; } // This is by design. + + front_insert_iterator operator++(int) + { return *this; } // This is by design. + + protected: + void operator=(const this_type&){} // Declared to avoid compiler warnings about inability to generate this function. + }; + + + /// front_inserter + /// + /// Creates an instance of a front_insert_iterator. + /// + template + inline front_insert_iterator + front_inserter(Container& x) + { return front_insert_iterator(x); } + + + + + /// insert_iterator + /// + /// An insert_iterator is like an iterator except that when you assign a value to it, + /// the insert_iterator inserts the value into the container and increments the iterator. + /// + /// insert_iterator is an iterator adaptor that functions as an OutputIterator: + /// assignment through an insert_iterator inserts an object into a container. + /// Specifically, if ii is an insert_iterator, then ii keeps track of a container c and + /// an insertion point p; the expression *ii = x performs the insertion container.insert(p, x). + /// + /// If you assign through an insert_iterator several times, then you will be inserting + /// several elements into the underlying container. In the case of a sequence, they will + /// appear at a particular location in the underlying sequence, in the order in which + /// they were inserted: one of the arguments to insert_iterator's constructor is an + /// iterator p, and the new range will be inserted immediately before p. + /// + template + class insert_iterator : public iterator + { + public: + typedef Container container_type; + typedef typename Container::iterator iterator_type; + typedef typename Container::const_reference const_reference; + + protected: + Container& container; + iterator_type it; + + public: + // This assignment operator is defined more to stop compiler warnings (e.g. VC++ C4512) + // than to be useful. However, it does allow an insert_iterator to be assigned to another + // insert iterator provided that they point to the same container. + insert_iterator& operator=(const insert_iterator& x) + { + EASTL_ASSERT(&x.container == &container); + it = x.it; + return *this; + } + + insert_iterator(Container& x, iterator_type itNew) + : container(x), it(itNew) {} + + insert_iterator& operator=(const_reference value) + { + it = container.insert(it, value); + ++it; + return *this; + } + + insert_iterator& operator*() + { return *this; } + + insert_iterator& operator++() + { return *this; } // This is by design. + + insert_iterator& operator++(int) + { return *this; } // This is by design. + + }; // insert_iterator + + + /// inserter + /// + /// Creates an instance of an insert_iterator. + /// + template + inline eastl::insert_iterator + inserter(Container& x, Iterator i) + { + typedef typename Container::iterator iterator; + return eastl::insert_iterator(x, iterator(i)); + } + + + /// is_insert_iterator + /// + /// This is a type traits extension utility. + /// Given an iterator, tells if it's an insert_iterator vs anything else. + /// If it's a insert_iterator wrapped by another iterator then value is false. + /// + template + struct is_insert_iterator + : public eastl::false_type {}; + + template + struct is_insert_iterator< eastl::insert_iterator > + : public eastl::true_type {}; + + + + + ////////////////////////////////////////////////////////////////////////////////// + /// distance + /// + /// Implements the distance() function. There are two versions, one for + /// random access iterators (e.g. with vector) and one for regular input + /// iterators (e.g. with list). The former is more efficient. + /// + template + inline typename eastl::iterator_traits::difference_type + distance_impl(InputIterator first, InputIterator last, EASTL_ITC_NS::input_iterator_tag) + { + typename eastl::iterator_traits::difference_type n = 0; + + while(first != last) + { + ++first; + ++n; + } + return n; + } + + template + inline typename eastl::iterator_traits::difference_type + distance_impl(RandomAccessIterator first, RandomAccessIterator last, EASTL_ITC_NS::random_access_iterator_tag) + { + return last - first; + } + + // Special version defined so that std C++ iterators can be recognized by + // this function. Unfortunately, this function treats all foreign iterators + // as InputIterators and thus can seriously hamper performance in the case + // of large ranges of bidirectional_iterator_tag iterators. + //template + //inline typename eastl::iterator_traits::difference_type + //distance_impl(InputIterator first, InputIterator last, ...) + //{ + // typename eastl::iterator_traits::difference_type n = 0; + // + // while(first != last) + // { + // ++first; + // ++n; + // } + // return n; + //} + + template + inline typename eastl::iterator_traits::difference_type + distance(InputIterator first, InputIterator last) + { + typedef typename eastl::iterator_traits::iterator_category IC; + + return eastl::distance_impl(first, last, IC()); + } + + + + + ////////////////////////////////////////////////////////////////////////////////// + /// advance + /// + /// Implements the advance() function. There are three versions, one for + /// random access iterators (e.g. with vector), one for bidirectional + /// iterators (list) and one for regular input iterators (e.g. with slist). + /// + template + inline void + advance_impl(InputIterator& i, Distance n, EASTL_ITC_NS::input_iterator_tag) + { + while(n--) + ++i; + } + + template + struct advance_bi_impl + { + template + static void advance_impl(BidirectionalIterator& i, Distance n) // Specialization for unsigned distance type. + { + while(n--) + ++i; + } + }; + + template <> + struct advance_bi_impl + { + template + static void advance_impl(BidirectionalIterator& i, Distance n) // Specialization for signed distance type. + { + if(n > 0) + { + while(n--) + ++i; + } + else + { + while(n++) + --i; + } + } + }; + + template + inline void + advance_impl(BidirectionalIterator& i, Distance n, EASTL_ITC_NS::bidirectional_iterator_tag) + { + advance_bi_impl::value>::advance_impl(i, n); + } + + template + inline void + advance_impl(RandomAccessIterator& i, Distance n, EASTL_ITC_NS::random_access_iterator_tag) + { + i += n; + } + + // Special version defined so that std C++ iterators can be recognized by + // this function. Unfortunately, this function treats all foreign iterators + // as InputIterators and thus can seriously hamper performance in the case + // of large ranges of bidirectional_iterator_tag iterators. + //template + //inline void + //advance_impl(InputIterator& i, Distance n, ...) + //{ + // while(n--) + // ++i; + //} + + template + inline void + advance(InputIterator& i, Distance n) + { + typedef typename eastl::iterator_traits::iterator_category IC; + + eastl::advance_impl(i, n, IC()); + } + + + // eastl::next / eastl::prev + // Return the nth/-nth successor of iterator it. + // + // http://en.cppreference.com/w/cpp/iterator/next + // + template + inline InputIterator + next(InputIterator it, typename eastl::iterator_traits::difference_type n = 1) + { + eastl::advance(it, n); + return it; + } + + template + inline InputIterator + prev(InputIterator it, typename eastl::iterator_traits::difference_type n = 1) + { + eastl::advance(it, -n); + return it; + } + + + // eastl::data + // + // http://en.cppreference.com/w/cpp/iterator/data + // + template + EA_CONSTEXPR auto data(Container& c) -> decltype(c.data()) + { return c.data(); } + + template + EA_CONSTEXPR auto data(const Container& c) -> decltype(c.data()) + { return c.data(); } + + template + EA_CONSTEXPR T* data(T(&array)[N]) EA_NOEXCEPT + { return array; } + + template + EA_CONSTEXPR const E* data(std::initializer_list il) EA_NOEXCEPT + { return il.begin(); } + + + // eastl::size + // + // http://en.cppreference.com/w/cpp/iterator/size + // + template + EA_CONSTEXPR auto size(const C& c) -> decltype(c.size()) + { return c.size(); } + + template + EA_CONSTEXPR std::size_t size(const T (&)[N]) EA_NOEXCEPT + { return N; } + + + // eastl::empty + // + // http://en.cppreference.com/w/cpp/iterator/empty + // + template + EA_CONSTEXPR auto empty(const Container& c) -> decltype(c.empty()) + { return c.empty(); } + + template + EA_CONSTEXPR bool empty(const T (&)[N]) EA_NOEXCEPT + { return false; } + + template + EA_CONSTEXPR bool empty(std::initializer_list il) EA_NOEXCEPT + { return il.size() == 0; } + + + // eastl::begin / eastl::end + // http://en.cppreference.com/w/cpp/iterator/begin + // + // In order to enable eastl::begin and eastl::end, the compiler needs to have conforming support + // for argument-dependent lookup if it supports C++11 range-based for loops. The reason for this is + // that in C++11 range-based for loops result in usage of std::begin/std::end, but allow that to + // be overridden by argument-dependent lookup: + // C++11 Standard, section 6.5.4, paragraph 1. + // "otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively, + // where begin and end are looked up with argument-dependent lookup (3.4.2). For the + // purposes of this name lookup, namespace std is an associated namespace." + // It turns out that one compiler has a problem: GCC 4.6. That version added support for + // range-based for loops but has broken argument-dependent lookup which was fixed in GCC 4.7. + // + #if (defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION == 4006)) + #define EASTL_BEGIN_END_ENABLED 0 + #else + #define EASTL_BEGIN_END_ENABLED 1 + #endif + + #if EASTL_BEGIN_END_ENABLED + #if defined(EA_COMPILER_NO_DECLTYPE) // C++11 decltype + + template + inline typename Container::iterator begin(Container& container) + { + return container.begin(); + } + + template + inline typename Container::const_iterator begin(const Container& container) + { + return container.begin(); + } + + template + inline typename Container::const_iterator cbegin(const Container& container) + { + return container.begin(); + } + + template + inline typename Container::iterator end(Container& container) + { + return container.end(); + } + + template + inline typename Container::const_iterator end(const Container& container) + { + return container.end(); + } + + template + inline typename Container::const_iterator cend(const Container& container) + { + return container.end(); + } + + template + inline typename Container::reverse_iterator rbegin(Container& container) + { + return container.rbegin(); + } + + template + inline typename Container::reverse_iterator rbegin(const Container& container) + { + return container.rbegin(); + } + + template + inline typename Container::reverse_iterator rend(Container& container) + { + return container.rend(); + } + + template + inline typename Container::reverse_iterator rend(const Container& container) + { + return container.rend(); + } + + template + inline typename Container::const_reverse_iterator crbegin(const Container& container) + { + return container.rbegin(); + } + + template + inline typename Container::const_reverse_iterator crend(const Container& container) + { + return container.rend(); + } + #else + template + inline auto begin(Container& container) -> decltype(container.begin()) + { + return container.begin(); + } + + template + inline auto begin(const Container& container) -> decltype(container.begin()) + { + return container.begin(); + } + + template + inline auto cbegin(const Container& container) -> decltype(container.begin()) + { + return container.begin(); + } + + template + inline auto end(Container& container) -> decltype(container.end()) + { + return container.end(); + } + + template + inline auto end(const Container& container) -> decltype(container.end()) + { + return container.end(); + } + + template + inline auto cend(const Container& container) -> decltype(container.end()) + { + return container.end(); + } + + template + inline auto rbegin(Container& container) -> decltype(container.rbegin()) + { + return container.rbegin(); + } + + template + inline auto rbegin(const Container& container) -> decltype(container.rbegin()) + { + return container.rbegin(); + } + + template + inline auto rend(Container& container) -> decltype(container.rend()) + { + return container.rend(); + } + + template + inline auto rend(const Container& container) -> decltype(container.rend()) + { + return container.rend(); + } + + template + inline auto crbegin(const Container& container) -> decltype(eastl::rbegin(container)) + { + return container.rbegin(); + } + + template + inline auto crend(const Container& container) -> decltype(eastl::rend(container)) + { + return container.rend(); + } + + #endif + + template + inline T* begin(T (&arrayObject)[arraySize]) + { + return arrayObject; + } + + template + inline T* end(T (&arrayObject)[arraySize]) + { + return (arrayObject + arraySize); + } + + template + inline reverse_iterator rbegin(T (&arrayObject)[arraySize]) + { + return reverse_iterator(arrayObject + arraySize); + } + + template + inline reverse_iterator rend(T (&arrayObject)[arraySize]) + { + return reverse_iterator(arrayObject); + } + + template + inline reverse_iterator rbegin(std::initializer_list ilist) + { + return eastl::reverse_iterator(ilist.end()); + } + + template + inline reverse_iterator rend(std::initializer_list ilist) + { + return eastl::reverse_iterator(ilist.begin()); + } + + template + reverse_iterator make_reverse_iterator(Iterator i) + { return reverse_iterator(i); } + + #endif // EASTL_BEGIN_END_ENABLED + +} // namespace eastl + + + +// Some compilers (e.g. GCC 4.6) support range-based for loops, but have a bug with +// respect to argument-dependent lookup which results on them unilaterally using std::begin/end +// with range-based for loops. To work around this we #include for this case in +// order to make std::begin/end visible to users of , for portability. +#if !EASTL_BEGIN_END_ENABLED && !defined(EA_COMPILER_NO_RANGE_BASED_FOR_LOOP) + #include +#endif + + + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + + +#endif // Header include guard + + + + + diff --git a/libs/eastl/include/EASTL/linked_array.h b/libs/eastl/include/EASTL/linked_array.h new file mode 100644 index 0000000..88d9914 --- /dev/null +++ b/libs/eastl/include/EASTL/linked_array.h @@ -0,0 +1,336 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This class implements a linked_array template, which is an array version +// of linked_ptr. See linked_ptr for detailed documentation. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_LINKED_ARRAY_H +#define EASTL_LINKED_ARRAY_H + + +#include +#include // Defines smart_array_deleter +#include // Defines linked_ptr_base +#include // Definition of ptrdiff_t + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// class linked_array + /// + /// This class implements a linked_array template, which is an array version + /// of linked_ptr. See linked_ptr for detailed documentation. + /// + template > + class linked_array + { + + protected: + + /// this_type + /// This is an alias for linked_array, this class. + typedef linked_array this_type; + + /// deleter_type + typedef Deleter deleter_type; + + T* mpArray; + mutable const this_type* mpPrev; + mutable const this_type* mpNext; + + void link(const linked_array& linkedArray) + { // This code can only be called when we are in a reset state. + // assert(!mpArray && (mpNext == mpPrev)); + mpNext = linkedArray.mpNext; + mpNext->mpPrev = this; + mpPrev = &linkedArray; + linkedArray.mpNext = this; + } + + public: + /// element_type + /// Synonym for type T, useful for external code to reference the + /// type in a generic way. + typedef T element_type; + + + /// linked_array + /// Takes ownership of the pointer. It is OK if the input pointer is null. + explicit linked_array(T* pArray = NULL) + : mpArray(pArray) + { + mpPrev = mpNext = this; + } + + + /// linked_array + /// Shares ownership of a pointer with another instance of linked_array. + linked_array(const linked_array& linkedArray) + : mpArray(linkedArray.mpArray) + { + if(mpArray) + link(linkedArray); + else + mpPrev = mpNext = this; + } + + + /// ~linked_array + /// Removes this object from the of objects using the shared pointer. + /// If this object is the last owner of the shared pointer, the shared + /// pointer is deleted. + ~linked_array() + { + reset(); + } + + + /// operator= + /// Copies another linked_array to this object. Note that this object + /// may already own a shared pointer with another different pointer + /// (but still of the same type) before this call. In that case, + /// this function removes ownership of the old pointer and takes shared + /// ownership of the new pointer and increments its reference count. + linked_array& operator=(const linked_array& linkedArray) + { + if(linkedArray.mpArray != mpArray) + { + reset(linkedArray.mpArray); + if(linkedArray.mpArray) + link(linkedArray); + } + return *this; + } + + + /// operator= + /// Assigns a new pointer. If the new pointer is equivalent + /// to the current pointer, nothing is done. Otherwise the + /// current pointer is unlinked and possibly destroyed. + /// The new pointer can be NULL. + linked_array& operator=(T* pArray) + { + reset(pArray); + return *this; + } + + + /// reset + /// Releases the owned pointer and takes ownership of the + /// passed in pointer. If the passed in pointer is the same + /// as the owned pointer, nothing is done. The passed in pointer + /// can be null, in which case the use count is set to 1. + void reset(T* pArray = NULL) + { + if(pArray != mpArray) + { + if(unique()) + { + deleter_type del; + del(mpArray); + } + else + { + mpPrev->mpNext = mpNext; + mpNext->mpPrev = mpPrev; + mpPrev = mpNext = this; + } + mpArray = pArray; + } + } + + + /// swap + /// Exchanges the owned pointer beween two linkedArray objects. + /// + /// This function is disabled as it is currently deemed unsafe. + /// The problem is that the only way to implement this function + /// is to transfer pointers between the objects; you cannot + /// transfer the linked list membership between the objects. + /// Thus unless both linked_array objects were 'unique()', the + /// shared pointers would be duplicated amongst containers, + /// resulting in a crash. + //void swap(linked_array& linkedArray) + //{ + // if(linkedArray.mpArray != mpArray) + // { // This is only safe if both linked_arrays are unique(). + // linkedArray::element_type* const pArrayTemp = linkedArray.mpArray; + // linkedArray.reset(mpArray); + // reset(pArrayTemp); + // } + //} + + + /// operator[] + /// Returns a reference to the specified item in the owned pointer array. + T& operator[](ptrdiff_t i) const + { + // assert(mpArray && (i >= 0)); + return mpArray[i]; + } + + + /// operator* + /// Returns the owner pointer dereferenced. + T& operator*() const + { + return *mpArray; + } + + + /// operator-> + /// Allows access to the owned pointer via operator->() + T* operator->() const + { + return mpArray; + } + + + /// get + /// Returns the owned pointer. Note that this class does + /// not provide an operator T() function. This is because such + /// a thing (automatic conversion) is deemed unsafe. + T* get() const + { + return mpArray; + } + + + /// use_count + /// Returns the use count of the shared pointer. + /// The return value is one if the owned pointer is null. + /// This function is provided for compatibility with the + /// proposed C++ standard and for debugging purposes. It is not + /// intended for runtime use given that its execution time is + /// not constant. + int use_count() const + { + int useCount(1); + + for(const linked_ptr_base* pCurrent = this; pCurrent->mpNext != this; pCurrent = pCurrent->mpNext) + ++useCount; + + return useCount; + } + + + /// unique + /// Returns true if the use count of the owned pointer is one. + /// The return value is true if the owned pointer is null. + bool unique() const + { + return (mpNext == this); + } + + + /// Implicit operator bool + /// Allows for using a linked_array as a boolean. + /// Note that below we do not use operator bool(). The reason for this + /// is that booleans automatically convert up to short, int, float, etc. + /// The result is that this: if(linkedArray == 1) would yield true (bad). + typedef T* (this_type::*bool_)() const; + operator bool_() const + { + if(mpArray) + return &this_type::get; + return NULL; + } + + + /// operator! + /// This returns the opposite of operator bool; it returns true if + /// the owned pointer is null. Some compilers require this and some don't. + bool operator!() + { + return (mpArray == NULL); + } + + + /// force_delete + /// Forces deletion of the shared pointer. Fixes all references to the + /// pointer by any other owners to be NULL. + void force_delete() + { + T* const pArray = mpArray; + + this_type* p = this; + do + { + this_type* const pNext = const_cast(p->mpNext); + p->mpArray = NULL; + p->mpNext = p->mpPrev = p; + p = pNext; + } + while(p != this); + + deleter_type del; + del(pArray); + } + + }; // class linked_array + + + + /// get_pointer + /// Returns linked_array::get() via the input linked_array. Provided for compatibility + /// with certain well-known libraries that use this functionality. + template + inline T* get_pointer(const linked_array& linkedArray) + { + return linkedArray.get(); + } + + + /// operator== + /// Compares two linked_array objects for equality. Equality is defined as + /// being true when the pointer shared between two linked_array objects is equal. + template + inline bool operator==(const linked_array& linkedArray1, const linked_array& linkedArray2) + { + return (linkedArray1.get() == linkedArray2.get()); + } + + + /// operator!= + /// Compares two linked_array objects for inequality. Equality is defined as + /// being true when the pointer shared between two linked_array objects is equal. + template + inline bool operator!=(const linked_array& linkedArray1, const linked_array& linkedArray2) + { + return (linkedArray1.get() != linkedArray2.get()); + } + + + /// operator< + /// Returns which linked_array is 'less' than the other. Useful when storing + /// sorted containers of linked_array objects. + template + inline bool operator<(const linked_array& linkedArray1, const linked_array& linkedArray2) + { + return (linkedArray1.get() < linkedArray2.get()); + } + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + diff --git a/libs/eastl/include/EASTL/linked_ptr.h b/libs/eastl/include/EASTL/linked_ptr.h new file mode 100644 index 0000000..f57681a --- /dev/null +++ b/libs/eastl/include/EASTL/linked_ptr.h @@ -0,0 +1,426 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_LINKED_PTR_H +#define EASTL_LINKED_PTR_H + + + +#include +#include // Defines smart_ptr_deleter +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// linked_ptr_base + /// + /// This class allows linked_ptr and linked_ptr to share the same + /// base nodes and thus be in the same linked list. + /// + struct linked_ptr_base + { + mutable linked_ptr_base* mpPrev; + mutable linked_ptr_base* mpNext; + }; + + + /// linked_ptr + /// + /// This class implements a linked_ptr template. A linked_ptr is like the C++ + /// Standard Library auto_ptr except that it allows sharing of pointers between + /// instances of auto_ptr via reference counting. linked_ptr objects can safely + /// be copied and can safely be used in C++ Standard Library containers such + /// as std::vector or std::list. This implementation, however, is not thread-safe. + /// you would need to use a separate linked_ptr_mt (multi-threaded) to get + /// thread safety. + /// + /// linked_ptr is a variation of shared_ptr (a.k.a. counted_ptr) which differs + /// in that instead of being implemented by a shared integer stored on the heap, + /// it is implemented by linked list stored within the linked_ptr object itself. + /// The result is that no memory is explicitly allocated from the heap, though + /// the cost of each linked_ptr object is 12 bytes of memory (32 bit machine) + /// instead of 4 bytes for the case of shared_ptr (depending on the heap). + /// + template > + class linked_ptr : public linked_ptr_base + { + protected: + template friend class linked_ptr; + + /// this_type + /// This is an alias for linked_ptr, this class. + typedef linked_ptr this_type; + + /// deleter_type + typedef Deleter deleter_type; + + T* mpValue; /// The owned pointer. + + template + void link(const linked_ptr& linkedPtr) + { // This code can only be called when we are in a reset state. + // assert(!mpValue && (mpNext == mpPrev)); + mpNext = linkedPtr.mpNext; + mpNext->mpPrev = this; + mpPrev = const_cast*>(&linkedPtr); + linkedPtr.mpNext = this; + } + + public: + /// element_type + /// Synonym for type T, useful for external code to reference the + /// type in a generic way. + typedef T element_type; + + + /// linked_ptr + /// Default constructor. + linked_ptr() + : mpValue(NULL) + { + mpPrev = mpNext = this; + } + + + /// linked_ptr + /// Takes ownership of the pointer. It is OK if the input pointer is null. + template + explicit linked_ptr(U* pValue) + : mpValue(pValue) + { + mpPrev = mpNext = this; + } + + + /// linked_ptr + /// Construction with self type. + /// If we want a shared_ptr constructor that is templated on linked_ptr, + /// then we need to make it in addition to this function, as otherwise + /// the compiler will generate this function and things will go wrong. + linked_ptr(const linked_ptr& linkedPtr) + : mpValue(linkedPtr.mpValue) + { + if(mpValue) + link(linkedPtr); + else + mpPrev = mpNext = this; + } + + + /// linked_ptr + /// Shares ownership of a pointer with another instance of linked_ptr. + template + linked_ptr(const linked_ptr& linkedPtr) + : mpValue(linkedPtr.mpValue) + { + if(mpValue) + link(linkedPtr); + else + mpPrev = mpNext = this; + } + + + /// ~linked_ptr + /// Removes this object from the of objects using the shared pointer. + /// If this object is the last owner of the shared pointer, the shared + /// pointer is deleted. + ~linked_ptr() + { + reset(); + } + + + /// operator= + /// If we want a shared_ptr operator= that is templated on linked_ptr, + /// then we need to make it in addition to this function, as otherwise + /// the compiler will generate this function and things will go wrong. + linked_ptr& operator=(const linked_ptr& linkedPtr) + { + if(linkedPtr.mpValue != mpValue) + { + reset(linkedPtr.mpValue); + if(linkedPtr.mpValue) + link(linkedPtr); + } + return *this; + } + + + /// operator= + /// Copies another linked_ptr to this object. Note that this object + /// may already own a shared pointer with another different pointer + /// (but still of the same type) before this call. In that case, + /// this function removes ownership of the old pointer and takes shared + /// ownership of the new pointer and increments its reference count. + template + linked_ptr& operator=(const linked_ptr& linkedPtr) + { + if(linkedPtr.mpValue != mpValue) + { + reset(linkedPtr.mpValue); + if(linkedPtr.mpValue) + link(linkedPtr); + } + return *this; + } + + + /// operator= + /// Assigns a new pointer. If the new pointer is equivalent + /// to the current pointer, nothing is done. Otherwise the + /// current pointer is unlinked and possibly destroyed. + /// The new pointer can be NULL. + template + linked_ptr& operator=(U* pValue) + { + reset(pValue); + return *this; + } + + + /// reset + /// Releases the owned pointer and takes ownership of the + /// passed in pointer. If the passed in pointer is the same + /// as the owned pointer, nothing is done. The passed in pointer + /// can be NULL, in which case the use count is set to 1. + template + void reset(U* pValue) + { + if(pValue != mpValue) + { + if(unique()) + { + deleter_type del; + del(mpValue); + } + else + { + mpPrev->mpNext = mpNext; + mpNext->mpPrev = mpPrev; + mpPrev = mpNext = this; + } + mpValue = pValue; + } + } + + + /// reset + /// Resets the container with NULL. If the current pointer + /// is non-NULL, it is unlinked and possibly destroyed. + void reset() + { + reset((T*)NULL); + } + + + /// swap + /// Exchanges the owned pointer beween two linkedPtr objects. + /// + /// This function is disabled as it is currently deemed unsafe. + /// The problem is that the only way to implement this function + /// is to transfer pointers between the objects; you cannot + /// transfer the linked list membership between the objects. + /// Thus unless both linked_ptr objects were 'unique()', the + /// shared pointers would be duplicated amongst containers, + /// resulting in a crash. + //template + //void swap(linked_ptr& linkedPtr) + //{ + // if(linkedPtr.mpValue != mpValue) + // { // This is only safe if both linked_ptrs are unique(). + // linkedPtr::element_type* const pValueTemp = linkedPtr.mpValue; + // linkedPtr.reset(mpValue); + // reset(pValueTemp); + // } + //} + + + /// operator* + /// Returns the owner pointer dereferenced. + T& operator*() const + { + return *mpValue; + } + + + /// operator-> + /// Allows access to the owned pointer via operator->() + T* operator->() const + { + return mpValue; + } + + + /// get + /// Returns the owned pointer. Note that this class does + /// not provide an operator T() function. This is because such + /// a thing (automatic conversion) is deemed unsafe. + T* get() const + { + return mpValue; + } + + + /// use_count + /// Returns the use count of the shared pointer. + /// The return value is one if the owned pointer is null. + /// This function is provided for compatibility with the + /// proposed C++ standard and for debugging purposes. It is not + /// intended for runtime use given that its execution time is + /// not constant. + int use_count() const + { + int useCount(1); + + for(const linked_ptr_base* pCurrent = static_cast(this); + pCurrent->mpNext != static_cast(this); pCurrent = pCurrent->mpNext) + ++useCount; + + return useCount; + } + + + /// unique + /// Returns true if the use count of the owned pointer is one. + /// The return value is true if the owned pointer is null. + bool unique() const + { + return (mpNext == static_cast(this)); + } + + + /// Implicit operator bool + /// Allows for using a linked_ptr as a boolean. + /// Note that below we do not use operator bool(). The reason for this + /// is that booleans automatically convert up to short, int, float, etc. + /// The result is that this: if(linkedPtr == 1) would yield true (bad). + typedef T* (this_type::*bool_)() const; + operator bool_() const + { + if(mpValue) + return &this_type::get; + return NULL; + } + + + /// operator! + /// This returns the opposite of operator bool; it returns true if + /// the owned pointer is null. Some compilers require this and some don't. + bool operator!() + { + return (mpValue == NULL); + } + + + /// detach + /// Returns ownership of the pointer to the caller. Fixes all + /// references to the pointer by any other owners to be NULL. + /// This function can work properly only if all entries in the list + /// refer to type T and none refer to any other type (e.g. U). + T* detach() + { + T* const pValue = mpValue; + + linked_ptr_base* p = this; + do + { + linked_ptr_base* const pNext = p->mpNext; + static_cast(p)->mpValue = NULL; + p->mpNext = p->mpPrev = p; + p = pNext; + } + while(p != this); + + return pValue; + } + + /// force_delete + /// Forces deletion of the shared pointer. Fixes all references to the + /// pointer by any other owners to be NULL. + /// This function can work properly only if all entries in the list + /// refer to type T and none refer to any other type (e.g. U). + void force_delete() + { + T* const pValue = detach(); + Deleter del; + del(pValue); + } + + }; // class linked_ptr + + + + /// get_pointer + /// Returns linked_ptr::get() via the input linked_ptr. Provided for compatibility + /// with certain well-known libraries that use this functionality. + template + inline T* get_pointer(const linked_ptr& linkedPtr) + { + return linkedPtr.get(); + } + + + /// operator== + /// Compares two linked_ptr objects for equality. Equality is defined as + /// being true when the pointer shared between two linked_ptr objects is equal. + template + inline bool operator==(const linked_ptr& linkedPtr1, const linked_ptr& linkedPtr2) + { + return (linkedPtr1.get() == linkedPtr2.get()); + } + + + /// operator!= + /// Compares two linked_ptr objects for inequality. Equality is defined as + /// being true when the pointer shared between two linked_ptr objects is equal. + template + inline bool operator!=(const linked_ptr& linkedPtr1, const linked_ptr& linkedPtr2) + { + return (linkedPtr1.get() != linkedPtr2.get()); + } + + + /// operator< + /// Returns which linked_ptr is 'less' than the other. Useful when storing + /// sorted containers of linked_ptr objects. + template + inline bool operator<(const linked_ptr& linkedPtr1, const linked_ptr& linkedPtr2) + { + return (linkedPtr1.get() < linkedPtr2.get()); + } + + +} // namespace eastl + + +#endif // Header include guard + + + + + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/list.h b/libs/eastl/include/EASTL/list.h new file mode 100644 index 0000000..752ecc3 --- /dev/null +++ b/libs/eastl/include/EASTL/list.h @@ -0,0 +1,2377 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements a doubly-linked list, much like the C++ std::list class. +// The primary distinctions between this list and std::list are: +// - list doesn't implement some of the less-frequently used functions +// of std::list. Any required functions can be added at a later time. +// - list has a couple extension functions that increase performance. +// - list can contain objects with alignment requirements. std::list cannot +// do so without a bit of tedious non-portable effort. +// - list has optimizations that don't exist in the STL implementations +// supplied by library vendors for our targeted platforms. +// - list supports debug memory naming natively. +// - list::size() by default is not a constant time function, like the list::size +// in some std implementations such as STLPort and SGI STL but unlike the +// list in Dinkumware and Metrowerks. The EASTL_LIST_SIZE_CACHE option can change this. +// - list provides a guaranteed portable node definition that allows users +// to write custom fixed size node allocators that are portable. +// - list is easier to read, debug, and visualize. +// - list is savvy to an environment that doesn't have exception handling, +// as is sometimes the case with console or embedded environments. +// - list has less deeply nested function calls and allows the user to +// enable forced inlining in debug builds in order to reduce bloat. +// - list doesn't keep a member size variable. This means that list is +// smaller than std::list (depends on std::list) and that for most operations +// it is faster than std::list. However, the list::size function is slower. +// - list::size_type is defined as eastl_size_t instead of size_t in order to +// save memory and run faster on 64 bit systems. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_LIST_H +#define EASTL_LIST_H + + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + #pragma warning(push, 0) + #include + #include + #pragma warning(pop) +#else + #include + #include +#endif + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4530) // C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc + #pragma warning(disable: 4345) // Behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized + #pragma warning(disable: 4571) // catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught. +#endif + +EA_DISABLE_SN_WARNING(828); // The EDG SN compiler has a bug in its handling of variadic template arguments and mistakenly reports "parameter "args" was never referenced" + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// EASTL_LIST_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_LIST_DEFAULT_NAME + #define EASTL_LIST_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " list" // Unless the user overrides something, this is "EASTL list". + #endif + + + /// EASTL_LIST_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_LIST_DEFAULT_ALLOCATOR + #define EASTL_LIST_DEFAULT_ALLOCATOR allocator_type(EASTL_LIST_DEFAULT_NAME) + #endif + + + + /// ListNodeBase + /// + /// We define a ListNodeBase separately from ListNode (below), because it allows + /// us to have non-templated operations such as insert, remove (below), and it + /// makes it so that the list anchor node doesn't carry a T with it, which would + /// waste space and possibly lead to surprising the user due to extra Ts existing + /// that the user didn't explicitly create. The downside to all of this is that + /// it makes debug viewing of a list harder, given that the node pointers are of + /// type ListNodeBase and not ListNode. However, see ListNodeBaseProxy below. + /// + struct ListNodeBase + { + ListNodeBase* mpNext; + ListNodeBase* mpPrev; + + void insert(ListNodeBase* pNext) EA_NOEXCEPT; // Inserts this standalone node before the node pNext in pNext's list. + void remove() EA_NOEXCEPT; // Removes this node from the list it's in. Leaves this node's mpNext/mpPrev invalid. + void splice(ListNodeBase* pFirst, ListNodeBase* pLast) EA_NOEXCEPT; // Removes [pFirst,pLast) from the list it's in and inserts it before this in this node's list. + void reverse() EA_NOEXCEPT; // Reverses the order of nodes in the circular list this node is a part of. + static void swap(ListNodeBase& a, ListNodeBase& b) EA_NOEXCEPT; // Swaps the nodes a and b in the lists to which they belong. + + void insert_range(ListNodeBase* pFirst, ListNodeBase* pFinal) EA_NOEXCEPT; // Differs from splice in that first/final aren't in another list. + static void remove_range(ListNodeBase* pFirst, ListNodeBase* pFinal) EA_NOEXCEPT; // + } EASTL_LIST_PROXY_MAY_ALIAS; + + + #if EASTL_LIST_PROXY_ENABLED + + /// ListNodeBaseProxy + /// + /// In debug builds, we define ListNodeBaseProxy to be the same thing as + /// ListNodeBase, except it is templated on the parent ListNode class. + /// We do this because we want users in debug builds to be able to easily + /// view the list's contents in a debugger GUI. We do this only in a debug + /// build for the reasons described above: that ListNodeBase needs to be + /// as efficient as possible and not cause code bloat or extra function + /// calls (inlined or not). + /// + /// ListNodeBaseProxy *must* be separate from its parent class ListNode + /// because the list class must have a member node which contains no T value. + /// It is thus incorrect for us to have one single ListNode class which + /// has mpNext, mpPrev, and mValue. So we do a recursive template trick in + /// the definition and use of SListNodeBaseProxy. + /// + template + struct ListNodeBaseProxy + { + LN* mpNext; + LN* mpPrev; + }; + + template + struct ListNode : public ListNodeBaseProxy< ListNode > + { + T mValue; + }; + + #else + + template + struct ListNode : public ListNodeBase + { + T mValue; + }; + + #endif + + + + + /// ListIterator + /// + template + struct ListIterator + { + typedef ListIterator this_type; + typedef ListIterator iterator; + typedef ListIterator const_iterator; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef ListNode node_type; + typedef Pointer pointer; + typedef Reference reference; + typedef EASTL_ITC_NS::bidirectional_iterator_tag iterator_category; + + public: + node_type* mpNode; + + public: + ListIterator() EA_NOEXCEPT; + ListIterator(const ListNodeBase* pNode) EA_NOEXCEPT; + ListIterator(const iterator& x) EA_NOEXCEPT; + + this_type next() const EA_NOEXCEPT; + this_type prev() const EA_NOEXCEPT; + + reference operator*() const EA_NOEXCEPT; + pointer operator->() const EA_NOEXCEPT; + + this_type& operator++() EA_NOEXCEPT; + this_type operator++(int) EA_NOEXCEPT; + + this_type& operator--() EA_NOEXCEPT; + this_type operator--(int) EA_NOEXCEPT; + + }; // ListIterator + + + + + /// ListBase + /// + /// See VectorBase (class vector) for an explanation of why we + /// create this separate base class. + /// + template + class ListBase + { + public: + typedef T value_type; + typedef Allocator allocator_type; + typedef ListNode node_type; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to uint32_t. + typedef ptrdiff_t difference_type; + #if EASTL_LIST_PROXY_ENABLED + typedef ListNodeBaseProxy< ListNode > base_node_type; + #else + typedef ListNodeBase base_node_type; // We use ListNodeBase instead of ListNode because we don't want to create a T. + #endif + + protected: + base_node_type mNode; + #if EASTL_LIST_SIZE_CACHE + size_type mSize; + #endif + // disabled, Spore list class is only 8 bytes long + allocator_type mAllocator; // To do: Use base class optimization to make this go away. + + public: + const allocator_type& get_allocator() const EA_NOEXCEPT; + allocator_type& get_allocator() EA_NOEXCEPT; + void set_allocator(const allocator_type& allocator); + + protected: + ListBase(); + ListBase(const allocator_type& a); + ~ListBase(); + + node_type* DoAllocateNode(); + void DoFreeNode(node_type* pNode); + + void DoInit() EA_NOEXCEPT; + void DoClear(); + + }; // ListBase + + + + + /// list + /// + /// -- size() is O(n) -- + /// Note that as of this writing, list::size() is an O(n) operation when EASTL_LIST_SIZE_CACHE is disabled. + /// That is, getting the size of the list is not a fast operation, as it requires traversing the list and + /// counting the nodes. We could make list::size() be fast by having a member mSize variable. There are reasons + /// for having such functionality and reasons for not having such functionality. We currently choose + /// to not have a member mSize variable as it would add four bytes to the class, add a tiny amount + /// of processing to functions such as insert and erase, and would only serve to improve the size + /// function, but no others. The alternative argument is that the C++ standard states that std::list + /// should be an O(1) operation (i.e. have a member size variable), most C++ standard library list + /// implementations do so, the size is but an integer which is quick to update, and many users + /// expect to have a fast size function. The EASTL_LIST_SIZE_CACHE option changes this. + /// To consider: Make size caching an optional template parameter. + /// + /// Pool allocation + /// If you want to make a custom memory pool for a list container, your pool + /// needs to contain items of type list::node_type. So if you have a memory + /// pool that has a constructor that takes the size of pool items and the + /// count of pool items, you would do this (assuming that MemoryPool implements + /// the Allocator interface): + /// typedef list WidgetList; // Delare your WidgetList type. + /// MemoryPool myPool(sizeof(WidgetList::node_type), 100); // Make a pool of 100 Widget nodes. + /// WidgetList myList(&myPool); // Create a list that uses the pool. + /// + template + class list : public ListBase + { + typedef ListBase base_type; + typedef list this_type; + + public: + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef ListIterator iterator; + typedef ListIterator const_iterator; + typedef eastl::reverse_iterator reverse_iterator; + typedef eastl::reverse_iterator const_reverse_iterator; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::base_node_type base_node_type; + + using base_type::mNode; + using base_type::mAllocator; + using base_type::DoAllocateNode; + using base_type::DoFreeNode; + using base_type::DoClear; + using base_type::DoInit; + using base_type::get_allocator; + #if EASTL_LIST_SIZE_CACHE + using base_type::mSize; + #endif + + public: + list(); + list(const allocator_type& allocator); + explicit list(size_type n, const allocator_type& allocator = EASTL_LIST_DEFAULT_ALLOCATOR); + list(size_type n, const value_type& value, const allocator_type& allocator = EASTL_LIST_DEFAULT_ALLOCATOR); + list(const this_type& x); + list(const this_type& x, const allocator_type& allocator); + #if EASTL_MOVE_SEMANTICS_ENABLED + list(this_type&& x); + list(this_type&&, const allocator_type&); + #endif + list(std::initializer_list ilist, const allocator_type& allocator = EASTL_LIST_DEFAULT_ALLOCATOR); + + template + list(InputIterator first, InputIterator last); // allocator arg removed because VC7.1 fails on the default arg. To do: Make a second version of this function without a default arg. + + this_type& operator=(const this_type& x); + this_type& operator=(std::initializer_list ilist); + #if EASTL_MOVE_SEMANTICS_ENABLED + this_type& operator=(this_type&& x); + #endif + + // In the case that the two containers' allocators are unequal, swap copies elements instead + // of replacing them in place. In this case swap is an O(n) operation instead of O(1). + void swap(this_type& x); + + void assign(size_type n, const value_type& value); + + template // It turns out that the C++ std::list specifies a two argument + void assign(InputIterator first, InputIterator last); // version of assign that takes (int size, int value). These are not + // iterators, so we need to do a template compiler trick to do the right thing. + void assign(std::initializer_list ilist); + + iterator begin() EA_NOEXCEPT; + const_iterator begin() const EA_NOEXCEPT; + const_iterator cbegin() const EA_NOEXCEPT; + + iterator end() EA_NOEXCEPT; + const_iterator end() const EA_NOEXCEPT; + const_iterator cend() const EA_NOEXCEPT; + + reverse_iterator rbegin() EA_NOEXCEPT; + const_reverse_iterator rbegin() const EA_NOEXCEPT; + const_reverse_iterator crbegin() const EA_NOEXCEPT; + + reverse_iterator rend() EA_NOEXCEPT; + const_reverse_iterator rend() const EA_NOEXCEPT; + const_reverse_iterator crend() const EA_NOEXCEPT; + + bool empty() const EA_NOEXCEPT; + size_type size() const EA_NOEXCEPT; + + void resize(size_type n, const value_type& value); + void resize(size_type n); + + reference front(); + const_reference front() const; + + reference back(); + const_reference back() const; + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + void emplace_front(Args&&... args); + + template + void emplace_back(Args&&... args); + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + void emplace_front(value_type&& value); + void emplace_back(value_type&& value); + #endif + void emplace_front(const value_type& value); + void emplace_back(const value_type& value); + #endif + + void push_front(const value_type& value); + #if EASTL_MOVE_SEMANTICS_ENABLED + void push_front(value_type&& x); + #endif + reference push_front(); + void* push_front_uninitialized(); + + void push_back(const value_type& value); + #if EASTL_MOVE_SEMANTICS_ENABLED + void push_back(value_type&& x); + #endif + reference push_back(); + void* push_back_uninitialized(); + + void pop_front(); + void pop_back(); + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + iterator emplace(const_iterator position, Args&&... args); + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + iterator emplace(const_iterator position, value_type&& value); + #endif + iterator emplace(const_iterator position, const value_type& value); + #endif + + iterator insert(const_iterator position); + iterator insert(const_iterator position, const value_type& value); + #if EASTL_MOVE_SEMANTICS_ENABLED + iterator insert(const_iterator position, value_type&& x); + #endif + + void insert(const_iterator position, size_type n, const value_type& value); + + template + void insert(const_iterator position, InputIterator first, InputIterator last); + + iterator insert(const_iterator position, std::initializer_list ilist); + + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + + reverse_iterator erase(const_reverse_iterator position); + reverse_iterator erase(const_reverse_iterator first, reverse_iterator last); + + void clear() EA_NOEXCEPT; + void reset_lose_memory() EA_NOEXCEPT; // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. + + void remove(const T& x); + + template + void remove_if(Predicate); + + void reverse() EA_NOEXCEPT; + + // splice inserts elements in the range [first,last) before position and removes the elements from x. + // In the case that the two containers' allocators are unequal, splice copies elements + // instead of splicing them. In this case elements are not removed from x, and iterators + // into the spliced elements from x continue to point to the original values in x. + void splice(const_iterator position, this_type& x); + void splice(const_iterator position, this_type& x, const_iterator i); + void splice(const_iterator position, this_type& x, const_iterator first, const_iterator last); + + #if EASTL_MOVE_SEMANTICS_ENABLED + void splice(const_iterator position, this_type&& x); + void splice(const_iterator position, this_type&& x, const_iterator i); + void splice(const_iterator position, this_type&& x, const_iterator first, const_iterator last); + #endif + + #if EASTL_RESET_ENABLED + void reset() EA_NOEXCEPT; // This function name is deprecated; use reset_lose_memory instead. + #endif + + public: + // For merge, see notes for splice regarding the handling of unequal allocators. + void merge(this_type& x); + + #if EASTL_MOVE_SEMANTICS_ENABLED + void merge(this_type&& x); + #endif + + template + void merge(this_type& x, Compare compare); + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + void merge(this_type&& x, Compare compare); + #endif + + void unique(); + + template + void unique(BinaryPredicate); + + // Sorting functionality + // This is independent of the global sort algorithms, as lists are + // linked nodes and can be sorted more efficiently by moving nodes + // around in ways that global sort algorithms aren't privy to. + void sort(); + + template + void sort(Compare compare); + + public: + bool validate() const; + int validate_iterator(const_iterator i) const; + + protected: + node_type* DoCreateNode(); + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED // If we can do variadic arguments... + template + node_type* DoCreateNode(Args&&... args); + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + node_type* DoCreateNode(value_type&& value); + #endif + node_type* DoCreateNode(const value_type& value); + #endif + + template + void DoAssign(Integer n, Integer value, true_type); + + template + void DoAssign(InputIterator first, InputIterator last, false_type); + + void DoAssignValues(size_type n, const value_type& value); + + template + void DoInsert(ListNodeBase* pNode, Integer n, Integer value, true_type); + + template + void DoInsert(ListNodeBase* pNode, InputIterator first, InputIterator last, false_type); + + void DoInsertValues(ListNodeBase* pNode, size_type n, const value_type& value); + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED // If we can do variadic arguments... + template + void DoInsertValue(ListNodeBase* pNode, Args&&... args); + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + void DoInsertValue(ListNodeBase* pNode, value_type&& value); + #endif + void DoInsertValue(ListNodeBase* pNode, const value_type& value); + #endif + + void DoErase(ListNodeBase* pNode); + + void DoSwap(this_type& x); + + template + iterator DoSort(iterator i1, iterator end2, size_type n, Compare& compare); + + }; // class list + + + + + + /////////////////////////////////////////////////////////////////////// + // ListNodeBase + /////////////////////////////////////////////////////////////////////// + + // Swaps the nodes a and b in the lists to which they belong. This is similar to + // splicing a into b's list and b into a's list at the same time. + // Works by swapping the members of a and b, and fixes up the lists that a and b + // were part of to point to the new members. + inline void ListNodeBase::swap(ListNodeBase& a, ListNodeBase& b) EA_NOEXCEPT + { + const ListNodeBase temp(a); + a = b; + b = temp; + + if(a.mpNext == &b) + a.mpNext = a.mpPrev = &a; + else + a.mpNext->mpPrev = a.mpPrev->mpNext = &a; + + if(b.mpNext == &a) + b.mpNext = b.mpPrev = &b; + else + b.mpNext->mpPrev = b.mpPrev->mpNext = &b; + } + + + // splices the [first,last) range from its current list into our list before this node. + inline void ListNodeBase::splice(ListNodeBase* first, ListNodeBase* last) EA_NOEXCEPT + { + // We assume that [first, last] are not within our list. + last->mpPrev->mpNext = this; + first->mpPrev->mpNext = last; + this->mpPrev->mpNext = first; + + ListNodeBase* const pTemp = this->mpPrev; + this->mpPrev = last->mpPrev; + last->mpPrev = first->mpPrev; + first->mpPrev = pTemp; + } + + + inline void ListNodeBase::reverse() EA_NOEXCEPT + { + ListNodeBase* pNode = this; + do + { + EA_ANALYSIS_ASSUME(pNode != NULL); + ListNodeBase* const pTemp = pNode->mpNext; + pNode->mpNext = pNode->mpPrev; + pNode->mpPrev = pTemp; + pNode = pNode->mpPrev; + } + while(pNode != this); + } + + + inline void ListNodeBase::insert(ListNodeBase* pNext) EA_NOEXCEPT + { + mpNext = pNext; + mpPrev = pNext->mpPrev; + pNext->mpPrev->mpNext = this; + pNext->mpPrev = this; + } + + + // Removes this node from the list that it's in. Assumes that the + // node is within a list and thus that its prev/next pointers are valid. + inline void ListNodeBase::remove() EA_NOEXCEPT + { + mpNext->mpPrev = mpPrev; + mpPrev->mpNext = mpNext; + } + + + // Inserts the standalone range [pFirst, pFinal] before pPosition. Assumes that the + // range is not within a list and thus that it's prev/next pointers are not valid. + // Assumes that this node is within a list and thus that its prev/next pointers are valid. + inline void ListNodeBase::insert_range(ListNodeBase* pFirst, ListNodeBase* pFinal) EA_NOEXCEPT + { + mpPrev->mpNext = pFirst; + pFirst->mpPrev = mpPrev; + mpPrev = pFinal; + pFinal->mpNext = this; + } + + + // Removes the range [pFirst, pFinal] from the list that it's in. Assumes that the + // range is within a list and thus that its prev/next pointers are valid. + inline void ListNodeBase::remove_range(ListNodeBase* pFirst, ListNodeBase* pFinal) EA_NOEXCEPT + { + pFinal->mpNext->mpPrev = pFirst->mpPrev; + pFirst->mpPrev->mpNext = pFinal->mpNext; + } + + + /////////////////////////////////////////////////////////////////////// + // ListIterator + /////////////////////////////////////////////////////////////////////// + + template + inline ListIterator::ListIterator() EA_NOEXCEPT + : mpNode() // To consider: Do we really need to intialize mpNode? + { + // Empty + } + + + template + inline ListIterator::ListIterator(const ListNodeBase* pNode) EA_NOEXCEPT + : mpNode(static_cast((ListNode*)const_cast(pNode))) // All this casting is in the name of making runtime debugging much easier on the user. + { + // Empty + } + + + template + inline ListIterator::ListIterator(const iterator& x) EA_NOEXCEPT + : mpNode(const_cast(x.mpNode)) + { + // Empty + } + + + template + inline typename ListIterator::this_type + ListIterator::next() const EA_NOEXCEPT + { + return ListIterator(mpNode->mpNext); + } + + + template + inline typename ListIterator::this_type + ListIterator::prev() const EA_NOEXCEPT + { + return ListIterator(mpNode->mpPrev); + } + + + template + inline typename ListIterator::reference + ListIterator::operator*() const EA_NOEXCEPT + { + return mpNode->mValue; + } + + + template + inline typename ListIterator::pointer + ListIterator::operator->() const EA_NOEXCEPT + { + return &mpNode->mValue; + } + + + template + inline typename ListIterator::this_type& + ListIterator::operator++() EA_NOEXCEPT + { + mpNode = static_cast(mpNode->mpNext); + return *this; + } + + + template + inline typename ListIterator::this_type + ListIterator::operator++(int) EA_NOEXCEPT + { + this_type temp(*this); + mpNode = static_cast(mpNode->mpNext); + return temp; + } + + + template + inline typename ListIterator::this_type& + ListIterator::operator--() EA_NOEXCEPT + { + mpNode = static_cast(mpNode->mpPrev); + return *this; + } + + + template + inline typename ListIterator::this_type + ListIterator::operator--(int) EA_NOEXCEPT + { + this_type temp(*this); + mpNode = static_cast(mpNode->mpPrev); + return temp; + } + + + // The C++ defect report #179 requires that we support comparisons between const and non-const iterators. + // Thus we provide additional template paremeters here to support this. The defect report does not + // require us to support comparisons between reverse_iterators and const_reverse_iterators. + template + inline bool operator==(const ListIterator& a, + const ListIterator& b) EA_NOEXCEPT + { + return a.mpNode == b.mpNode; + } + + + template + inline bool operator!=(const ListIterator& a, + const ListIterator& b) EA_NOEXCEPT + { + return a.mpNode != b.mpNode; + } + + + // We provide a version of operator!= for the case where the iterators are of the + // same type. This helps prevent ambiguity errors in the presence of rel_ops. + template + inline bool operator!=(const ListIterator& a, + const ListIterator& b) EA_NOEXCEPT + { + return a.mpNode != b.mpNode; + } + + + + /////////////////////////////////////////////////////////////////////// + // ListBase + /////////////////////////////////////////////////////////////////////// + + template + inline ListBase::ListBase() + : mNode(), + #if EASTL_LIST_SIZE_CACHE + mSize(0), + #endif + mAllocator(EASTL_LIST_DEFAULT_NAME) + { + DoInit(); + } + + template + inline ListBase::ListBase(const allocator_type& allocator) + : mNode(), + #if EASTL_LIST_SIZE_CACHE + mSize(0), + #endif + mAllocator(allocator) + { + DoInit(); + } + + + template + inline ListBase::~ListBase() + { + DoClear(); + } + + + template + const typename ListBase::allocator_type& + ListBase::get_allocator() const EA_NOEXCEPT + { + return mAllocator; + } + + + template + typename ListBase::allocator_type& + ListBase::get_allocator() EA_NOEXCEPT + { + return mAllocator; + } + + + template + inline void ListBase::set_allocator(const allocator_type& allocator) + { + EASTL_ASSERT((mAllocator == allocator) || (static_cast(mNode.mpNext) == &mNode)); // We can only assign a different allocator if we are empty of elements. + mAllocator = allocator; + } + + + template + inline typename ListBase::node_type* + ListBase::DoAllocateNode() + { + node_type* pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(T), 0); + EASTL_ASSERT(pNode != nullptr); + return pNode; + } + + + template + inline void ListBase::DoFreeNode(node_type* p) + { + EASTLFree(mAllocator, p, sizeof(node_type)); + } + + + template + inline void ListBase::DoInit() EA_NOEXCEPT + { + mNode.mpNext = (ListNode*)&mNode; + mNode.mpPrev = (ListNode*)&mNode; + } + + + template + inline void ListBase::DoClear() + { + node_type* p = static_cast(mNode.mpNext); + + while(p != &mNode) + { + node_type* const pTemp = p; + p = static_cast(p->mpNext); + pTemp->~node_type(); + EASTLFree(mAllocator, pTemp, sizeof(node_type)); + } + } + + + + /////////////////////////////////////////////////////////////////////// + // list + /////////////////////////////////////////////////////////////////////// + + template + inline list::list() + : base_type() + { + // Empty + } + + + template + inline list::list(const allocator_type& allocator) + : base_type(allocator) + { + // Empty + } + + + template + inline list::list(size_type n, const allocator_type& allocator) + : base_type(allocator) + { + DoInsertValues((ListNodeBase*)&mNode, n, value_type()); + } + + + template + inline list::list(size_type n, const value_type& value, const allocator_type& allocator) + : base_type(allocator) + { + DoInsertValues((ListNodeBase*)&mNode, n, value); + } + + + template + inline list::list(const this_type& x) + : base_type(x.mAllocator) + { + DoInsert((ListNodeBase*)&mNode, const_iterator((ListNodeBase*)x.mNode.mpNext), const_iterator((ListNodeBase*)&x.mNode), false_type()); + } + + + template + inline list::list(const this_type& x, const allocator_type& allocator) + : base_type(allocator) + { + DoInsert((ListNodeBase*)&mNode, const_iterator((ListNodeBase*)x.mNode.mpNext), const_iterator((ListNodeBase*)&x.mNode), false_type()); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline list::list(this_type&& x) + : base_type(eastl::move(x.mAllocator)) + { + swap(x); + } + + + template + inline list::list(this_type&& x, const allocator_type& allocator) + : base_type(allocator) + { + swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. + } + #endif + + + template + inline list::list(std::initializer_list ilist, const allocator_type& allocator) + : base_type(allocator) + { + DoInsert((ListNodeBase*)&mNode, ilist.begin(), ilist.end(), false_type()); + } + + + template + template + list::list(InputIterator first, InputIterator last) + : base_type(EASTL_LIST_DEFAULT_ALLOCATOR) + { + //insert(const_iterator((ListNodeBase*)&mNode), first, last); + DoInsert((ListNodeBase*)&mNode, first, last, is_integral()); + } + + + template + typename list::iterator + inline list::begin() EA_NOEXCEPT + { + return iterator((ListNodeBase*)mNode.mpNext); + } + + + template + inline typename list::const_iterator + list::begin() const EA_NOEXCEPT + { + return const_iterator((ListNodeBase*)mNode.mpNext); + } + + + template + inline typename list::const_iterator + list::cbegin() const EA_NOEXCEPT + { + return const_iterator((ListNodeBase*)mNode.mpNext); + } + + + template + inline typename list::iterator + list::end() EA_NOEXCEPT + { + return iterator((ListNodeBase*)&mNode); + } + + + template + inline typename list::const_iterator + list::end() const EA_NOEXCEPT + { + return const_iterator((ListNodeBase*)&mNode); + } + + + template + inline typename list::const_iterator + list::cend() const EA_NOEXCEPT + { + return const_iterator((ListNodeBase*)&mNode); + } + + + template + inline typename list::reverse_iterator + list::rbegin() EA_NOEXCEPT + { + return reverse_iterator((ListNodeBase*)&mNode); + } + + + template + inline typename list::const_reverse_iterator + list::rbegin() const EA_NOEXCEPT + { + return const_reverse_iterator((ListNodeBase*)&mNode); + } + + + template + inline typename list::const_reverse_iterator + list::crbegin() const EA_NOEXCEPT + { + return const_reverse_iterator((ListNodeBase*)&mNode); + } + + + template + inline typename list::reverse_iterator + list::rend() EA_NOEXCEPT + { + return reverse_iterator((ListNodeBase*)mNode.mpNext); + } + + + template + inline typename list::const_reverse_iterator + list::rend() const EA_NOEXCEPT + { + return const_reverse_iterator((ListNodeBase*)mNode.mpNext); + } + + + template + inline typename list::const_reverse_iterator + list::crend() const EA_NOEXCEPT + { + return const_reverse_iterator((ListNodeBase*)mNode.mpNext); + } + + + template + inline typename list::reference + list::front() + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference an empty container. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(static_cast(mNode.mpNext) == &mNode)) + EASTL_FAIL_MSG("list::front -- empty container"); + #endif + + return static_cast(mNode.mpNext)->mValue; + } + + + template + inline typename list::const_reference + list::front() const + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference an empty container. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(static_cast(mNode.mpNext) == &mNode)) + EASTL_FAIL_MSG("list::front -- empty container"); + #endif + + return static_cast(mNode.mpNext)->mValue; + } + + + template + inline typename list::reference + list::back() + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference an empty container. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(static_cast(mNode.mpNext) == &mNode)) + EASTL_FAIL_MSG("list::back -- empty container"); + #endif + + return static_cast(mNode.mpPrev)->mValue; + } + + + template + inline typename list::const_reference + list::back() const + { + #if EASTL_EMPTY_REFERENCE_ASSERT_ENABLED + // We allow the user to reference an empty container. + #elif EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(static_cast(mNode.mpNext) == &mNode)) + EASTL_FAIL_MSG("list::back -- empty container"); + #endif + + return static_cast(mNode.mpPrev)->mValue; + } + + + template + inline bool list::empty() const EA_NOEXCEPT + { + #if EASTL_LIST_SIZE_CACHE + return (mSize == 0); + #else + return static_cast(mNode.mpNext) == &mNode; + #endif + } + + + template + inline typename list::size_type + list::size() const EA_NOEXCEPT + { + #if EASTL_LIST_SIZE_CACHE + return mSize; + #else + #if EASTL_DEBUG + const ListNodeBase* p = (ListNodeBase*)mNode.mpNext; + size_type n = 0; + while(p != (ListNodeBase*)&mNode) + { + ++n; + p = (ListNodeBase*)p->mpNext; + } + return n; + #else + // The following optimizes to slightly better code than the code above. + return (size_type)eastl::distance(const_iterator((ListNodeBase*)mNode.mpNext), const_iterator((ListNodeBase*)&mNode)); + #endif + #endif + } + + + template + typename list::this_type& + list::operator=(const this_type& x) + { + if(this != &x) // If not assigning to self... + { + // If (EASTL_ALLOCATOR_COPY_ENABLED == 1) and the current contents are allocated by an + // allocator that's unequal to x's allocator, we need to reallocate our elements with + // our current allocator and reallocate it with x's allocator. If the allocators are + // equal then we can use a more optimal algorithm that doesn't reallocate our elements + // but instead can copy them in place. + + #if EASTL_ALLOCATOR_COPY_ENABLED + bool bSlowerPathwayRequired = (mAllocator != x.mAllocator); + #else + bool bSlowerPathwayRequired = false; + #endif + + if(bSlowerPathwayRequired) + { + clear(); + + #if EASTL_ALLOCATOR_COPY_ENABLED + mAllocator = x.mAllocator; + #endif + } + + DoAssign(x.begin(), x.end(), eastl::false_type()); + } + + return *this; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + typename list::this_type& + list::operator=(this_type&& x) + { + if(this != &x) + { + clear(); // To consider: Are we really required to clear here? x is going away soon and will clear itself in its dtor. + swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. + } + return *this; + } + #endif + + + template + typename list::this_type& + list::operator=(std::initializer_list ilist) + { + DoAssign(ilist.begin(), ilist.end(), false_type()); + return *this; + } + + + template + inline void list::assign(size_type n, const value_type& value) + { + DoAssignValues(n, value); + } + + + // It turns out that the C++ std::list specifies a two argument + // version of assign that takes (int size, int value). These are not + // iterators, so we need to do a template compiler trick to do the right thing. + template + template + inline void list::assign(InputIterator first, InputIterator last) + { + DoAssign(first, last, is_integral()); + } + + + template + inline void list::assign(std::initializer_list ilist) + { + DoAssign(ilist.begin(), ilist.end(), false_type()); + } + + + template + inline void list::clear() EA_NOEXCEPT + { + DoClear(); + DoInit(); + #if EASTL_LIST_SIZE_CACHE + mSize = 0; + #endif + } + + + #if EASTL_RESET_ENABLED + // This function name is deprecated; use reset_lose_memory instead. + template + inline void list::reset() EA_NOEXCEPT + { + reset_lose_memory(); + } + #endif + + + template + inline void list::reset_lose_memory() EA_NOEXCEPT + { + // The reset_lose_memory function is a special extension function which unilaterally + // resets the container to an empty state without freeing the memory of + // the contained objects. This is useful for very quickly tearing down a + // container built into scratch memory. + DoInit(); + #if EASTL_LIST_SIZE_CACHE + mSize = 0; + #endif + } + + + template + void list::resize(size_type n, const value_type& value) + { + iterator current((ListNodeBase*)mNode.mpNext); + size_type i = 0; + + while((current.mpNode != &mNode) && (i < n)) + { + ++current; + ++i; + } + if(i == n) + erase(current, (ListNodeBase*)&mNode); + else + insert((ListNodeBase*)&mNode, n - i, value); + } + + + template + inline void list::resize(size_type n) + { + resize(n, value_type()); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + template + void list::emplace_front(Args&&... args) + { + DoInsertValue((ListNodeBase*)mNode.mpNext, eastl::forward(args)...); + } + + template + template + void list::emplace_back(Args&&... args) + { + DoInsertValue((ListNodeBase*)&mNode, eastl::forward(args)...); + } + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + template + void list::emplace_front(value_type&& value) + { + DoInsertValue((ListNodeBase*)mNode.mpNext, eastl::move(value)); + } + + template + void list::emplace_back(value_type&& value) + { + DoInsertValue((ListNodeBase*)&mNode, eastl::move(value)); + } + #endif + + template + void list::emplace_front(const value_type& value) + { + DoInsertValue((ListNodeBase*)mNode.mpNext, value); + } + + template + void list::emplace_back(const value_type& value) + { + DoInsertValue((ListNodeBase*)&mNode, value); + } + #endif + + + template + inline void list::push_front(const value_type& value) + { + DoInsertValue((ListNodeBase*)mNode.mpNext, value); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline void list::push_front(value_type&& value) + { + emplace(begin(), eastl::move(value)); + } + #endif + + + template + inline typename list::reference + list::push_front() + { + node_type* const pNode = DoCreateNode(); + ((ListNodeBase*)pNode)->insert((ListNodeBase*)mNode.mpNext); + #if EASTL_LIST_SIZE_CACHE + ++mSize; + #endif + return static_cast(mNode.mpNext)->mValue; // Same as return front(); + } + + + template + inline void* list::push_front_uninitialized() + { + node_type* const pNode = DoAllocateNode(); + ((ListNodeBase*)pNode)->insert((ListNodeBase*)mNode.mpNext); + #if EASTL_LIST_SIZE_CACHE + ++mSize; + #endif + return &pNode->mValue; + } + + + template + inline void list::pop_front() + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(static_cast(mNode.mpNext) == &mNode)) + EASTL_FAIL_MSG("list::pop_front -- empty container"); + #endif + + DoErase((ListNodeBase*)mNode.mpNext); + } + + + template + inline void list::push_back(const value_type& value) + { + DoInsertValue((ListNodeBase*)&mNode, value); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline void list::push_back(value_type&& value) + { + emplace(end(), eastl::move(value)); + } + #endif + + + template + inline typename list::reference + list::push_back() + { + node_type* const pNode = DoCreateNode(); + ((ListNodeBase*)pNode)->insert((ListNodeBase*)&mNode); + #if EASTL_LIST_SIZE_CACHE + ++mSize; + #endif + return static_cast(mNode.mpPrev)->mValue; // Same as return back(); + } + + + template + inline void* list::push_back_uninitialized() + { + node_type* const pNode = DoAllocateNode(); + ((ListNodeBase*)pNode)->insert((ListNodeBase*)&mNode); + #if EASTL_LIST_SIZE_CACHE + ++mSize; + #endif + return &pNode->mValue; + } + + + template + inline void list::pop_back() + { + #if EASTL_ASSERT_ENABLED + if(EASTL_UNLIKELY(static_cast(mNode.mpNext) == &mNode)) + EASTL_FAIL_MSG("list::pop_back -- empty container"); + #endif + + DoErase((ListNodeBase*)mNode.mpPrev); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + template + inline typename list::iterator + list::emplace(const_iterator position, Args&&... args) + { + DoInsertValue(position.mpNode, eastl::forward(args)...); + return iterator(position.mpNode->mpPrev); + } + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename list::iterator + list::emplace(const_iterator position, value_type&& value) + { + DoInsertValue(position.mpNode, eastl::move(value)); + return iterator(position.mpNode->mpPrev); + } + #endif + + template + inline typename list::iterator + list::emplace(const_iterator position, const value_type& value) + { + DoInsertValue(position.mpNode, value); + return iterator(position.mpNode->mpPrev); + } + #endif + + + template + inline typename list::iterator + list::insert(const_iterator position) + { + node_type* const pNode = DoCreateNode(value_type()); + ((ListNodeBase*)pNode)->insert((ListNodeBase*)position.mpNode); + #if EASTL_LIST_SIZE_CACHE + ++mSize; + #endif + return (ListNodeBase*)pNode; + } + + + template + inline typename list::iterator + list::insert(const_iterator position, const value_type& value) + { + node_type* const pNode = DoCreateNode(value); + ((ListNodeBase*)pNode)->insert((ListNodeBase*)position.mpNode); + #if EASTL_LIST_SIZE_CACHE + ++mSize; + #endif + return (ListNodeBase*)pNode; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename list::iterator + list::insert(const_iterator position, value_type&& value) + { + return emplace(position, eastl::move(value)); + } + #endif + + + template + inline void list::insert(const_iterator position, size_type n, const value_type& value) + { + // To do: Get rid of DoInsertValues and put its implementation directly here. + DoInsertValues((ListNodeBase*)position.mpNode, n, value); + } + + + template + template + inline void list::insert(const_iterator position, InputIterator first, InputIterator last) + { + DoInsert((ListNodeBase*)position.mpNode, first, last, is_integral()); + } + + + template + inline typename list::iterator + list::insert(const_iterator position, std::initializer_list ilist) + { + iterator itPrev(position.mpNode); + --itPrev; + DoInsert((ListNodeBase*)position.mpNode, ilist.begin(), ilist.end(), false_type()); + return ++itPrev; // Inserts in front of position, returns iterator to new elements. + } + + + template + inline typename list::iterator + list::erase(const_iterator position) + { + ++position; + DoErase((ListNodeBase*)position.mpNode->mpPrev); + return iterator(position.mpNode); + } + + + template + typename list::iterator + list::erase(const_iterator first, const_iterator last) + { + while(first != last) + first = erase(first); + return iterator(last.mpNode); + } + + + template + inline typename list::reverse_iterator + list::erase(const_reverse_iterator position) + { + return reverse_iterator(erase((++position).base())); + } + + + template + typename list::reverse_iterator + list::erase(const_reverse_iterator first, reverse_iterator last) + { + // Version which erases in order from first to last. + // difference_type i(first.base() - last.base()); + // while(i--) + // first = erase(first); + // return first; + + // Version which erases in order from last to first, but is slightly more efficient: + const_iterator itLastBase((++last).base()); + const_iterator itFirstBase((++first).base()); + + return reverse_iterator(erase(itLastBase, itFirstBase)); + } + + + template + void list::remove(const value_type& value) + { + iterator current((ListNodeBase*)mNode.mpNext); + + while(current.mpNode != &mNode) + { + if(EASTL_LIKELY(!(*current == value))) + ++current; // We have duplicate '++current' statements here and below, but the logic here forces this. + else + { + ++current; + DoErase((ListNodeBase*)current.mpNode->mpPrev); + } + } + } + + + template + template + inline void list::remove_if(Predicate predicate) + { + for(iterator first((ListNodeBase*)mNode.mpNext), last((ListNodeBase*)&mNode); first != last; ) + { + iterator temp(first); + ++temp; + if(predicate(first.mpNode->mValue)) + DoErase((ListNodeBase*)first.mpNode); + first = temp; + } + } + + + template + inline void list::reverse() EA_NOEXCEPT + { + ((ListNodeBase&)mNode).reverse(); + } + + + template + inline void list::splice(const_iterator position, this_type& x) + { + // Splicing operations cannot succeed if the two containers use unequal allocators. + // This issue is not addressed in the C++ 1998 standard but is discussed in the + // LWG defect reports, such as #431. There is no simple solution to this problem. + // One option is to throw an exception. Another option which probably captures the + // user intent most of the time is to copy the range from the source to the dest and + // remove it from the source. + + if(mAllocator == x.mAllocator) + { + #if EASTL_LIST_SIZE_CACHE + if(x.mSize) + { + ((ListNodeBase*)position.mpNode)->splice((ListNodeBase*)x.mNode.mpNext, (ListNodeBase*)&x.mNode); + mSize += x.mSize; + x.mSize = 0; + } + #else + if(!x.empty()) + ((ListNodeBase*)position.mpNode)->splice((ListNodeBase*)x.mNode.mpNext, (ListNodeBase*)&x.mNode); + #endif + } + else + { + insert(position, x.begin(), x.end()); + x.clear(); + } + } + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline void list::splice(const_iterator position, this_type&& x) + { + return splice(position, x); // This will call splice(const_iterator, const this_type&); + } + #endif + + + template + inline void list::splice(const_iterator position, list& x, const_iterator i) + { + if(mAllocator == x.mAllocator) + { + iterator i2(i.mpNode); + ++i2; + if((position != i) && (position != i2)) + { + ((ListNodeBase*)position.mpNode)->splice((ListNodeBase*)i.mpNode, (ListNodeBase*)i2.mpNode); + + #if EASTL_LIST_SIZE_CACHE + ++mSize; + --x.mSize; + #endif + } + } + else + { + insert(position, *i); + x.erase(i); + } + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline void list::splice(const_iterator position, list&& x, const_iterator i) + { + return splice(position, x, i); // This will call splice(const_iterator, const this_type&, const_iterator); + } + #endif + + + template + inline void list::splice(const_iterator position, this_type& x, const_iterator first, const_iterator last) + { + if(mAllocator == x.mAllocator) + { + #if EASTL_LIST_SIZE_CACHE + const size_type n = (size_type)eastl::distance(first, last); + + if(n) + { + ((ListNodeBase*)position.mpNode)->splice((ListNodeBase*)first.mpNode, (ListNodeBase*)last.mpNode); + mSize += n; + x.mSize -= n; + } + #else + if(first != last) + ((ListNodeBase*)position.mpNode)->splice((ListNodeBase*)first.mpNode, (ListNodeBase*)last.mpNode); + #endif + } + else + { + insert(position, first, last); + x.erase(first, last); + } + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline void list::splice(const_iterator position, list&& x, const_iterator first, const_iterator last) + { + return splice(position, x, first, last); // This will call splice(const_iterator, const this_type&, const_iterator, const_iterator); + } + #endif + + + template + inline void list::swap(this_type& x) + { + if(mAllocator == x.mAllocator) // If allocators are equivalent... + DoSwap(x); + else // else swap the contents. + { + const this_type temp(*this); // Can't call eastl::swap because that would + *this = x; // itself call this member swap function. + x = temp; + } + } + + + template + void list::merge(this_type& x) + { + if(this != &x) + { + iterator first(begin()); + iterator firstX(x.begin()); + const iterator last(end()); + const iterator lastX(x.end()); + + while((first != last) && (firstX != lastX)) + { + if(*firstX < *first) + { + iterator next(firstX); + + splice(first, x, firstX, ++next); + firstX = next; + } + else + ++first; + } + + if(firstX != lastX) + splice(last, x, firstX, lastX); + } + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + void list::merge(this_type&& x) + { + return merge(x); // This will call merge(this_type&) + } + #endif + + + template + template + void list::merge(this_type& x, Compare compare) + { + if(this != &x) + { + iterator first(begin()); + iterator firstX(x.begin()); + const iterator last(end()); + const iterator lastX(x.end()); + + while((first != last) && (firstX != lastX)) + { + if(compare(*firstX, *first)) + { + iterator next(firstX); + + splice(first, x, firstX, ++next); + firstX = next; + } + else + ++first; + } + + if(firstX != lastX) + splice(last, x, firstX, lastX); + } + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + template + void list::merge(this_type&& x, Compare compare) + { + return merge(x, compare); // This will call merge(this_type&, Compare) + } + #endif + + + template + void list::unique() + { + iterator first(begin()); + const iterator last(end()); + + if(first != last) + { + iterator next(first); + + while(++next != last) + { + if(*first == *next) + DoErase((ListNodeBase*)next.mpNode); + else + first = next; + next = first; + } + } + } + + + template + template + void list::unique(BinaryPredicate predicate) + { + iterator first(begin()); + const iterator last(end()); + + if(first != last) + { + iterator next(first); + + while(++next != last) + { + if(predicate(*first, *next)) + DoErase((ListNodeBase*)next.mpNode); + else + first = next; + next = first; + } + } + } + + + template + void list::sort() + { + eastl::less compare; + DoSort(begin(), end(), size(), compare); + } + + + template + template + void list::sort(Compare compare) + { + DoSort(begin(), end(), size(), compare); + } + + + template + template + typename list::iterator + list::DoSort(iterator i1, iterator end2, size_type n, Compare& compare) + { + // A previous version of this function did this by creating temporary lists, + // but that was incompatible with fixed_list because the sizes could be too big. + // We sort subsegments by recursive descent. Then merge as we ascend. + // Return an iterator to the beginning of the sorted subsegment. + // Start with a special case for small node counts. + switch (n) + { + case 0: + case 1: + return i1; + + case 2: + // Potentialy swap these two nodes and return the resulting first of them. + if(compare(*--end2, *i1)) + { + end2.mpNode->remove(); + end2.mpNode->insert(i1.mpNode); + return end2; + } + return i1; + + case 3: + { + // We do a list insertion sort. Measurements showed this improved performance 3-12%. + iterator lowest = i1; + + for(iterator current = i1.next(); current != end2; ++current) + { + if(compare(*current, *lowest)) + lowest = current; + } + + if(lowest == i1) + ++i1; + else + { + lowest.mpNode->remove(); + lowest.mpNode->insert(i1.mpNode); + } + + if(compare(*--end2, *i1)) // At this point, i1 refers to the second element in this three element segment. + { + end2.mpNode->remove(); + end2.mpNode->insert(i1.mpNode); + } + + return lowest; + } + } + + // Divide the range into two parts are recursively sort each part. Upon return we will have + // two halves that are each sorted but we'll need to merge the two together before returning. + iterator result; + size_type nMid = (n / 2); + iterator end1 = eastl::next(i1, (difference_type)nMid); + i1 = DoSort(i1, end1, nMid, compare); // Return the new beginning of the first sorted sub-range. + iterator i2 = DoSort(end1, end2, n - nMid, compare); // Return the new beginning of the second sorted sub-range. + + // If the start of the second list is before the start of the first list, insert the first list + // into the second at an appropriate starting place. + if(compare(*i2, *i1)) + { + // Find the position to insert the first list into the second list. + iterator ix = i2.next(); + while((ix != end2) && compare(*ix, *i1)) + ++ix; + + // Cut out the initial segment of the second list and move it to be in front of the first list. + ListNodeBase* i2Cut = i2.mpNode; + ListNodeBase* i2CutLast = ix.mpNode->mpPrev; + result = i2; + end1 = i2 = ix; + ListNodeBase::remove_range(i2Cut, i2CutLast); + i1.mpNode->insert_range(i2Cut, i2CutLast); + } + else + { + result = i1; + end1 = i2; + } + + // Merge the two segments. We do this by merging the second sub-segment into the first, by walking forward in each of the two sub-segments. + for(++i1; (i1 != end1) && (i2 != end2); ++i1) // while still working on either segment... + { + if(compare(*i2, *i1)) // If i2 is less than i1 and it needs to be merged in front of i1... + { + // Find the position to insert the i2 list into the i1 list. + iterator ix = i2.next(); + while((ix != end2) && compare(*ix, *i1)) + ++ix; + + // Cut this section of the i2 sub-segment out and merge into the appropriate place in the i1 list. + ListNodeBase* i2Cut = i2.mpNode; + ListNodeBase* i2CutLast = ix.mpNode->mpPrev; + if(end1 == i2) + end1 = ix; + i2 = ix; + ListNodeBase::remove_range(i2Cut, i2CutLast); + i1.mpNode->insert_range(i2Cut, i2CutLast); + } + } + + return result; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED // If we can do variadic arguments... + template + template + inline typename list::node_type* + list::DoCreateNode(Args&&... args) + { + node_type* const pNode = DoAllocateNode(); // pNode is of type node_type, but it's uninitialized memory. + + #if EASTL_EXCEPTIONS_ENABLED + try + { + ::new((void*)&pNode->mValue) value_type(eastl::forward(args)...); + } + catch(...) + { + DoFreeNode(pNode); + throw; + } + #else + ::new((void*)&pNode->mValue) value_type(eastl::forward(args)...); + #endif + + return pNode; + } + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline typename list::node_type* + list::DoCreateNode(value_type&& value) + { + node_type* const pNode = DoAllocateNode(); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + ::new((void*)&pNode->mValue) value_type(eastl::move(value)); + } + catch(...) + { + DoFreeNode(pNode); + throw; + } + #else + ::new((void*)&pNode->mValue) value_type(eastl::move(value)); + #endif + + return pNode; + } + #endif + + template + inline typename list::node_type* + list::DoCreateNode(const value_type& value) + { + node_type* const pNode = DoAllocateNode(); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + ::new((void*)&pNode->mValue) value_type(value); + } + catch(...) + { + DoFreeNode(pNode); + throw; + } + #else + ::new((void*)&pNode->mValue) value_type(value); + #endif + + return pNode; + } + #endif + + + template + inline typename list::node_type* + list::DoCreateNode() + { + node_type* const pNode = DoAllocateNode(); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + ::new((void*)&pNode->mValue) value_type(); + } + catch(...) + { + DoFreeNode(pNode); + throw; + } + #else + ::new((void*)&pNode->mValue) value_type; + #endif + + return pNode; + } + + + template + template + inline void list::DoAssign(Integer n, Integer value, true_type) + { + DoAssignValues(static_cast(n), static_cast(value)); + } + + + template + template + void list::DoAssign(InputIterator first, InputIterator last, false_type) + { + node_type* pNode = static_cast(mNode.mpNext); + + for(; (pNode != &mNode) && (first != last); ++first) + { + pNode->mValue = *first; + pNode = static_cast(pNode->mpNext); + } + + if(first == last) + erase(const_iterator((ListNodeBase*)pNode), (ListNodeBase*)&mNode); + else + DoInsert((ListNodeBase*)&mNode, first, last, false_type()); + } + + + template + void list::DoAssignValues(size_type n, const value_type& value) + { + node_type* pNode = static_cast(mNode.mpNext); + + for(; (pNode != &mNode) && (n > 0); --n) + { + pNode->mValue = value; + pNode = static_cast(pNode->mpNext); + } + + if(n) + DoInsertValues((ListNodeBase*)&mNode, n, value); + else + erase(const_iterator((ListNodeBase*)pNode), (ListNodeBase*)&mNode); + } + + + template + template + inline void list::DoInsert(ListNodeBase* pNode, Integer n, Integer value, true_type) + { + DoInsertValues(pNode, static_cast(n), static_cast(value)); + } + + + template + template + inline void list::DoInsert(ListNodeBase* pNode, InputIterator first, InputIterator last, false_type) + { + for(; first != last; ++first) + DoInsertValue(pNode, *first); + } + + + template + inline void list::DoInsertValues(ListNodeBase* pNode, size_type n, const value_type& value) + { + for(; n > 0; --n) + DoInsertValue(pNode, value); + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED // If we can do variadic arguments... + template + template + inline void list::DoInsertValue(ListNodeBase* pNode, Args&&... args) + { + node_type* const pNodeNew = DoCreateNode(eastl::forward(args)...); + ((ListNodeBase*)pNodeNew)->insert(pNode); + #if EASTL_LIST_SIZE_CACHE + ++mSize; + #endif + } + #else + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline void list::DoInsertValue(ListNodeBase* pNode, value_type&& value) + { + node_type* const pNodeNew = DoCreateNode(eastl::move(value)); + ((ListNodeBase*)pNodeNew)->insert(pNode); + #if EASTL_LIST_SIZE_CACHE + ++mSize; + #endif + } + #endif + + template + inline void list::DoInsertValue(ListNodeBase* pNode, const value_type& value) + { + node_type* const pNodeNew = DoCreateNode(value); + ((ListNodeBase*)pNodeNew)->insert(pNode); + #if EASTL_LIST_SIZE_CACHE + ++mSize; + #endif + } + #endif + + + template + inline void list::DoErase(ListNodeBase* pNode) + { + pNode->remove(); + ((node_type*)pNode)->~node_type(); + DoFreeNode(((node_type*)pNode)); + #if EASTL_LIST_SIZE_CACHE + --mSize; + #endif + + /* Test version that uses union intermediates + union + { + ListNodeBase* mpBase; + node_type* mpNode; + } node = { pNode }; + + node.mpNode->~node_type(); + node.mpBase->remove(); + DoFreeNode(node.mpNode); + #if EASTL_LIST_SIZE_CACHE + --mSize; + #endif + */ + } + + + template + inline void list::DoSwap(this_type& x) + { + ListNodeBase::swap((ListNodeBase&)mNode, (ListNodeBase&)x.mNode); // We need to implement a special swap because we can't do a shallow swap. + eastl::swap(mAllocator, x.mAllocator); // We do this even if EASTL_ALLOCATOR_COPY_ENABLED is 0. + #if EASTL_LIST_SIZE_CACHE + eastl::swap(mSize, x.mSize); + #endif + } + + + template + inline bool list::validate() const + { + #if EASTL_LIST_SIZE_CACHE + size_type n = 0; + + for(const_iterator i(begin()), iEnd(end()); i != iEnd; ++i) + ++n; + + if(n != mSize) + return false; + #endif + + // To do: More validation. + return true; + } + + + template + inline int list::validate_iterator(const_iterator i) const + { + // To do: Come up with a more efficient mechanism of doing this. + + for(const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp) + { + if(temp == i) + return (isf_valid | isf_current | isf_can_dereference); + } + + if(i == end()) + return (isf_valid | isf_current); + + return isf_none; + } + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template + bool operator==(const list& a, const list& b) + { + typename list::const_iterator ia = a.begin(); + typename list::const_iterator ib = b.begin(); + typename list::const_iterator enda = a.end(); + + #if EASTL_LIST_SIZE_CACHE + if(a.size() == b.size()) + { + while((ia != enda) && (*ia == *ib)) + { + ++ia; + ++ib; + } + return (ia == enda); + } + return false; + #else + typename list::const_iterator endb = b.end(); + + while((ia != enda) && (ib != endb) && (*ia == *ib)) + { + ++ia; + ++ib; + } + return (ia == enda) && (ib == endb); + #endif + } + + template + bool operator<(const list& a, const list& b) + { + return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); + } + + template + bool operator!=(const list& a, const list& b) + { + return !(a == b); + } + + template + bool operator>(const list& a, const list& b) + { + return b < a; + } + + template + bool operator<=(const list& a, const list& b) + { + return !(b < a); + } + + template + bool operator>=(const list& a, const list& b) + { + return !(a < b); + } + + template + void swap(list& a, list& b) + { + a.swap(b); + } + + +} // namespace eastl + + +EA_RESTORE_SN_WARNING() + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + +#endif // Header include guard + + +// Check for Spore +//static_assert(sizeof(eastl::list) == 8, "sizeof(eastl::list) != 8"); + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/eastl/include/EASTL/map.h b/libs/eastl/include/EASTL/map.h new file mode 100644 index 0000000..7cd1b9b --- /dev/null +++ b/libs/eastl/include/EASTL/map.h @@ -0,0 +1,610 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_MAP_H +#define EASTL_MAP_H + + +#include +#include +#include +#include + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// EASTL_MAP_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_MAP_DEFAULT_NAME + #define EASTL_MAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " map" // Unless the user overrides something, this is "EASTL map". + #endif + + + /// EASTL_MULTIMAP_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_MULTIMAP_DEFAULT_NAME + #define EASTL_MULTIMAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " multimap" // Unless the user overrides something, this is "EASTL multimap". + #endif + + + /// EASTL_MAP_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_MAP_DEFAULT_ALLOCATOR + #define EASTL_MAP_DEFAULT_ALLOCATOR allocator_type(EASTL_MAP_DEFAULT_NAME) + #endif + + /// EASTL_MULTIMAP_DEFAULT_ALLOCATOR + /// + #ifndef EASTL_MULTIMAP_DEFAULT_ALLOCATOR + #define EASTL_MULTIMAP_DEFAULT_ALLOCATOR allocator_type(EASTL_MULTIMAP_DEFAULT_NAME) + #endif + + + + /// map + /// + /// Implements a canonical map. + /// + /// The large majority of the implementation of this class is found in the rbtree + /// base class. We control the behaviour of rbtree via template parameters. + /// + /// Pool allocation + /// If you want to make a custom memory pool for a map container, your pool + /// needs to contain items of type map::node_type. So if you have a memory + /// pool that has a constructor that takes the size of pool items and the + /// count of pool items, you would do this (assuming that MemoryPool implements + /// the Allocator interface): + /// typedef map, MemoryPool> WidgetMap; // Delare your WidgetMap type. + /// MemoryPool myPool(sizeof(WidgetMap::node_type), 100); // Make a pool of 100 Widget nodes. + /// WidgetMap myMap(&myPool); // Create a map that uses the pool. + /// + template , typename Allocator = EASTLAllocatorType> + class map + : public rbtree, Compare, Allocator, eastl::use_first >, true, true> + { + public: + typedef rbtree, Compare, Allocator, + eastl::use_first >, true, true> base_type; + typedef map this_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::key_type key_type; + typedef T mapped_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::insert_return_type insert_return_type; + typedef typename base_type::extract_key extract_key; + // Other types are inherited from the base class. + + using base_type::begin; + using base_type::end; + using base_type::find; + using base_type::lower_bound; + using base_type::upper_bound; + using base_type::mCompare; + using base_type::insert; + using base_type::erase; + + class value_compare + { + protected: + friend class map; + Compare compare; + value_compare(Compare c) : compare(c) {} + + public: + typedef bool result_type; + typedef value_type first_argument_type; + typedef value_type second_argument_type; + + bool operator()(const value_type& x, const value_type& y) const + { return compare(x.first, y.first); } + }; + + public: + map(const allocator_type& allocator = EASTL_MAP_DEFAULT_ALLOCATOR); + map(const Compare& compare, const allocator_type& allocator = EASTL_MAP_DEFAULT_ALLOCATOR); + map(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + map(this_type&& x); + map(this_type&& x, const allocator_type& allocator); + #endif + map(std::initializer_list ilist, const Compare& compare = Compare(), const allocator_type& allocator = EASTL_MAP_DEFAULT_ALLOCATOR); + + template + map(Iterator itBegin, Iterator itEnd); // allocator arg removed because VC7.1 fails on the default arg. To consider: Make a second version of this function without a default arg. + + #if EASTL_MOVE_SEMANTICS_ENABLED // The (this_type&& x) ctor above has the side effect of forcing us to make operator= visible in this subclass. + this_type& operator=(const this_type& x) { return (this_type&)base_type::operator=(x); } + this_type& operator=(std::initializer_list ilist) { return (this_type&)base_type::operator=(ilist); } + this_type& operator=(this_type&& x) { return (this_type&)base_type::operator=(eastl::move(x)); } + #endif + + public: + /// This is an extension to the C++ standard. We insert a default-constructed + /// element with the given key. The reason for this is that we can avoid the + /// potentially expensive operation of creating and/or copying a mapped_type + /// object on the stack. Note that C++11 move insertions and variadic emplace + /// support make this extension mostly no longer necessary. + insert_return_type insert(const Key& key); + + value_compare value_comp() const; + + size_type erase(const Key& key); + size_type count(const Key& key) const; + + eastl::pair equal_range(const Key& key); + eastl::pair equal_range(const Key& key) const; + + T& operator[](const Key& key); // Of map, multimap, set, and multimap, only map has operator[]. + #if EASTL_MOVE_SEMANTICS_ENABLED + T& operator[](Key&& key); + #endif + + }; // map + + + + + + + /// multimap + /// + /// Implements a canonical multimap. + /// + /// The large majority of the implementation of this class is found in the rbtree + /// base class. We control the behaviour of rbtree via template parameters. + /// + /// Pool allocation + /// If you want to make a custom memory pool for a multimap container, your pool + /// needs to contain items of type multimap::node_type. So if you have a memory + /// pool that has a constructor that takes the size of pool items and the + /// count of pool items, you would do this (assuming that MemoryPool implements + /// the Allocator interface): + /// typedef multimap, MemoryPool> WidgetMap; // Delare your WidgetMap type. + /// MemoryPool myPool(sizeof(WidgetMap::node_type), 100); // Make a pool of 100 Widget nodes. + /// WidgetMap myMap(&myPool); // Create a map that uses the pool. + /// + template , typename Allocator = EASTLAllocatorType> + class multimap + : public rbtree, Compare, Allocator, eastl::use_first >, true, false> + { + public: + typedef rbtree, Compare, Allocator, + eastl::use_first >, true, false> base_type; + typedef multimap this_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::key_type key_type; + typedef T mapped_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::node_type node_type; + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::insert_return_type insert_return_type; + typedef typename base_type::extract_key extract_key; + // Other types are inherited from the base class. + + using base_type::begin; + using base_type::end; + using base_type::find; + using base_type::lower_bound; + using base_type::upper_bound; + using base_type::mCompare; + using base_type::insert; + using base_type::erase; + + class value_compare + { + protected: + friend class multimap; + Compare compare; + value_compare(Compare c) : compare(c) {} + + public: + typedef bool result_type; + typedef value_type first_argument_type; + typedef value_type second_argument_type; + + bool operator()(const value_type& x, const value_type& y) const + { return compare(x.first, y.first); } + }; + + public: + multimap(const allocator_type& allocator = EASTL_MULTIMAP_DEFAULT_ALLOCATOR); + multimap(const Compare& compare, const allocator_type& allocator = EASTL_MULTIMAP_DEFAULT_ALLOCATOR); + multimap(const this_type& x); + #if EASTL_MOVE_SEMANTICS_ENABLED + multimap(this_type&& x); + multimap(this_type&& x, const allocator_type& allocator); + #endif + multimap(std::initializer_list ilist, const Compare& compare = Compare(), const allocator_type& allocator = EASTL_MULTIMAP_DEFAULT_ALLOCATOR); + + template + multimap(Iterator itBegin, Iterator itEnd); // allocator arg removed because VC7.1 fails on the default arg. To consider: Make a second version of this function without a default arg. + + #if EASTL_MOVE_SEMANTICS_ENABLED // The (this_type&& x) ctor above has the side effect of forcing us to make operator= visible in this subclass. + this_type& operator=(const this_type& x) { return (this_type&)base_type::operator=(x); } + this_type& operator=(std::initializer_list ilist) { return (this_type&)base_type::operator=(ilist); } + this_type& operator=(this_type&& x) { return (this_type&)base_type::operator=(eastl::move(x)); } + #endif + + public: + /// This is an extension to the C++ standard. We insert a default-constructed + /// element with the given key. The reason for this is that we can avoid the + /// potentially expensive operation of creating and/or copying a mapped_type + /// object on the stack. Note that C++11 move insertions and variadic emplace + /// support make this extension mostly no longer necessary. + insert_return_type insert(const Key& key); + + value_compare value_comp() const; + + size_type erase(const Key& key); + size_type count(const Key& key) const; + + eastl::pair equal_range(const Key& key); + eastl::pair equal_range(const Key& key) const; + + /// equal_range_small + /// This is a special version of equal_range which is optimized for the + /// case of there being few or no duplicated keys in the tree. + eastl::pair equal_range_small(const Key& key); + eastl::pair equal_range_small(const Key& key) const; + + }; // multimap + + + + + + /////////////////////////////////////////////////////////////////////// + // map + /////////////////////////////////////////////////////////////////////// + + template + inline map::map(const allocator_type& allocator) + : base_type(allocator) + { + } + + + template + inline map::map(const Compare& compare, const allocator_type& allocator) + : base_type(compare, allocator) + { + } + + + template + inline map::map(const this_type& x) + : base_type(x) + { + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline map::map(this_type&& x) + : base_type(eastl::move(x)) + { + } + + template + inline map::map(this_type&& x, const allocator_type& allocator) + : base_type(eastl::move(x), allocator) + { + } + #endif + + + template + inline map::map(std::initializer_list ilist, const Compare& compare, const allocator_type& allocator) + : base_type(ilist.begin(), ilist.end(), compare, allocator) + { + } + + + template + template + inline map::map(Iterator itBegin, Iterator itEnd) + : base_type(itBegin, itEnd, Compare(), EASTL_MAP_DEFAULT_ALLOCATOR) + { + } + + + template + inline typename map::insert_return_type + map::insert(const Key& key) + { + return base_type::DoInsertKey(true_type(), key); + } + + + template + inline typename map::value_compare + map::value_comp() const + { + return value_compare(mCompare); + } + + + template + inline typename map::size_type + map::erase(const Key& key) + { + const iterator it(find(key)); + + if(it != end()) // If it exists... + { + base_type::erase(it); + return 1; + } + return 0; + } + + + template + inline typename map::size_type + map::count(const Key& key) const + { + const const_iterator it(find(key)); + return (it != end()) ? 1 : 0; + } + + + template + inline eastl::pair::iterator, + typename map::iterator> + map::equal_range(const Key& key) + { + // The resulting range will either be empty or have one element, + // so instead of doing two tree searches (one for lower_bound and + // one for upper_bound), we do just lower_bound and see if the + // result is a range of size zero or one. + const iterator itLower(lower_bound(key)); + + if((itLower == end()) || mCompare(key, itLower.mpNode->mValue.first)) // If at the end or if (key is < itLower)... + return eastl::pair(itLower, itLower); + + iterator itUpper(itLower); + return eastl::pair(itLower, ++itUpper); + } + + + template + inline eastl::pair::const_iterator, + typename map::const_iterator> + map::equal_range(const Key& key) const + { + // See equal_range above for comments. + const const_iterator itLower(lower_bound(key)); + + if((itLower == end()) || mCompare(key, itLower.mpNode->mValue.first)) // If at the end or if (key is < itLower)... + return eastl::pair(itLower, itLower); + + const_iterator itUpper(itLower); + return eastl::pair(itLower, ++itUpper); + } + + + template + inline T& map::operator[](const Key& key) + { + iterator itLower(lower_bound(key)); // itLower->first is >= key. + + if((itLower == end()) || mCompare(key, (*itLower).first)) + { + itLower = base_type::DoInsertKey(true_type(), itLower, key); + } + + return (*itLower).second; + + // Reference implementation of this function, which may not be as fast: + //iterator it(base_type::insert(eastl::pair(key, T())).first); + //return it->second; + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline T& map::operator[](Key&& key) + { + iterator itLower(lower_bound(key)); // itLower->first is >= key. + + if((itLower == end()) || mCompare(key, (*itLower).first)) + { + itLower = base_type::DoInsertKey(true_type(), itLower, eastl::move(key)); + } + + return (*itLower).second; + + // Reference implementation of this function, which may not be as fast: + //iterator it(base_type::insert(eastl::pair(key, T())).first); + //return it->second; + } + #endif + + + + + + + /////////////////////////////////////////////////////////////////////// + // multimap + /////////////////////////////////////////////////////////////////////// + + template + inline multimap::multimap(const allocator_type& allocator) + : base_type(allocator) + { + } + + + template + inline multimap::multimap(const Compare& compare, const allocator_type& allocator) + : base_type(compare, allocator) + { + } + + + template + inline multimap::multimap(const this_type& x) + : base_type(x) + { + } + + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + inline multimap::multimap(this_type&& x) + : base_type(eastl::move(x)) + { + } + + template + inline multimap::multimap(this_type&& x, const allocator_type& allocator) + : base_type(eastl::move(x), allocator) + { + } + #endif + + + template + inline multimap::multimap(std::initializer_list ilist, const Compare& compare, const allocator_type& allocator) + : base_type(ilist.begin(), ilist.end(), compare, allocator) + { + } + + + template + template + inline multimap::multimap(Iterator itBegin, Iterator itEnd) + : base_type(itBegin, itEnd, Compare(), EASTL_MULTIMAP_DEFAULT_ALLOCATOR) + { + } + + + template + inline typename multimap::insert_return_type + multimap::insert(const Key& key) + { + return base_type::DoInsertKey(false_type(), key); + } + + + template + inline typename multimap::value_compare + multimap::value_comp() const + { + return value_compare(mCompare); + } + + + template + inline typename multimap::size_type + multimap::erase(const Key& key) + { + const eastl::pair range(equal_range(key)); + const size_type n = (size_type)eastl::distance(range.first, range.second); + base_type::erase(range.first, range.second); + return n; + } + + + template + inline typename multimap::size_type + multimap::count(const Key& key) const + { + const eastl::pair range(equal_range(key)); + return (size_type)eastl::distance(range.first, range.second); + } + + + template + inline eastl::pair::iterator, + typename multimap::iterator> + multimap::equal_range(const Key& key) + { + // There are multiple ways to implement equal_range. The implementation mentioned + // in the C++ standard and which is used by most (all?) commercial STL implementations + // is this: + // return eastl::pair(lower_bound(key), upper_bound(key)); + // + // This does two tree searches -- one for the lower bound and one for the + // upper bound. This works well for the case whereby you have a large container + // and there are lots of duplicated values. We provide an alternative version + // of equal_range called equal_range_small for cases where the user is confident + // that the number of duplicated items is only a few. + + return eastl::pair(lower_bound(key), upper_bound(key)); + } + + + template + inline eastl::pair::const_iterator, + typename multimap::const_iterator> + multimap::equal_range(const Key& key) const + { + // See comments above in the non-const version of equal_range. + return eastl::pair(lower_bound(key), upper_bound(key)); + } + + + template + inline eastl::pair::iterator, + typename multimap::iterator> + multimap::equal_range_small(const Key& key) + { + // We provide alternative version of equal_range here which works faster + // for the case where there are at most small number of potential duplicated keys. + const iterator itLower(lower_bound(key)); + iterator itUpper(itLower); + + while((itUpper != end()) && !mCompare(key, itUpper.mpNode->mValue.first)) + ++itUpper; + + return eastl::pair(itLower, itUpper); + } + + + template + inline eastl::pair::const_iterator, + typename multimap::const_iterator> + multimap::equal_range_small(const Key& key) const + { + // We provide alternative version of equal_range here which works faster + // for the case where there are at most small number of potential duplicated keys. + const const_iterator itLower(lower_bound(key)); + const_iterator itUpper(itLower); + + while((itUpper != end()) && !mCompare(key, itUpper.mpNode->mValue.first)) + ++itUpper; + + return eastl::pair(itLower, itUpper); + } + + + static_assert(sizeof(map) == 0x1C, "sizeof(map) != 1Ch"); + +} // namespace eastl + + +#endif // Header include guard + + + + diff --git a/libs/eastl/include/EASTL/memory.h b/libs/eastl/include/EASTL/memory.h new file mode 100644 index 0000000..b020a64 --- /dev/null +++ b/libs/eastl/include/EASTL/memory.h @@ -0,0 +1,1556 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// This file implements the following functions from the C++ standard that +// are found in the header: +// +// Temporary memory: +// get_temporary_buffer +// return_temporary_buffer +// +// Utility: +// late_constructed - Extention to standard functionality. +// +// Uninitialized operations: +// These are the same as the copy, fill, and fill_n algorithms, except that +// they *construct* the destination with the source values rather than assign +// the destination with the source values. +// +// uninitialized_copy +// uninitialized_copy_n +// uninitialized_move +// uninitialized_move_if_noexcept - Extention to standard functionality. +// uninitialized_move_n +// uninitialized_fill +// uninitialized_fill_n +// uninitialized_relocate - Extention to standard functionality. +// uninitialized_copy_ptr - Extention to standard functionality. +// uninitialized_move_ptr - Extention to standard functionality. +// uninitialized_move_ptr_if_noexcept- Extention to standard functionality. +// uninitialized_fill_ptr - Extention to standard functionality. +// uninitialized_fill_n_ptr - Extention to standard functionality. +// uninitialized_copy_fill - Extention to standard functionality. +// uninitialized_fill_copy - Extention to standard functionality. +// uninitialized_copy_copy - Extention to standard functionality. +// +// In-place destructor helpers: +// destruct(T*) +// destruct(first, last) +// +// Alignment +// align +// align_advance - Extention to standard functionality. +// +// Allocator-related +// uses_allocator +// allocator_arg_t +// allocator_arg +// +// Pointers +// pointer_traits +// +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_MEMORY_H +#define EASTL_MEMORY_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + #pragma warning(push, 0) +#endif +#include +#include +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4530) // C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc + #pragma warning(disable: 4146) // unary minus operator applied to unsigned type, result still unsigned + #pragma warning(disable: 4571) // catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught. +#endif + +EA_DISABLE_SN_WARNING(828); // The EDG SN compiler has a bug in its handling of variadic template arguments and mistakenly reports "parameter "args" was never referenced" + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + +namespace eastl +{ + + /// EASTL_TEMP_DEFAULT_NAME + /// + /// Defines a default container name in the absence of a user-provided name. + /// + #ifndef EASTL_TEMP_DEFAULT_NAME + #define EASTL_TEMP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " temp" // Unless the user overrides something, this is "EASTL temp". + #endif + + + /// addressof + /// + /// From the C++11 Standard, section 20.6.12.1 + /// Returns the actual address of the object or function referenced by r, even in the presence of an overloaded operator&. + /// + template + T* addressof(T& value) EA_NOEXCEPT + { + return reinterpret_cast(&const_cast(reinterpret_cast(value))); + } + + + /// get_temporary_buffer + /// + /// From the C++ standard, section 20.4.3: + /// 1 Effects: Obtains a pointer to storage sufficient to store up to n adjacent T objects. + /// 2 Returns: A pair containing the buffer's address and capacity (in the units of sizeof(T)), + /// or a pair of 0 values if no storage can be obtained. + /// + /// Note: The return value is space to hold T elements, but no T elements are constructed. + /// + /// Our implementation here differs slightly in that we have alignment, alignmentOffset, and pName arguments. + /// Note that you can use the EASTL_NAME_VAL macro to make names go away in release builds. + /// + /// Example usage: + /// pair pr = get_temporary_buffer(100, 0, 0, EASTL_NAME_VAL("Temp int array")); + /// memset(pr.first, 0, 100 * sizeof(int)); + /// return_temporary_buffer(pr.first); + /// + template + eastl::pair get_temporary_buffer(ptrdiff_t n, size_t alignment = 1, size_t alignmentOffset = 0, const char* pName = EASTL_TEMP_DEFAULT_NAME) + { + EASTLAllocatorType allocator(*EASTLAllocatorDefault(), pName); + return eastl::pair(static_cast(EASTLAllocAligned(allocator, n * sizeof(T), alignment, alignmentOffset)), n); + } + + + /// return_temporary_buffer + /// + /// From the C++ standard, section 20.4.3: + /// 3 Effects: Deallocates the buffer to which p points. + /// 4 Requires: The buffer shall have been previously allocated by get_temporary_buffer. + /// + /// Note: This function merely frees space and does not destruct any T elements. + /// + /// Example usage: + /// pair pr = get_temporary_buffer(300); + /// memset(pr.first, 0, 300 * sizeof(int)); + /// return_temporary_buffer(pr.first, pr.second); + /// + template + void return_temporary_buffer(T* p, ptrdiff_t n = 0) + { + EASTLAllocatorType& allocator(*EASTLAllocatorDefault()); + EASTLFree(allocator, p, n * sizeof(T)); + } + + + + /// late_constructed + /// + /// Implements a smart pointer type which separates the memory allocation of an object from + /// the object's construction. The primary use case is to declare a global variable of the + /// late_construction type, which allows the memory to be global but the constructor executes + /// at some point after main() begins as opposed to before main, which is often dangerous + /// for non-trivial types. + /// + /// The autoConstruct template parameter controls whether the object is automatically default + /// constructed upon first reference or must be manually constructed upon the first use of + /// operator * or ->. autoConstruct is convenient but it causes * and -> to be slightly slower + /// and may result in construction at an inconvenient time. + /// + /// While construction can be automatic or manual, automatic destruction support is always present. + /// Thus you aren't required in any case to manually call destruct. However, you may safely manually + /// destruct the object at any time before the late_constructed destructor is executed. + /// + /// You may still use late_constructed after calling destruct(), including calling construct() + /// again to reconstruct the instance. destruct returns the late_constructed instance to a + /// state equivalent to before construct was called. + /// + /// Caveat: While late_constructed instances can be declared in global scope and initialize + /// prior to main() executing, you cannot otherwise use such globally declared instances prior + /// to main with guaranteed behavior unless you can ensure that the late_constructed instance + /// is itself constructed prior to your use of it. + /// + /// Example usage (demonstrating manual-construction): + /// late_constructed gWidget; + /// + /// void main(){ + /// gWidget.construct(kScrollbarType, kVertical, "MyScrollbar"); + /// gWidget->SetValue(15); + /// gWidget.destruct(); + /// } + /// + /// Example usage (demonstrating auto-construction): + /// late_constructed gWidget; + /// + /// void main(){ + /// gWidget->SetValue(15); + /// // You may want to call destruct here, but aren't required to do so unless the Widget type requires it. + /// } + /// + template + class late_constructed + { + public: + typedef late_constructed this_type; + typedef T value_type; + typedef typename eastl::aligned_storage::value>::type storage_type; + + late_constructed() EA_NOEXCEPT // In the case of the late_constructed instance being at global scope, we rely on the + : mpValue(NULL) {} // compiler executing this constructor or placing the instance in auto-zeroed-at-startup memory. + + ~late_constructed() + { + if(mpValue) + (*mpValue).~value_type(); + } + + #if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED + template + void construct(Args&&... args) + { + if(!mpValue) + mpValue = new(&mStorage) value_type(eastl::forward(args)...); + } + #else + void construct() + { + if(!mpValue) + mpValue = new(&mStorage) value_type; + } + + #if EASTL_MOVE_SEMANTICS_ENABLED + template + void construct(A1&& a1) + { + if(!mpValue) + mpValue = new(&mStorage) value_type(eastl::forward(a1)); + } + + template + void construct(A1&& a1, A2&& a2) + { + if(!mpValue) + mpValue = new(&mStorage) value_type(eastl::forward(a1), eastl::forward(a2)); + } + + template + void construct(A1&& a1, A2&& a2, A3&& a3) + { + if(!mpValue) + mpValue = new(&mStorage) value_type(eastl::forward(a1), eastl::forward(a2), eastl::forward(a3)); + } + #endif + + template + void construct(const A1& a1) + { + if(!mpValue) + mpValue = new(&mStorage) value_type(a1); + } + + template + void construct(const A1& a1, const A2& a2) + { + if(!mpValue) + mpValue = new(&mStorage) value_type(a1, a2); + } + + template + void construct(const A1& a1, const A2& a2, const A3& a3) + { + if(!mpValue) + mpValue = new(&mStorage) value_type(a1, a2, a3); + } + #endif + + bool is_constructed() const EA_NOEXCEPT + { return mpValue != NULL; } + + void destruct() + { + if(mpValue) + { + (*mpValue).~value_type(); + mpValue = NULL; + } + } + + value_type& operator*() EA_NOEXCEPT + { + if(!mpValue) + construct(); + + EA_ANALYSIS_ASSUME(mpValue); + return *mpValue; + } + + value_type* operator->() EA_NOEXCEPT + { + if(!mpValue) + construct(); + return mpValue; + } + + value_type* get() EA_NOEXCEPT + { + if(!mpValue) + construct(); + return mpValue; + } + + protected: + storage_type mStorage; // Declared first because it may have aligment requirements, and it would be more space-efficient if it was first. + value_type* mpValue; + }; + + + // Specialization that doesn't auto-construct on demand. + template + class late_constructed : public late_constructed + { + public: + typedef late_constructed base_type; + + typename base_type::value_type& operator*() EA_NOEXCEPT + { EASTL_ASSERT(base_type::mpValue); return *base_type::mpValue; } + + typename base_type::value_type* operator->() EA_NOEXCEPT + { EASTL_ASSERT(base_type::mpValue); return base_type::mpValue; } + + typename base_type::value_type* get() EA_NOEXCEPT + { return base_type::mpValue; } + }; + + + + /// raw_storage_iterator + /// + /// From the C++11 Standard, section 20.6.10 p1 + /// raw_storage_iterator is provided to enable algorithms to store their results into uninitialized memory. + /// The formal template parameter OutputIterator is required to have its operator* return an object for + /// which operator& is defined and returns a pointer to T, and is also required to satisfy the requirements + /// of an output iterator (24.2.4). + + template + class raw_storage_iterator : public iterator + { + protected: + OutputIterator mIterator; + + public: + explicit raw_storage_iterator(OutputIterator iterator) + : mIterator(iterator) + { + } + + raw_storage_iterator& operator*() + { + return *this; + } + + raw_storage_iterator& operator=(const T& value) + { + ::new(eastl::addressof(*mIterator)) T(value); + return *this; + } + + raw_storage_iterator& operator++() + { + ++mIterator; + return *this; + } + + raw_storage_iterator operator++(int) + { + raw_storage_iterator tempIterator = *this; + ++mIterator; + return tempIterator; + } + }; + + + /// uninitialized_relocate (formerly named uninitialized_move prior to C++11) + /// + /// This utility is deprecated in favor of C++11 rvalue move functionality. + /// + /// uninitialized_relocate takes a constructed sequence of objects and an + /// uninitialized destination buffer. In the case of any exception thrown + /// while moving the objects, any newly constructed objects are guaranteed + /// to be destructed and the input left fully constructed. + /// + /// In the case where you need to do multiple moves atomically, split the + /// calls into uninitialized_relocate_start/abort/commit. + /// + /// uninitialized_relocate_start can possibly throw an exception. If it does, + /// you don't need to do anything. However, if it returns without throwing + /// an exception you need to guarantee that either uninitialized_relocate_abort + /// or uninitialized_relocate_commit is called. + /// + /// Both uninitialized_relocate_abort and uninitialize_move_commit are + /// guaranteed to not throw C++ exceptions. + namespace Internal + { + template + struct uninitialized_relocate_impl + { + template + static ForwardIteratorDest do_move_start(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) + { + typedef typename eastl::iterator_traits::value_type value_type; + + #if EASTL_EXCEPTIONS_ENABLED + ForwardIteratorDest origDest(dest); + try + { + for(; first != last; ++first, ++dest) + ::new((void*)&*dest) value_type(*first); + } + catch(...) + { + for(; origDest < dest; ++origDest) + (*origDest).~value_type(); + throw; + } + #else + for(; first != last; ++first, ++dest) + ::new((void*)&*dest) value_type(*first); + #endif + + return dest; + } + + template + static ForwardIteratorDest do_move_commit(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) //throw() + { + typedef typename eastl::iterator_traits::value_type value_type; + for(; first != last; ++first, ++dest) + (*first).~value_type(); + + return dest; + } + + template + static ForwardIteratorDest do_move_abort(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) //throw() + { + typedef typename eastl::iterator_traits::value_type value_type; + for(; first != last; ++first, ++dest) + (*dest).~value_type(); + return dest; + } + }; + + template <> + struct uninitialized_relocate_impl + { + template + static T* do_move_start(T* first, T* last, T* dest) + { + return (T*)memcpy(dest, first, (size_t)((uintptr_t)last - (uintptr_t)first)) + (last - first); + } + + template + static T* do_move_commit(T* first, T* last, T* dest) + { + return dest + (last - first); + } + + template + static T* do_move_abort(T* first, T* last, T* dest) + { + return dest + (last - first); + } + }; + } + + + /// uninitialized_relocate_start, uninitialized_relocate_commit, uninitialized_relocate_abort + /// + /// This utility is deprecated in favor of C++11 rvalue move functionality. + /// + /// After calling uninitialized_relocate_start, if it doesn't throw an exception, + /// both the source and destination iterators point to undefined data. If it + /// does throw an exception, the destination remains uninitialized and the source + /// is as it was before. + /// + /// In order to make the iterators valid again you need to call either uninitialized_relocate_abort + /// or uninitialized_relocate_commit. The abort call makes the original source + /// iterator valid again, and commit makes the destination valid. Both abort + /// and commit are guaranteed to not throw C++ exceptions. + /// + /// Example usage: + /// iterator dest2 = uninitialized_relocate_start(first, last, dest); + /// try { + /// // some code here that might throw an exception + /// } + /// catch(...) + /// { + /// uninitialized_relocate_abort(first, last, dest); + /// throw; + /// } + /// uninitialized_relocate_commit(first, last, dest); + /// + template + inline ForwardIteratorDest uninitialized_relocate_start(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) + { + typedef typename eastl::iterator_traits::iterator_category IC; + typedef typename eastl::iterator_traits::value_type value_type_input; + typedef typename eastl::iterator_traits::value_type value_type_output; + + const bool bHasTrivialMove = type_and::value, + is_pointer::value, + is_pointer::value, + is_same::value>::value; + + return Internal::uninitialized_relocate_impl::do_move_start(first, last, dest); + } + + template + inline ForwardIteratorDest uninitialized_relocate_commit(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) + { + typedef typename eastl::iterator_traits::iterator_category IC; + typedef typename eastl::iterator_traits::value_type value_type_input; + typedef typename eastl::iterator_traits::value_type value_type_output; + + const bool bHasTrivialMove = type_and::value, + is_pointer::value, + is_pointer::value, + is_same::value>::value; + + return Internal::uninitialized_relocate_impl::do_move_commit(first, last, dest); + } + + template + inline ForwardIteratorDest uninitialized_relocate_abort(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) + { + typedef typename eastl::iterator_traits::iterator_category IC; + typedef typename eastl::iterator_traits::value_type value_type_input; + typedef typename eastl::iterator_traits::value_type value_type_output; + + const bool bHasTrivialMove = type_and::value, + is_pointer::value, + is_pointer::value, + is_same::value>::value; + + return Internal::uninitialized_relocate_impl::do_move_abort(first, last, dest); + } + + /// uninitialized_relocate + /// + /// See above for documentation. + /// + template + inline ForwardIteratorDest uninitialized_relocate(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) + { + ForwardIteratorDest result = uninitialized_relocate_start(first, last, dest); + eastl::uninitialized_relocate_commit(first, last, dest); + + return result; + } + + + + + + // uninitialized_copy + // + namespace Internal + { + template + inline ForwardIterator uninitialized_copy_impl(InputIterator first, InputIterator last, ForwardIterator dest, true_type) + { + return eastl::copy(first, last, dest); // The copy() in turn will use memcpy for POD types. + } + + template + inline ForwardIterator uninitialized_copy_impl(InputIterator first, InputIterator last, ForwardIterator dest, false_type) + { + typedef typename eastl::iterator_traits::value_type value_type; + ForwardIterator currentDest(dest); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + for(; first != last; ++first, ++currentDest) + ::new((void*)&*currentDest) value_type(*first); + } + catch(...) + { + for(; dest < currentDest; ++dest) + (*dest).~value_type(); + throw; + } + #else + for(; first != last; ++first, ++currentDest) + ::new((void*)&*currentDest) value_type(*first); + #endif + + return currentDest; + } + } + + /// uninitialized_copy + /// + /// Copies a source range to a destination, copy-constructing the destination with + /// the source values (and not *assigning* the destination with the source values). + /// Returns the end of the destination range (i.e. dest + (last - first)). + /// + /// Declaration: + /// template + /// ForwardIterator uninitialized_copy(InputIterator sourceFirst, InputIterator sourceLast, ForwardIterator destination); + /// + /// Example usage: + /// SomeClass* pArray = malloc(10 * sizeof(SomeClass)); + /// uninitialized_copy(pSourceDataBegin, pSourceDataBegin + 10, pArray); + /// + template + inline ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result) + { + typedef typename eastl::iterator_traits::value_type value_type; + + // We use is_trivial, which in the C++11 Standard means is_trivially_copyable and is_trivially_default_constructible. + return Internal::uninitialized_copy_impl(first, last, result, eastl::is_trivial()); + } + + + /// uninitialized_copy_n + /// + /// Copies count elements from a range beginning at first to an uninitialized memory area + /// beginning at dest. The elements in the uninitialized area are constructed using copy constructor. + /// If an exception is thrown during the initialization, the function has no final effects. + /// + /// first: Beginning of the range of the elements to copy. + /// dest: Beginning of the destination range. + /// return value: Iterator of dest type to the element past the last element copied. + /// + namespace Internal + { + template + struct uninitialized_copy_n_impl + { + static ForwardIterator impl(InputIterator first, Count n, ForwardIterator dest) + { + typedef typename eastl::iterator_traits::value_type value_type; + ForwardIterator currentDest(dest); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + for(; n > 0; --n, ++first, ++currentDest) + ::new((void*)&*currentDest) value_type(*first); + } + catch(...) + { + for(; dest < currentDest; ++dest) + (*dest).~value_type(); + throw; + } + #else + for(; n > 0; --n, ++first, ++currentDest) + ::new((void*)&*currentDest) value_type(*first); + #endif + + return currentDest; + } + }; + + template + struct uninitialized_copy_n_impl + { + static inline ForwardIterator impl(InputIterator first, Count n, ForwardIterator dest) + { + return eastl::uninitialized_copy(first, first + n, dest); + } + }; + } + + template + inline ForwardIterator uninitialized_copy_n(InputIterator first, Count n, ForwardIterator dest) + { + typedef typename eastl::iterator_traits::iterator_category IC; + return Internal::uninitialized_copy_n_impl::impl(first, n, dest); + } + + + + /// uninitialized_copy_ptr + /// + /// This is a specialization of uninitialized_copy for iterators that are pointers. We use it because + /// internally it uses generic_iterator to make pointers act like regular eastl::iterator. + /// + template + inline Result uninitialized_copy_ptr(First first, Last last, Result result) + { + typedef typename eastl::iterator_traits >::value_type value_type; + const generic_iterator i(Internal::uninitialized_copy_impl(eastl::generic_iterator(first), // generic_iterator makes a pointer act like an iterator. + eastl::generic_iterator(last), + eastl::generic_iterator(result), + eastl::is_trivially_copy_assignable())); + return i.base(); + } + + + + /// uninitialized_move_ptr + /// + /// This is a specialization of uninitialized_move for iterators that are pointers. We use it because + /// internally it uses generic_iterator to make pointers act like regular eastl::iterator. + /// + #if EASTL_MOVE_SEMANTICS_ENABLED + namespace Internal + { + template + inline ForwardIterator uninitialized_move_impl(InputIterator first, InputIterator last, ForwardIterator dest, true_type) + { + return eastl::copy(first, last, dest); // The copy() in turn will use memcpy for is_trivially_copy_assignable (e.g. POD) types. + } + + template + inline ForwardIterator uninitialized_move_impl(InputIterator first, InputIterator last, ForwardIterator dest, false_type) + { + typedef typename eastl::iterator_traits::value_type value_type; + ForwardIterator currentDest(dest); + + // We must run a loop over every element and move-construct it at the new location. + #if EASTL_EXCEPTIONS_ENABLED + try + { + for(; first != last; ++first, ++currentDest) + ::new((void*)&*currentDest) value_type(eastl::move(*first)); // If value_type has a move constructor then it will be used here. + } + catch(...) + { + // We have a problem here: If an exception occurs while doing the loop below then we will + // have values that were moved from the source to the dest that may need to be moved back + // in the catch. What does the C++11 Standard say about this? And what happens if there's an + // exception while moving them back? We may want to trace through a conforming C++11 Standard + // Library to see what it does and do something similar. Given that rvalue references are + // objects that are going away, we may not need to move the values back, though that has the + // side effect of a certain kind of lost elements problem. + for(; dest < currentDest; ++dest) + (*dest).~value_type(); + throw; + } + #else + for(; first != last; ++first, ++currentDest) + ::new((void*)&*currentDest) value_type(eastl::move(*first)); // If value_type has a move constructor then it will be used here. + #endif + + return currentDest; + } + } + + template + inline Result uninitialized_move_ptr(First first, Last last, Result dest) + { + typedef typename eastl::iterator_traits >::value_type value_type; + const generic_iterator i(Internal::uninitialized_move_impl(eastl::generic_iterator(first), // generic_iterator makes a pointer act like an iterator. + eastl::generic_iterator(last), + eastl::generic_iterator(dest), + eastl::is_trivially_copy_assignable())); // is_trivially_copy_assignable identifies if copy assignment would be as valid as move assignment, which means we have the opportunity to memcpy/memmove optimization. + return i.base(); + } + #else + template + inline Result uninitialized_move_ptr(First first, Last last, Result dest) + { + return uninitialized_copy_ptr(first, last, dest); + } + #endif + + + + + /// uninitialized_move + /// + /// Moves a source range to a destination, move-constructing the destination with + /// the source values (and not *assigning* the destination with the source values). + /// Returns the end of the destination range (i.e. dest + (last - first)). + /// + /// uninitialized_move is not part of any current C++ Standard, up to C++14. + /// + /// Declaration: + /// template + /// ForwardIterator uninitialized_move(InputIterator sourceFirst, InputIterator sourceLast, ForwardIterator destination); + /// + /// Example usage: + /// SomeClass* pArray = malloc(10 * sizeof(SomeClass)); + /// uninitialized_move(pSourceDataBegin, pSourceDataBegin + 10, pArray); + /// + template + inline ForwardIterator uninitialized_move(InputIterator first, InputIterator last, ForwardIterator dest) + { + #if EASTL_MOVE_SEMANTICS_ENABLED + return eastl::uninitialized_copy(eastl::make_move_iterator(first), eastl::make_move_iterator(last), dest); + #else + return eastl::uninitialized_copy(first, last, dest); + #endif + } + + + /// uninitialized_move_if_noexcept + /// + /// If the iterated type can be moved without exceptions, move construct the dest with the input. Else copy-construct + /// the dest witih the input. If move isn't supported by the compiler, do regular copy. + /// + template + inline ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest) + { + #if EASTL_MOVE_SEMANTICS_ENABLED + return eastl::uninitialized_copy(eastl::make_move_if_noexcept_iterator(first), eastl::make_move_if_noexcept_iterator(last), dest); + #else + return eastl::uninitialized_copy(first, last, dest); + #endif + } + + + /// uninitialized_move_ptr_if_noexcept + /// + template + inline Result uninitialized_move_ptr_if_noexcept(First first, Last last, Result dest) + { + #if EASTL_EXCEPTIONS_ENABLED + return eastl::uninitialized_move_if_noexcept(first, last, dest); + #else + return eastl::uninitialized_move_ptr(first, last, dest); + #endif + } + + + /// uninitialized_move_n + /// + /// Moves count elements from a range beginning at first to an uninitialized memory area + /// beginning at dest. The elements in the uninitialized area are constructed using copy constructor. + /// If an exception is thrown during the initialization, the function has no final effects. + /// + /// first: Beginning of the range of the elements to move. + /// dest: Beginning of the destination range. + /// return value: Iterator of dest type to the element past the last element moved. + /// + template + inline ForwardIterator uninitialized_move_n(InputIterator first, Count n, ForwardIterator dest) + { + #if EASTL_MOVE_SEMANTICS_ENABLED + return eastl::uninitialized_copy_n(eastl::make_move_iterator(first), n, dest); + #else + return eastl::uninitialized_copy_n(first, n, dest); + #endif + } + + // Disable warning C4345 - behavior change: an object of POD type constructed with an initializer of the form () + // will be default-initialized. + // This is the behavior we intend below. + EA_DISABLE_VC_WARNING(4345) + /// uninitialized_default_fill + /// + /// Default-constructs the elements in the destination range. + /// Returns void. It wouldn't be useful to return the end of the destination range, + /// as that is the same as the 'last' input parameter. + /// + /// Declaration: + /// template + /// void uninitialized_default_fill(ForwardIterator destinationFirst, ForwardIterator destinationLast); + /// + template + inline void uninitialized_default_fill(ForwardIterator first, ForwardIterator last) + { + typedef typename eastl::iterator_traits::value_type value_type; + ForwardIterator currentDest(first); + +#if EASTL_EXCEPTIONS_ENABLED + try + { + for (; currentDest != last; ++currentDest) + ::new (static_cast(&*currentDest)) value_type(); + } + catch (...) + { + for (; first < currentDest; ++first) + (*first).~value_type(); + throw; + } +#else + for (; currentDest != last; ++currentDest) + ::new (static_cast(&*currentDest)) value_type(); +#endif + } + + /// uninitialized_default_fill_n + /// + /// Default-constructs the range of [first, first + n). + /// Returns void as per the C++ standard, though returning the end input iterator + /// value may be of use. + /// + /// Declaration: + /// template + /// void uninitialized_default_fill_n(ForwardIterator destination, Count n); + /// + template + inline void uninitialized_default_fill_n(ForwardIterator first, Count n) + { + typedef typename eastl::iterator_traits::value_type value_type; + ForwardIterator currentDest(first); + +#if EASTL_EXCEPTIONS_ENABLED + try + { + for (; n > 0; --n, ++currentDest) + ::new (static_cast(&*currentDest)) value_type(); + } + catch (...) + { + for (; first < currentDest; ++first) + (*first).~value_type(); + throw; + } +#else + for (; n > 0; --n, ++currentDest) + ::new (static_cast(&*currentDest)) value_type(); +#endif + } + EA_RESTORE_VC_WARNING() + + /// uninitialized_fill + /// + /// Copy-constructs the elements in the destination range with the given input value. + /// Returns void. It wouldn't be useful to return the end of the destination range, + /// as that is the same as the 'last' input parameter. + /// + /// Declaration: + /// template + /// void uninitialized_fill(ForwardIterator destinationFirst, ForwardIterator destinationLast, const T& value); + /// + namespace Internal + { + template + inline void uninitialized_fill_impl(ForwardIterator first, ForwardIterator last, const T& value, true_type) + { + eastl::fill(first, last, value); + } + + template + void uninitialized_fill_impl(ForwardIterator first, ForwardIterator last, const T& value, false_type) + { + typedef typename eastl::iterator_traits::value_type value_type; + ForwardIterator currentDest(first); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + for(; currentDest != last; ++currentDest) + ::new((void*)&*currentDest) value_type(value); + } + catch(...) + { + for(; first < currentDest; ++first) + (*first).~value_type(); + throw; + } + #else + for(; currentDest != last; ++currentDest) + ::new((void*)&*currentDest) value_type(value); + #endif + } + } + + template + inline void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& value) + { + typedef typename eastl::iterator_traits::value_type value_type; + Internal::uninitialized_fill_impl(first, last, value, eastl::is_trivially_copy_assignable()); + } + + + + /// uninitialized_fill_ptr + /// + /// This is a specialization of uninitialized_fill for iterators that are pointers. + /// It exists so that we can declare a value_type for the iterator, which you + /// can't do with a pointer by itself. + /// + template + inline void uninitialized_fill_ptr(T* first, T* last, const T& value) + { + typedef typename eastl::iterator_traits >::value_type value_type; + Internal::uninitialized_fill_impl(eastl::generic_iterator(first), eastl::generic_iterator(last), value, eastl::is_trivially_copy_assignable()); + } + + + + /// uninitialized_fill_n + /// + /// Copy-constructs the range of [first, first + n) with the given input value. + /// Returns void as per the C++ standard, though returning the end input iterator + /// value may be of use. + /// + /// Declaration: + /// template + /// void uninitialized_fill_n(ForwardIterator destination, Count n, const T& value); + /// + namespace Internal + { + template + inline void uninitialized_fill_n_impl(ForwardIterator first, Count n, const T& value, true_type) + { + eastl::fill_n(first, n, value); + } + + template + void uninitialized_fill_n_impl(ForwardIterator first, Count n, const T& value, false_type) + { + typedef typename eastl::iterator_traits::value_type value_type; + ForwardIterator currentDest(first); + + #if EASTL_EXCEPTIONS_ENABLED + try + { + for(; n > 0; --n, ++currentDest) + ::new((void*)&*currentDest) value_type(value); + } + catch(...) + { + for(; first < currentDest; ++first) + (*first).~value_type(); + throw; + } + #else + for(; n > 0; --n, ++currentDest) + ::new((void*)&*currentDest) value_type(value); + #endif + } + } + + template + inline void uninitialized_fill_n(ForwardIterator first, Count n, const T& value) + { + typedef typename eastl::iterator_traits::value_type value_type; + Internal::uninitialized_fill_n_impl(first, n, value, eastl::is_trivially_copy_assignable()); + } + + + + /// uninitialized_fill_n_ptr + /// + /// This is a specialization of uninitialized_fill_n for iterators that are pointers. + /// It exists so that we can declare a value_type for the iterator, which you + /// can't do with a pointer by itself. + /// + template + inline void uninitialized_fill_n_ptr(T* first, Count n, const T& value) + { + typedef typename eastl::iterator_traits >::value_type value_type; + Internal::uninitialized_fill_n_impl(eastl::generic_iterator(first), n, value, eastl::is_trivially_copy_assignable()); + } + + + + + /// uninitialized_copy_fill + /// + /// Copies [first1, last1) into [first2, first2 + (last1 - first1)) then + /// fills [first2 + (last1 - first1), last2) with value. + /// + template + inline void uninitialized_copy_fill(InputIterator first1, InputIterator last1, + ForwardIterator first2, ForwardIterator last2, const T& value) + { + const ForwardIterator mid(eastl::uninitialized_copy(first1, last1, first2)); + + #if EASTL_EXCEPTIONS_ENABLED + typedef typename eastl::iterator_traits::value_type value_type; + try + { + #endif + eastl::uninitialized_fill(mid, last2, value); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + for(; first2 < mid; ++first2) + (*first2).~value_type(); + throw; + } + #endif + } + + + /// uninitialized_move_fill + /// + /// Moves [first1, last1) into [first2, first2 + (last1 - first1)) then + /// fills [first2 + (last1 - first1), last2) with value. + /// + template + inline void uninitialized_move_fill(InputIterator first1, InputIterator last1, + ForwardIterator first2, ForwardIterator last2, const T& value) + { + const ForwardIterator mid(eastl::uninitialized_move(first1, last1, first2)); + + #if EASTL_EXCEPTIONS_ENABLED + typedef typename eastl::iterator_traits::value_type value_type; + try + { + #endif + eastl::uninitialized_fill(mid, last2, value); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + for(; first2 < mid; ++first2) + (*first2).~value_type(); + throw; + } + #endif + } + + + + + + /// uninitialized_fill_copy + /// + /// Fills [result, mid) with value then copies [first, last) into [mid, mid + (last - first)). + /// + template + inline ForwardIterator + uninitialized_fill_copy(ForwardIterator result, ForwardIterator mid, const T& value, InputIterator first, InputIterator last) + { + eastl::uninitialized_fill(result, mid, value); + + #if EASTL_EXCEPTIONS_ENABLED + typedef typename eastl::iterator_traits::value_type value_type; + try + { + #endif + return eastl::uninitialized_copy(first, last, mid); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + for(; result < mid; ++result) + (*result).~value_type(); + throw; + } + #endif + } + + + /// uninitialized_fill_move + /// + /// Fills [result, mid) with value then copies [first, last) into [mid, mid + (last - first)). + /// + template + inline ForwardIterator + uninitialized_fill_move(ForwardIterator result, ForwardIterator mid, const T& value, InputIterator first, InputIterator last) + { + eastl::uninitialized_fill(result, mid, value); + + #if EASTL_EXCEPTIONS_ENABLED + typedef typename eastl::iterator_traits::value_type value_type; + try + { + #endif + return eastl::uninitialized_move(first, last, mid); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + for(; result < mid; ++result) + (*result).~value_type(); + throw; + } + #endif + } + + + + /// uninitialized_copy_copy + /// + /// Copies [first1, last1) into [result, result + (last1 - first1)) then + /// copies [first2, last2) into [result, result + (last1 - first1) + (last2 - first2)). + /// + template + inline ForwardIterator + uninitialized_copy_copy(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + ForwardIterator result) + { + const ForwardIterator mid(eastl::uninitialized_copy(first1, last1, result)); + + #if EASTL_EXCEPTIONS_ENABLED + typedef typename eastl::iterator_traits::value_type value_type; + try + { + #endif + return eastl::uninitialized_copy(first2, last2, mid); + #if EASTL_EXCEPTIONS_ENABLED + } + catch(...) + { + for(; result < mid; ++result) + (*result).~value_type(); + throw; + } + #endif + } + + + + /// destruct + /// + /// Calls the destructor of a given object. + /// + /// Note that we don't have a specialized version of this for objects + /// with trivial destructors, such as integers. This is because the + /// compiler can already see in our version here that the destructor + /// is a no-op. + /// + template + inline void destruct(T* p) + { + p->~T(); + } + + + + // destruct(first, last) + // + template + inline void destruct_impl(ForwardIterator /*first*/, ForwardIterator /*last*/, true_type) // true means the type has a trivial destructor. + { + // Empty. The type has a trivial destructor. + } + + template + inline void destruct_impl(ForwardIterator first, ForwardIterator last, false_type) // false means the type has a significant destructor. + { + typedef typename eastl::iterator_traits::value_type value_type; + + for(; first != last; ++first) + (*first).~value_type(); + } + + /// destruct + /// + /// Calls the destructor on a range of objects. + /// + /// We have a specialization for objects with trivial destructors, such as + /// PODs. In this specialization the destruction of the range is a no-op. + /// + template + inline void destruct(ForwardIterator first, ForwardIterator last) + { + typedef typename eastl::iterator_traits::value_type value_type; + destruct_impl(first, last, eastl::has_trivial_destructor()); + } + + + /// align + /// + /// Same as C++11 std::align. http://en.cppreference.com/w/cpp/memory/align + /// If it is possible to fit size bytes of storage aligned by alignment into the buffer pointed to by + /// ptr with length space, the function updates ptr to point to the first possible address of such storage, + /// decreases space by the number of bytes used for alignment, and returns the new ptr value. Otherwise, + /// the function returns NULL and leaves ptr and space unmodified. + /// + /// Example usage: + /// char buffer[512]; + /// size_t space = sizeof(buffer); + /// void* p = buffer; + /// void* p1 = eastl::align(16, 3, p, space); p = (char*)p + 3; space -= 3; + /// void* p2 = eastl::align(32, 78, p, space); p = (char*)p + 78; space -= 78; + /// void* p3 = eastl::align(64, 9, p, space); p = (char*)p + 9; space -= 9; + + inline void* align(size_t alignment, size_t size, void*& ptr, size_t& space) + { + if(space >= size) + { + char* ptrAligned = (char*)(((size_t)ptr + (alignment - 1)) & -alignment); + size_t offset = (size_t)(ptrAligned - (char*)ptr); + + if((space - size) >= offset) // Have to implement this in terms of subtraction instead of addition in order to handle possible overflow. + { + ptr = ptrAligned; + space -= offset; + + return ptrAligned; + } + } + + return NULL; + } + + + /// align_advance + /// + /// Same as align except ptr and space can be adjusted to reflect remaining space. + /// Not present in the C++ Standard. + /// Note that the example code here is similar to align but simpler. + /// + /// Example usage: + /// char buffer[512]; + /// size_t space = sizeof(buffer); + /// void* p = buffer; + /// void* p1 = eastl::align_advance(16, 3, p, space, &p, &space); // p is advanced and space reduced accordingly. + /// void* p2 = eastl::align_advance(32, 78, p, space, &p, &space); + /// void* p3 = eastl::align_advance(64, 9, p, space, &p, &space); + /// void* p4 = eastl::align_advance(16, 33, p, space); + + inline void* align_advance(size_t alignment, size_t size, void* ptr, size_t space, void** ptrAdvanced = NULL, size_t* spaceReduced = NULL) + { + if(space >= size) + { + char* ptrAligned = (char*)(((size_t)ptr + (alignment - 1)) & -alignment); + size_t offset = (size_t)(ptrAligned - (char*)ptr); + + if((space - size) >= offset) // Have to implement this in terms of subtraction instead of addition in order to handle possible overflow. + { + if(ptrAdvanced) + *ptrAdvanced = (ptrAligned + size); + if(spaceReduced) + *spaceReduced = (space - (offset + size)); + + return ptrAligned; + } + } + + return NULL; + } + + + /////////////////////////////////////////////////////////////////////// + // uses_allocator + // + // Determines if the class T has an allocator_type member typedef + // which Allocator is convertible to. + // + // http://en.cppreference.com/w/cpp/memory/uses_allocator + // + // A program may specialize this template to derive from true_type for a + // user-defined type T that does not have a nested allocator_type but + // nonetheless can be constructed with an allocator where either: + // - the first argument of a constructor has type allocator_arg_t and + // the second argument has type Allocator. + // or + // - the last argument of a constructor has type Allocator. + // + // Example behavilor: + // uses_allocator::value => true + // uses_allocator::value => false + // + // This is useful for writing generic code for containers when you can't + // know ahead of time that the container has an allocator_type. + /////////////////////////////////////////////////////////////////////// + + template + struct has_allocator_type_helper + { + private: + template + static eastl::no_type test(...); + + template + static eastl::yes_type test(typename U::allocator_type* = NULL); + + public: + static const bool value = sizeof(test(NULL)) == sizeof(eastl::yes_type); + }; + + + template ::value> + struct uses_allocator_impl + : public integral_constant::value> + { + }; + + template + struct uses_allocator_impl + : public eastl::false_type + { + }; + + template + struct uses_allocator + : public uses_allocator_impl{ }; + + + + + + /////////////////////////////////////////////////////////////////////// + // pointer_traits + // + // C++11 Standard section 20.6.3 + // Provides information about a pointer type, mostly for the purpose + // of handling the case where the pointer type isn't a built-in T* but + // rather is a class that acts like a pointer. + // + // A user-defined Pointer has the following properties, by example: + // template + // struct Pointer + // { + // typedef Pointer pointer; // required for use by pointer_traits. + // typedef T1 element_type; // optional for use by pointer_traits. + // typedef T2 difference_type; // optional for use by pointer_traits. + // + // template + // using rebind = typename Ptr; // optional for use by pointer_traits. + // + // static pointer pointer_to(element_type& obj); // required for use by pointer_traits. + // }; + // + // + // Example usage: + // template + // typename pointer_traits::element_type& GetElementPointedTo(Pointer p) + // { return *p; } + // + /////////////////////////////////////////////////////////////////////// + + namespace Internal + { + // pointer_element_type + template + struct has_element_type // has_element_type::value is true if T has an element_type member typedef. + { + private: + template static eastl::no_type test(...); + template static eastl::yes_type test(typename U::element_type* = 0); + public: + static const bool value = sizeof(test(0)) == sizeof(eastl::yes_type); + }; + + template ::value> + struct pointer_element_type; + + template + struct pointer_element_type + { typedef typename Pointer::element_type type; }; + + #if EASTL_VARIADIC_TEMPLATES_ENABLED // See 20.6.3.1 p3 for why we need to support this. Pointer may be a template with various arguments as opposed to a non-templated class. + template

W9j`OE^t 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

W9j`OE^t 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