mirror of
https://github.com/electronicarts/EASTL.git
synced 2026-01-18 17:21:19 +01:00
3.10.00 release
This commit is contained in:
@@ -70,24 +70,3 @@ popd
|
||||
popd
|
||||
```
|
||||
|
||||
### Building using Buck
|
||||
|
||||
EASTL can also be built using [Buck Build](https://www.buckbuild.com).
|
||||
|
||||
To build EASTL:
|
||||
|
||||
```bash=
|
||||
buck build :eastl
|
||||
```
|
||||
|
||||
To run the tests:
|
||||
|
||||
```bash=
|
||||
buck run :test-runner
|
||||
```
|
||||
|
||||
To run the benchmarks:
|
||||
|
||||
```bash=
|
||||
buck run :benchmark
|
||||
```
|
||||
|
||||
@@ -64,13 +64,13 @@ int VPCompareC(const void* elem1, const void* elem2)
|
||||
}
|
||||
|
||||
|
||||
typedef std::vector<ValuePair> StdVectorVP;
|
||||
typedef eastl::vector<ValuePair> EaVectorVP;
|
||||
typedef std::vector<ValuePair> StdVectorVP;
|
||||
typedef eastl::vector<ValuePair> EaVectorVP;
|
||||
|
||||
typedef std::vector<uint32_t> StdVectorInt;
|
||||
typedef eastl::vector<uint32_t> EaVectorInt;
|
||||
typedef std::vector<uint32_t> StdVectorInt;
|
||||
typedef eastl::vector<uint32_t> EaVectorInt;
|
||||
|
||||
typedef std::vector<TestObject> StdVectorTO;
|
||||
typedef std::vector<TestObject> StdVectorTO;
|
||||
typedef eastl::vector<TestObject> EaVectorTO;
|
||||
|
||||
|
||||
@@ -155,22 +155,21 @@ namespace
|
||||
{
|
||||
enum SortFunctionType
|
||||
{
|
||||
sf_qsort, // C qsort
|
||||
sf_shell_sort, // eastl::shell_sort.
|
||||
sf_heap_sort, // eastl::heap_sort
|
||||
sf_merge_sort, // eastl::merge_sort
|
||||
sf_merge_sort_buffer, // eastl::merge_sort_buffer
|
||||
sf_comb_sort, // eastl::comb_sort
|
||||
sf_bubble_sort, // eastl::bubble_sort
|
||||
sf_selection_sort, // eastl::selection_sort
|
||||
sf_shaker_sort, // eastl::shaker_sort
|
||||
sf_quick_sort, // eastl::quick_sort
|
||||
sf_tim_sort, // eastl::tim_sort
|
||||
sf_insertion_sort, // eastl::insertion_sort
|
||||
sf_std_sort, // std::sort
|
||||
sf_std_stable_sort, // std::stable_sort
|
||||
sf_radix_sort, // eastl::radix_sort (unconventional sort)
|
||||
sf_count //
|
||||
sf_qsort, // C qsort
|
||||
sf_shell_sort, // eastl::shell_sort.
|
||||
sf_heap_sort, // eastl::heap_sort
|
||||
sf_merge_sort, // eastl::merge_sort
|
||||
sf_merge_sort_buffer, // eastl::merge_sort_buffer
|
||||
sf_comb_sort, // eastl::comb_sort
|
||||
sf_bubble_sort, // eastl::bubble_sort
|
||||
sf_selection_sort, // eastl::selection_sort
|
||||
sf_shaker_sort, // eastl::shaker_sort
|
||||
sf_quick_sort, // eastl::quick_sort
|
||||
sf_tim_sort, // eastl::tim_sort
|
||||
sf_insertion_sort, // eastl::insertion_sort
|
||||
sf_std_sort, // std::sort
|
||||
sf_radix_sort, // eastl::radix_sort (unconventional sort)
|
||||
sf_count //
|
||||
};
|
||||
|
||||
const char* GetSortFunctionName(int sortFunctionType)
|
||||
@@ -219,9 +218,6 @@ namespace
|
||||
case sf_std_sort:
|
||||
return "std::sort";
|
||||
|
||||
case sf_std_stable_sort:
|
||||
return "std::stable_sort";
|
||||
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
@@ -230,10 +226,10 @@ namespace
|
||||
|
||||
enum RandomizationType
|
||||
{
|
||||
kRandom, // Completely random data.
|
||||
kRandom, // Completely random data.
|
||||
kRandomSorted, // Random values already sorted.
|
||||
kOrdered, // Already sorted.
|
||||
kMostlyOrdered, // Partly sorted already.
|
||||
kOrdered, // Already sorted.
|
||||
kMostlyOrdered, // Partly sorted already.
|
||||
kRandomizationTypeCount
|
||||
};
|
||||
|
||||
@@ -285,26 +281,21 @@ namespace
|
||||
|
||||
case kOrdered:
|
||||
{
|
||||
for (eastl_size_t i = 0; i < v.size(); ++i)
|
||||
v[i] = value_type((value_type)i); // Note that value_type may be a struct and not an integer. Thus
|
||||
// the casting and construction here.
|
||||
for(eastl_size_t i = 0; i < v.size(); ++i)
|
||||
v[i] = value_type((value_type)i); // Note that value_type may be a struct and not an integer. Thus the casting and construction here.
|
||||
break;
|
||||
}
|
||||
|
||||
case kMostlyOrdered:
|
||||
{
|
||||
for (eastl_size_t i = 0; i < v.size(); ++i)
|
||||
v[i] = value_type((value_type)i); // Note that value_type may be a struct and not an integer. Thus
|
||||
// the casting and construction here.
|
||||
for(eastl_size_t i = 0; i < v.size(); ++i)
|
||||
v[i] = value_type((value_type)i); // Note that value_type may be a struct and not an integer. Thus the casting and construction here.
|
||||
|
||||
// We order random segments.
|
||||
// The algorithm below in practice will make slightly more than kPercentOrdered be ordered.
|
||||
const eastl_size_t kPercentOrdered =
|
||||
80; // In actuality, due to statistics, the actual ordered percent will be about 82-85%.
|
||||
const eastl_size_t kPercentOrdered = 80; // In actuality, due to statistics, the actual ordered percent will be about 82-85%.
|
||||
|
||||
for (eastl_size_t n = 0, s = v.size(),
|
||||
nEnd = ((s < (100 - kPercentOrdered)) ? 1 : (s / (100 - kPercentOrdered)));
|
||||
n < nEnd; n++)
|
||||
for(eastl_size_t n = 0, s = v.size(), nEnd = ((s < (100 - kPercentOrdered)) ? 1 : (s / (100 - kPercentOrdered))); n < nEnd; n++)
|
||||
{
|
||||
eastl_size_t i = rng.mRand.RandLimit((uint32_t)s);
|
||||
eastl_size_t j = rng.mRand.RandLimit((uint32_t)s);
|
||||
@@ -333,43 +324,26 @@ namespace
|
||||
static int nAssignCount;
|
||||
|
||||
SlowAssign()
|
||||
{
|
||||
x = 0;
|
||||
memcpy(gSlowAssignBuffer1, gSlowAssignBuffer2, sizeof(gSlowAssignBuffer1));
|
||||
}
|
||||
{ x = 0; memcpy(gSlowAssignBuffer1, gSlowAssignBuffer2, sizeof(gSlowAssignBuffer1)); }
|
||||
|
||||
SlowAssign(const SlowAssign& sa)
|
||||
{
|
||||
++nAssignCount;
|
||||
x = sa.x;
|
||||
memcpy(gSlowAssignBuffer1, gSlowAssignBuffer2, sizeof(gSlowAssignBuffer1));
|
||||
}
|
||||
{ ++nAssignCount; x = sa.x; memcpy(gSlowAssignBuffer1, gSlowAssignBuffer2, sizeof(gSlowAssignBuffer1)); }
|
||||
|
||||
SlowAssign& operator=(const SlowAssign& sa)
|
||||
{
|
||||
++nAssignCount;
|
||||
x = sa.x;
|
||||
memcpy(gSlowAssignBuffer1, gSlowAssignBuffer2, sizeof(gSlowAssignBuffer1));
|
||||
return *this;
|
||||
}
|
||||
{ ++nAssignCount; x = sa.x; memcpy(gSlowAssignBuffer1, gSlowAssignBuffer2, sizeof(gSlowAssignBuffer1)); return *this; }
|
||||
|
||||
SlowAssign& operator=(int a)
|
||||
{
|
||||
x = (T)a;
|
||||
return *this;
|
||||
}
|
||||
{ x = (T)a; return *this; }
|
||||
|
||||
static void Reset() { nAssignCount = 0; }
|
||||
static void Reset()
|
||||
{ nAssignCount = 0; }
|
||||
};
|
||||
|
||||
template <>
|
||||
int SlowAssign<uint32_t>::nAssignCount = 0;
|
||||
template<> int SlowAssign<uint32_t>::nAssignCount = 0;
|
||||
|
||||
template <typename T>
|
||||
bool operator<(const SlowAssign<T>& a, const SlowAssign<T>& b)
|
||||
{
|
||||
return a.x < b.x;
|
||||
}
|
||||
bool operator <(const SlowAssign<T>& a, const SlowAssign<T>& b)
|
||||
{ return a.x < b.x; }
|
||||
|
||||
|
||||
// SlowCompare
|
||||
@@ -425,8 +399,9 @@ namespace
|
||||
++SlowCompare<int32_t>::nCompareCount;
|
||||
|
||||
// This code is similar in performance to the C++ SlowCompare template functor above.
|
||||
if ((gSlowAssignBuffer1[0] == 0) && (gSlowAssignBuffer1[1] == 0) && (gSlowAssignBuffer1[1] == 0) &&
|
||||
(gSlowAssignBuffer1[2] == 0) && (gSlowAssignBuffer1[4] == 0) && (gSlowAssignBuffer1[5] == 0))
|
||||
if((gSlowAssignBuffer1[0] == 0) && (gSlowAssignBuffer1[1] == 0) &&
|
||||
(gSlowAssignBuffer1[1] == 0) && (gSlowAssignBuffer1[2] == 0) &&
|
||||
(gSlowAssignBuffer1[4] == 0) && (gSlowAssignBuffer1[5] == 0))
|
||||
{
|
||||
if (*(const int32_t*)a < *(const int32_t*)b)
|
||||
return -1;
|
||||
@@ -485,14 +460,14 @@ int CompareSortPerformance()
|
||||
EA::UnitTest::ReportVerbosity(2, "Random seed = %u\n", (unsigned)EA::UnitTest::GetRandSeed());
|
||||
|
||||
EA::UnitTest::RandGenT<int32_t> rng(EA::UnitTest::GetRandSeed());
|
||||
EA::StdC::Stopwatch stopwatch(EA::StdC::Stopwatch::kUnitsCPUCycles);
|
||||
EA::StdC::Stopwatch stopwatchGlobal(EA::StdC::Stopwatch::kUnitsSeconds);
|
||||
EA::StdC::Stopwatch stopwatch(EA::StdC::Stopwatch::kUnitsCPUCycles);
|
||||
EA::StdC::Stopwatch stopwatchGlobal(EA::StdC::Stopwatch::kUnitsSeconds);
|
||||
const eastl_size_t kArraySizeMax = *eastl::max_element(eastl::begin(kSizes), eastl::end(kSizes));
|
||||
const int kRunCount = 4;
|
||||
const int kRunCount = 4;
|
||||
|
||||
#if !defined(EA_DEBUG)
|
||||
EA::UnitTest::SetHighThreadPriority();
|
||||
#endif
|
||||
#if !defined(EA_DEBUG)
|
||||
EA::UnitTest::SetHighThreadPriority();
|
||||
#endif
|
||||
|
||||
eastl::vector<SortFunctionType> allSortFunctions;
|
||||
for (int i = 0; i < sf_count; i++)
|
||||
@@ -508,8 +483,8 @@ int CompareSortPerformance()
|
||||
// This is probably the most common type of comparison.
|
||||
EA::UnitTest::ReportVerbosity(2, "Sort comparison: Regular speed test\n");
|
||||
|
||||
typedef uint32_t ElementType;
|
||||
typedef eastl::less<ElementType> CompareFunction;
|
||||
typedef uint32_t ElementType;
|
||||
typedef eastl::less<ElementType> CompareFunction;
|
||||
|
||||
eastl::string sOutput;
|
||||
sOutput.set_capacity(100000);
|
||||
@@ -568,8 +543,7 @@ int CompareSortPerformance()
|
||||
|
||||
case sf_merge_sort:
|
||||
stopwatch.Restart();
|
||||
eastl::merge_sort(v.begin(), v.end(), *get_default_allocator((EASTLAllocatorType*)NULL),
|
||||
CompareFunction());
|
||||
eastl::merge_sort(v.begin(), v.end(), *get_default_allocator((EASTLAllocatorType*)NULL), CompareFunction());
|
||||
stopwatch.Stop();
|
||||
break;
|
||||
|
||||
@@ -605,9 +579,7 @@ int CompareSortPerformance()
|
||||
|
||||
case sf_radix_sort:
|
||||
stopwatch.Restart();
|
||||
eastl::radix_sort<ElementType*,
|
||||
identity_extract_radix_key<ElementType> >(
|
||||
v.begin(), v.end(), pBuffer);
|
||||
eastl::radix_sort<ElementType*, identity_extract_radix_key<ElementType>>(v.begin(), v.end(), pBuffer);
|
||||
stopwatch.Stop();
|
||||
break;
|
||||
|
||||
@@ -623,12 +595,6 @@ int CompareSortPerformance()
|
||||
stopwatch.Stop();
|
||||
break;
|
||||
|
||||
case sf_std_stable_sort:
|
||||
stopwatch.Restart();
|
||||
std::stable_sort(v.data(), v.data() + v.size(), std::less<ElementType>());
|
||||
stopwatch.Stop();
|
||||
break;
|
||||
|
||||
case sf_count:
|
||||
default:
|
||||
// unsupported
|
||||
@@ -749,8 +715,7 @@ int CompareSortPerformance()
|
||||
|
||||
case sf_merge_sort:
|
||||
stopwatch.Restart();
|
||||
eastl::merge_sort(v.begin(), v.end(), *get_default_allocator((EASTLAllocatorType*)NULL),
|
||||
CompareFunction());
|
||||
eastl::merge_sort(v.begin(), v.end(), *get_default_allocator((EASTLAllocatorType*)NULL), CompareFunction());
|
||||
stopwatch.Stop();
|
||||
break;
|
||||
|
||||
@@ -796,12 +761,6 @@ int CompareSortPerformance()
|
||||
stopwatch.Stop();
|
||||
break;
|
||||
|
||||
case sf_std_stable_sort:
|
||||
stopwatch.Restart();
|
||||
std::stable_sort(v.begin(), v.end(), CompareFunction());
|
||||
stopwatch.Stop();
|
||||
break;
|
||||
|
||||
case sf_radix_sort:
|
||||
case sf_count:
|
||||
default:
|
||||
@@ -926,8 +885,7 @@ int CompareSortPerformance()
|
||||
|
||||
case sf_merge_sort:
|
||||
stopwatch.Restart();
|
||||
eastl::merge_sort(v.begin(), v.end(), *get_default_allocator((EASTLAllocatorType*)NULL),
|
||||
CompareFunction());
|
||||
eastl::merge_sort(v.begin(), v.end(), *get_default_allocator((EASTLAllocatorType*)NULL), CompareFunction());
|
||||
stopwatch.Stop();
|
||||
break;
|
||||
|
||||
@@ -963,9 +921,7 @@ int CompareSortPerformance()
|
||||
|
||||
case sf_radix_sort:
|
||||
stopwatch.Restart();
|
||||
eastl::radix_sort<ElementType*,
|
||||
slow_assign_extract_radix_key<ElementType> >(
|
||||
v.begin(), v.end(), pBuffer);
|
||||
eastl::radix_sort<ElementType*, slow_assign_extract_radix_key<ElementType>>(v.begin(), v.end(), pBuffer);
|
||||
stopwatch.Stop();
|
||||
break;
|
||||
|
||||
@@ -975,12 +931,6 @@ int CompareSortPerformance()
|
||||
stopwatch.Stop();
|
||||
break;
|
||||
|
||||
case sf_std_stable_sort:
|
||||
stopwatch.Restart();
|
||||
std::stable_sort(v.begin(), v.end(), std::less<ElementType>());
|
||||
stopwatch.Stop();
|
||||
break;
|
||||
|
||||
case sf_qsort:
|
||||
case sf_count:
|
||||
default:
|
||||
@@ -1031,9 +981,9 @@ int CompareSortPerformance()
|
||||
EA::UnitTest::ReportVerbosity(2, "%s\n", sOutput.c_str());
|
||||
}
|
||||
|
||||
#if !defined(EA_DEBUG)
|
||||
EA::UnitTest::SetNormalThreadPriority();
|
||||
#endif
|
||||
#if !defined(EA_DEBUG)
|
||||
EA::UnitTest::SetNormalThreadPriority();
|
||||
#endif
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
@@ -1043,10 +993,9 @@ void BenchmarkSort()
|
||||
{
|
||||
EASTLTest_Printf("Sort\n");
|
||||
|
||||
EA::UnitTest::RandGenT<uint32_t> rng(12345678); // For debugging sort code we should use 12345678, for normal
|
||||
// testing use EA::UnitTest::GetRandSeed().
|
||||
EA::StdC::Stopwatch stopwatch1(EA::StdC::Stopwatch::kUnitsCPUCycles);
|
||||
EA::StdC::Stopwatch stopwatch2(EA::StdC::Stopwatch::kUnitsCPUCycles);
|
||||
EA::UnitTest::RandGenT<uint32_t> rng(12345678); // For debugging sort code we should use 12345678, for normal testing use EA::UnitTest::GetRandSeed().
|
||||
EA::StdC::Stopwatch stopwatch1(EA::StdC::Stopwatch::kUnitsCPUCycles);
|
||||
EA::StdC::Stopwatch stopwatch2(EA::StdC::Stopwatch::kUnitsCPUCycles);
|
||||
|
||||
if (EA::UnitTest::GetVerbosity() >= 3)
|
||||
CompareSortPerformance();
|
||||
@@ -1082,19 +1031,18 @@ void BenchmarkSort()
|
||||
}
|
||||
|
||||
TestQuickSortStdVP(stopwatch1, stdVectorVP);
|
||||
TestQuickSortEaVP(stopwatch2, eaVectorVP);
|
||||
TestQuickSortEaVP (stopwatch2, eaVectorVP);
|
||||
|
||||
if (i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/vector<ValuePair>", stopwatch1.GetUnits(),
|
||||
stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
if(i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/vector<ValuePair>", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
|
||||
// Benchmark the sorting of something that is already sorted.
|
||||
TestQuickSortStdVP(stopwatch1, stdVectorVP);
|
||||
TestQuickSortEaVP(stopwatch2, eaVectorVP);
|
||||
TestQuickSortEaVP (stopwatch2, eaVectorVP);
|
||||
|
||||
if(i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/vector<ValuePair>/sorted", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
|
||||
if (i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/vector<ValuePair>/sorted", stopwatch1.GetUnits(),
|
||||
stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
|
||||
|
||||
///////////////////////////////
|
||||
@@ -1102,28 +1050,27 @@ void BenchmarkSort()
|
||||
///////////////////////////////
|
||||
|
||||
StdVectorInt stdVectorInt(intVector.size());
|
||||
EaVectorInt eaVectorInt(intVector.size());
|
||||
EaVectorInt eaVectorInt (intVector.size());
|
||||
|
||||
for (eastl_size_t j = 0, jEnd = intVector.size(); j < jEnd; j++)
|
||||
for(eastl_size_t j = 0, jEnd = intVector.size(); j < jEnd; j++)
|
||||
{
|
||||
stdVectorInt[j] = intVector[j];
|
||||
eaVectorInt[j] = intVector[j];
|
||||
eaVectorInt[j] = intVector[j];
|
||||
}
|
||||
|
||||
TestQuickSortStdInt(stopwatch1, stdVectorInt);
|
||||
TestQuickSortEaInt(stopwatch2, eaVectorInt);
|
||||
TestQuickSortEaInt (stopwatch2, eaVectorInt);
|
||||
|
||||
if (i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/vector<uint32>", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(),
|
||||
stopwatch2.GetElapsedTime());
|
||||
if(i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/vector<uint32>", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
|
||||
// Benchmark the sorting of something that is already sorted.
|
||||
TestQuickSortStdInt(stopwatch1, stdVectorInt);
|
||||
TestQuickSortEaInt(stopwatch2, eaVectorInt);
|
||||
TestQuickSortEaInt (stopwatch2, eaVectorInt);
|
||||
|
||||
if(i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/vector<uint32>/sorted", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
|
||||
if (i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/vector<uint32>/sorted", stopwatch1.GetUnits(),
|
||||
stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
|
||||
|
||||
///////////////////////////////
|
||||
@@ -1143,16 +1090,15 @@ void BenchmarkSort()
|
||||
TestQuickSortEaTO(stopwatch2, eaVectorTO);
|
||||
|
||||
if (i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/vector<TestObject>", stopwatch1.GetUnits(),
|
||||
stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
Benchmark::AddResult("sort/q_sort/vector<TestObject>", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
|
||||
// Benchmark the sorting of something that is already sorted.
|
||||
TestQuickSortStdTO(stopwatch1, stdVectorTO);
|
||||
TestQuickSortEaTO(stopwatch2, eaVectorTO);
|
||||
|
||||
if (i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/vector<TestObject>/sorted", stopwatch1.GetUnits(),
|
||||
stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
Benchmark::AddResult("sort/q_sort/vector<TestObject>/sorted", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
|
||||
|
||||
|
||||
///////////////////////////////
|
||||
@@ -1160,26 +1106,29 @@ void BenchmarkSort()
|
||||
///////////////////////////////
|
||||
|
||||
// Reset the values back to the unsorted state.
|
||||
for (eastl_size_t j = 0, jEnd = intVector.size(); j < jEnd; j++)
|
||||
for(eastl_size_t j = 0, jEnd = intVector.size(); j < jEnd; j++)
|
||||
{
|
||||
stdVectorTO[j] = TestObject(intVector[j]);
|
||||
eaVectorTO[j] = TestObject(intVector[j]);
|
||||
eaVectorTO[j] = TestObject(intVector[j]);
|
||||
}
|
||||
|
||||
TestQuickSortStdTO(stopwatch1, stdVectorTO);
|
||||
TestQuickSortEaTO(stopwatch2, eaVectorTO);
|
||||
TestQuickSortEaTO (stopwatch2, eaVectorTO);
|
||||
|
||||
if (i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/TestObject[]", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(),
|
||||
stopwatch2.GetElapsedTime());
|
||||
if(i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/TestObject[]", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
|
||||
// Benchmark the sorting of something that is already sorted.
|
||||
TestQuickSortStdTO(stopwatch1, stdVectorTO);
|
||||
TestQuickSortEaTO(stopwatch2, eaVectorTO);
|
||||
TestQuickSortEaTO (stopwatch2, eaVectorTO);
|
||||
|
||||
if (i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/TestObject[]/sorted", stopwatch1.GetUnits(),
|
||||
stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
if(i == 1)
|
||||
Benchmark::AddResult("sort/q_sort/TestObject[]/sorted", stopwatch1.GetUnits(), stopwatch1.GetElapsedTime(), stopwatch2.GetElapsedTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -10,14 +10,30 @@
|
||||
|
||||
You don't need to restart Visual Studio to use it, you just need to restart the debug
|
||||
session. You can have multiple .natvis files and they will all be used.
|
||||
|
||||
VS2017 natvis documentation:
|
||||
https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects
|
||||
-->
|
||||
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
|
||||
<Type Name="eastl::shared_ptr<*>">
|
||||
<DisplayString>{mpValue}</DisplayString>
|
||||
<Type Name="eastl::unique_ptr<*>">
|
||||
<DisplayString Condition="mPair.mFirst != nullptr">({(void*)mPair.mFirst} = {*mPair.mFirst})</DisplayString>
|
||||
<DisplayString Condition="mPair.mFirst == nullptr">({nullptr})</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem>mpValue</ExpandedItem>
|
||||
<Item Name="[pointer]">(void*)mPair.mFirst</Item>
|
||||
<Item Name="[value]">*mPair.mFirst</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="eastl::shared_ptr<*>">
|
||||
<DisplayString Condition="mpValue != nullptr">({(void*)mpValue} = {*mpValue})</DisplayString>
|
||||
<DisplayString Condition="mpValue == nullptr">({nullptr})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[pointer]">(void*)mpValue</Item>
|
||||
<Item Name="[value]">*mpValue</Item>
|
||||
<Item Name="[reference count]">mpRefCount->mRefCount</Item>
|
||||
<Item Name="[weak reference count]">mpRefCount->mWeakRefCount</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
@@ -46,35 +62,19 @@
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="eastl::basic_string<char,*>">
|
||||
<DisplayString>{mPair.mFirst.heap.mpBegin,s}</DisplayString>
|
||||
<Type Name="eastl::basic_string<*>">
|
||||
<DisplayString Condition="!!(mPair.mFirst.sso.mSizeField.mnSize & kSSOMask)">"{mPair.mFirst.heap.mpBegin,sb}"</DisplayString>
|
||||
<DisplayString Condition="!(mPair.mFirst.sso.mSizeField.mnSize & kSSOMask)">"{mPair.mFirst.sso.mData,sb}"</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="length" Condition="!!(mPair.mFirst.sso.mnSize & kSSOMask)">mPair.mFirst.heap.mnSize</Item>
|
||||
<Item Name="capacity" Condition="!!(mPair.mFirst.sso.mnSize & kSSOMask)">(mPair.mFirst.heap.mnCapacity
|
||||
& ~kHeapMask)</Item>
|
||||
<Item Name="value" Condition="!!(mPair.mFirst.sso.mnSize & kSSOMask)">mPair.mFirst.heap.mpBegin,sb</Item>
|
||||
<Item Name="[length]" Condition="!!(mPair.mFirst.sso.mSizeField.mnSize & kSSOMask)">mPair.mFirst.heap.mnSize</Item>
|
||||
<Item Name="[capacity]" Condition="!!(mPair.mFirst.sso.mSizeField.mnSize & kSSOMask)">(mPair.mFirst.heap.mnCapacity & ~kHeapMask)</Item>
|
||||
<Item Name="[value]" Condition="!!(mPair.mFirst.sso.mSizeField.mnSize & kSSOMask)">mPair.mFirst.heap.mpBegin,sb</Item>
|
||||
|
||||
<Item Name="length" Condition="!(mPair.mFirst.sso.mnSize & kSSOMask)">mPair.mFirst.sso.mnSize</Item>
|
||||
<Item Name="capacity" Condition="!(mPair.mFirst.sso.mnSize & kSSOMask)">SSOLayout::SSO_CAPACITY</Item>
|
||||
<Item Name="value" Condition="!(mPair.mFirst.sso.mnSize & kSSOMask)">mPair.mFirst.sso.mData,sb</Item>
|
||||
<Item Name="[length]" Condition="!(mPair.mFirst.sso.mSizeField.mnSize & kSSOMask)">mPair.mFirst.sso.mSizeField.mnSize</Item>
|
||||
<Item Name="[capacity]" Condition="!(mPair.mFirst.sso.mSizeField.mnSize & kSSOMask)">SSOLayout::SSO_CAPACITY</Item>
|
||||
<Item Name="[value]" Condition="!(mPair.mFirst.sso.mSizeField.mnSize & kSSOMask)">mPair.mFirst.sso.mData,sb</Item>
|
||||
|
||||
<Item Name="uses heap">!!(mPair.mFirst.sso.mnSize & kSSOMask)</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="eastl::basic_string<wchar_t,*>">
|
||||
<DisplayString>{mPair.mFirst.heap.mpBegin,su}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="length" Condition="!!(mPair.mFirst.sso.mnSize & kSSOMask)">mPair.mFirst.heap.mnSize</Item>
|
||||
<Item Name="capacity" Condition="!!(mPair.mFirst.sso.mnSize & kSSOMask)">(mPair.mFirst.heap.mnCapacity
|
||||
& ~kHeapMask)</Item>
|
||||
<Item Name="value" Condition="!!(mPair.mFirst.sso.mnSize & kSSOMask)">mPair.mFirst.heap.mpBegin,sb</Item>
|
||||
|
||||
<Item Name="length" Condition="!(mPair.mFirst.sso.mnSize & kSSOMask)">mPair.mFirst.sso.mnSize</Item>
|
||||
<Item Name="capacity" Condition="!(mPair.mFirst.sso.mnSize & kSSOMask)">SSOLayout::SSO_CAPACITY</Item>
|
||||
<Item Name="value" Condition="!(mPair.mFirst.sso.mnSize & kSSOMask)">mPair.mFirst.sso.mData,sb</Item>
|
||||
|
||||
<Item Name="uses heap">!!(mPair.mFirst.sso.mnSize & kSSOMask)</Item>
|
||||
<Item Name="[uses heap]">!!(mPair.mFirst.sso.mSizeField.mnSize & kSSOMask)</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
@@ -445,4 +445,14 @@
|
||||
<StringView>mpBegin,[mnCount]</StringView>
|
||||
</Type>
|
||||
|
||||
<Type Name="eastl::compressed_pair_imp<*>">
|
||||
<DisplayString Condition="($T3) == 0" Optional="true">({mFirst}, {mSecond})</DisplayString>
|
||||
<DisplayString Condition="($T3) == 1" Optional="true">({mSecond})</DisplayString>
|
||||
<DisplayString Condition="($T3) == 2" Optional="true">({mFirst})</DisplayString>
|
||||
<DisplayString Condition="($T3) == 3" Optional="true">(empty)</DisplayString>
|
||||
<DisplayString Condition="($T3) == 4" Optional="true">(empty)</DisplayString>
|
||||
<DisplayString Condition="($T3) == 5" Optional="true">({mFirst}, {mSecond})</DisplayString>
|
||||
</Type>
|
||||
|
||||
|
||||
</AutoVisualizer>
|
||||
|
||||
@@ -1871,6 +1871,31 @@ namespace eastl
|
||||
return function;
|
||||
}
|
||||
|
||||
/// for_each_n
|
||||
///
|
||||
/// Calls the Function function for each value in the range [first, first + n).
|
||||
/// Function takes a single parameter: the current value.
|
||||
///
|
||||
/// Effects: Applies function to the result of dereferencing every iterator in
|
||||
/// the range [first, first + n), starting from first and proceeding to last 1.
|
||||
///
|
||||
/// Returns: first + n.
|
||||
///
|
||||
/// Complexity: Applies function exactly 'first + n' times.
|
||||
///
|
||||
/// Note:
|
||||
//// * If function returns a result, the result is ignored.
|
||||
//// * If n < 0, behaviour is undefined.
|
||||
///
|
||||
template <typename InputIterator, typename Size, typename Function>
|
||||
EA_CPP14_CONSTEXPR inline InputIterator
|
||||
for_each_n(InputIterator first, Size n, Function function)
|
||||
{
|
||||
for (Size i = 0; i < n; ++first, i++)
|
||||
function(*first);
|
||||
return first;
|
||||
}
|
||||
|
||||
|
||||
/// generate
|
||||
///
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
#ifndef EASTL_ANY_H
|
||||
#define EASTL_ANY_H
|
||||
|
||||
EA_ONCE()
|
||||
#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
|
||||
|
||||
#include <EASTL/internal/config.h>
|
||||
#include <EASTL/internal/in_place_t.h>
|
||||
|
||||
@@ -70,9 +70,9 @@ namespace eastl
|
||||
/// 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))
|
||||
#define BITSET_WORD_COUNT(nBitCount, WordType) (nBitCount == 0 ? 1 : ((nBitCount - 1) / (8 * sizeof(WordType)) + 1))
|
||||
#else
|
||||
#define BITSET_WORD_COUNT(nBitCount, WordType) ((N - 1) / (8 * sizeof(WordType)) + 1)
|
||||
#define BITSET_WORD_COUNT(nBitCount, WordType) ((nBitCount - 1) / (8 * sizeof(WordType)) + 1)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
#include <EASTL/fixed_vector.h>
|
||||
#include <EASTL/bonus/ring_buffer.h>
|
||||
|
||||
EA_ONCE()
|
||||
#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
|
||||
{
|
||||
|
||||
@@ -239,8 +239,8 @@ namespace ff_detail
|
||||
template <typename T, typename TotalStorageType>
|
||||
static void templated_call_move_and_destroy(void* in_lhs, void* in_rhs)
|
||||
{
|
||||
TotalStorageType& lhs = (TotalStorageType&)(*(TotalStorageType*)in_lhs);
|
||||
TotalStorageType&& rhs = (TotalStorageType&&)(*(TotalStorageType*)in_rhs);
|
||||
TotalStorageType& lhs = *(TotalStorageType*)in_lhs;
|
||||
TotalStorageType& rhs = *(TotalStorageType*)in_rhs;
|
||||
|
||||
typedef function_table_inplace_specialization<TotalStorageType::SIZE_IN_BYTES, T> specialization;
|
||||
specialization::move_functor(lhs, EASTL_MOVE(rhs));
|
||||
@@ -251,8 +251,8 @@ namespace ff_detail
|
||||
template <typename T, typename TotalStorageType>
|
||||
static void templated_call_copy(void* in_lhs, const void* in_rhs)
|
||||
{
|
||||
TotalStorageType& lhs = (TotalStorageType&)*(TotalStorageType*)in_lhs;
|
||||
const TotalStorageType& rhs = (const TotalStorageType&)*(const TotalStorageType*)in_rhs;
|
||||
TotalStorageType& lhs = *(TotalStorageType*)in_lhs;
|
||||
const TotalStorageType& rhs = *(const TotalStorageType*)in_rhs;
|
||||
|
||||
typedef function_table_inplace_specialization<TotalStorageType::SIZE_IN_BYTES, T> specialization;
|
||||
init_function_table<T>(lhs);
|
||||
@@ -262,7 +262,7 @@ namespace ff_detail
|
||||
template <typename T, typename TotalStorageType>
|
||||
static void templated_call_destroy(void* in_self)
|
||||
{
|
||||
TotalStorageType& self = (TotalStorageType&)in_self;
|
||||
TotalStorageType& self = *(TotalStorageType*)in_self;
|
||||
|
||||
typedef function_table_inplace_specialization<TotalStorageType::SIZE_IN_BYTES, T> specialization;
|
||||
specialization::destroy_functor(self);
|
||||
@@ -271,8 +271,8 @@ namespace ff_detail
|
||||
template <typename T, typename TotalStorageType>
|
||||
static void templated_call_copy_functor_only(void* in_lhs, void* in_rhs)
|
||||
{
|
||||
TotalStorageType& lhs = (TotalStorageType&)in_lhs;
|
||||
const TotalStorageType& rhs = (const TotalStorageType&)in_rhs;
|
||||
TotalStorageType& lhs = *(TotalStorageType*)in_lhs;
|
||||
const TotalStorageType& rhs = *(const TotalStorageType*)in_rhs;
|
||||
|
||||
typedef function_table_inplace_specialization<TotalStorageType::SIZE_IN_BYTES, T> specialization;
|
||||
specialization::store_functor(lhs, specialization::get_functor_ref(rhs));
|
||||
@@ -288,7 +288,7 @@ namespace ff_detail
|
||||
template <typename T, typename TotalStorageType>
|
||||
static void* templated_call_target(void* in_self, const std::type_info& type)
|
||||
{
|
||||
TotalStorageType& self = (TotalStorageType&)in_self;
|
||||
TotalStorageType& self = *(TotalStorageType*)in_self;
|
||||
|
||||
typedef function_table_inplace_specialization<T> specialization;
|
||||
if (type == typeid(T))
|
||||
@@ -359,6 +359,8 @@ public:
|
||||
|
||||
fixed_function& operator=(const fixed_function& other) EA_NOEXCEPT
|
||||
{
|
||||
storage.function_table_ptr->call_destroy(eastl::addressof(storage));
|
||||
|
||||
call = other.call;
|
||||
other.storage.function_table_ptr->call_copy(eastl::addressof(storage), eastl::addressof(other.storage));
|
||||
return *this;
|
||||
@@ -373,6 +375,9 @@ public:
|
||||
|
||||
fixed_function& operator=(std::nullptr_t)
|
||||
{
|
||||
if(call != nullptr)
|
||||
storage.function_table_ptr->call_destroy(eastl::addressof(storage));
|
||||
|
||||
initialize_empty();
|
||||
return *this;
|
||||
}
|
||||
@@ -433,7 +438,7 @@ private:
|
||||
Result (*call)(const ff_detail::functor_storage_type<SIZE_IN_BYTES>&, Arguments...);
|
||||
|
||||
template<typename T>
|
||||
void initialize(T functor)
|
||||
void initialize(T&& functor)
|
||||
{
|
||||
static_assert(sizeof(T) <= sizeof(typename total_storage_type_with_size::functor_storage_type_with_size), "fixed_function local buffer is not large enough to hold the callable.");
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ EA_ONCE()
|
||||
|
||||
#include <EASTL/internal/config.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#include <ctype.h> // toupper, etc.
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
namespace eastl
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -89,8 +89,8 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EASTL_VERSION
|
||||
#define EASTL_VERSION "3.09.00"
|
||||
#define EASTL_VERSION_N 30900
|
||||
#define EASTL_VERSION "3.10.00"
|
||||
#define EASTL_VERSION_N 31000
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1536,7 +1536,7 @@ namespace eastl
|
||||
//
|
||||
// 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
|
||||
// uint32_t explicitly via the EASTL_SIZE_T_32BIT define
|
||||
//
|
||||
// Example usage:
|
||||
// eastl_size_t n = intVector.size();
|
||||
@@ -1829,6 +1829,20 @@ typedef EASTL_SSIZE_T eastl_ssize_t; // Signed version of eastl_size_t. Concept
|
||||
#define EASTL_OPTIONAL_ENABLED 0
|
||||
#endif
|
||||
|
||||
|
||||
/// EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1913) // VS2017+
|
||||
#define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1
|
||||
#elif defined(EA_COMPILER_CLANG)
|
||||
#if !__is_identifier(__has_unique_object_representations)
|
||||
#define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1
|
||||
#else
|
||||
#define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 0
|
||||
#endif
|
||||
#else
|
||||
#define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 0
|
||||
#endif
|
||||
|
||||
#endif // Header include guard
|
||||
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ namespace detail
|
||||
struct function_table_inplace_specialization
|
||||
{
|
||||
template<typename Result, typename... Arguments>
|
||||
EA_FORCE_INLINE static Result call(const functor_storage_type & storage, Arguments... arguments)
|
||||
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<T &>(reinterpret_cast<const T &>(storage))(EASTL_FORWARD(Arguments, arguments)...);
|
||||
@@ -247,7 +247,7 @@ namespace detail
|
||||
|
||||
|
||||
template<typename Result, typename... Arguments>
|
||||
EA_FORCE_INLINE static Result call(const functor_storage_type & storage, Arguments... arguments)
|
||||
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<const FunctorPointer&>(storage))(EASTL_FORWARD(Arguments, arguments)...);
|
||||
|
||||
@@ -89,12 +89,12 @@ namespace eastl
|
||||
struct local_empty_struct {}; // a type that no user function will use as a return type
|
||||
|
||||
template <typename U>
|
||||
static decltype(to_functor(eastl::declval<U>())(eastl::declval<Arguments>()...)) check(U*);
|
||||
static decltype(to_functor(eastl::declval<U>())(eastl::declval<Arguments>()...)) local_check(U*);
|
||||
|
||||
template <typename>
|
||||
static local_empty_struct check(...);
|
||||
static local_empty_struct local_check(...);
|
||||
|
||||
static const bool value = eastl::is_convertible<decltype(check<T>(0)), Result>::value;
|
||||
static const bool value = eastl::is_convertible<decltype(local_check<T>(0)), Result>::value;
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace eastl
|
||||
|
||||
@@ -251,10 +251,8 @@ namespace eastl
|
||||
template <typename T>
|
||||
reference_wrapper<T> ref(T& t) EA_NOEXCEPT;
|
||||
|
||||
#if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS)
|
||||
template <typename T>
|
||||
void ref(const T&&) = delete;
|
||||
#endif
|
||||
template <typename T>
|
||||
void ref(const T&&) = delete;
|
||||
|
||||
template <typename T>
|
||||
reference_wrapper<T> ref(reference_wrapper<T>t) EA_NOEXCEPT;
|
||||
@@ -262,10 +260,8 @@ namespace eastl
|
||||
template <typename T>
|
||||
reference_wrapper<const T> cref(const T& t) EA_NOEXCEPT;
|
||||
|
||||
#if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS)
|
||||
template <typename T>
|
||||
void cref(const T&&) = delete;
|
||||
#endif
|
||||
template <typename T>
|
||||
void cref(const T&&) = delete;
|
||||
|
||||
template <typename T>
|
||||
reference_wrapper<const T> cref(reference_wrapper<T> t) EA_NOEXCEPT;
|
||||
@@ -303,20 +299,16 @@ namespace eastl
|
||||
// definition of invoke, so these specializations need to come after everything else has been defined.
|
||||
template <typename R, typename C, typename T, typename... Args>
|
||||
auto invoke_impl(R (C::*func)(Args...), T&& obj, Args&&... args) ->
|
||||
typename enable_if<
|
||||
is_reference_wrapper<typename remove_reference<T>::type>::value,
|
||||
decltype((obj.get().*func)(forward<Args>(args)...))
|
||||
>::type
|
||||
typename enable_if<is_reference_wrapper<typename remove_reference<T>::type>::value,
|
||||
decltype((obj.get().*func)(forward<Args>(args)...))>::type
|
||||
{
|
||||
return (obj.get().*func)(forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename M, typename C, typename T>
|
||||
auto invoke_impl(M (C::*member), T&& obj) ->
|
||||
typename enable_if<
|
||||
is_reference_wrapper<typename remove_reference<T>::type>::value,
|
||||
decltype(obj.get().*member)
|
||||
>::type
|
||||
auto invoke_impl(M(C::*member), T&& obj) ->
|
||||
typename enable_if<is_reference_wrapper<typename remove_reference<T>::type>::value,
|
||||
decltype(obj.get().*member)>::type
|
||||
{
|
||||
return obj.get().*member;
|
||||
}
|
||||
|
||||
@@ -1192,7 +1192,7 @@ namespace eastl
|
||||
}
|
||||
|
||||
node_type* DoAllocateNodeFromKey(const key_type& key);
|
||||
node_type* DoAllocateNodeFromKey(const key_type&& key);
|
||||
node_type* DoAllocateNodeFromKey(key_type&& key);
|
||||
void DoFreeNode(node_type* pNode);
|
||||
void DoFreeNodes(node_type** pBucketArray, size_type);
|
||||
|
||||
@@ -1262,8 +1262,8 @@ namespace eastl
|
||||
|
||||
eastl::pair<iterator, bool> DoInsertKey(true_type, const key_type& key);
|
||||
iterator DoInsertKey(false_type, const key_type& key);
|
||||
eastl::pair<iterator, bool> DoInsertKey(true_type, const key_type&& key);
|
||||
iterator DoInsertKey(false_type, const key_type&& key);
|
||||
eastl::pair<iterator, bool> DoInsertKey(true_type, key_type&& key);
|
||||
iterator DoInsertKey(false_type, key_type&& key);
|
||||
|
||||
void DoRehash(size_type nBucketCount);
|
||||
node_type* DoFindNode(node_type* pNode, const key_type& k, hash_code_t c) const;
|
||||
@@ -1585,7 +1585,7 @@ namespace eastl
|
||||
template <typename K, typename V, typename A, typename EK, typename Eq,
|
||||
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
|
||||
typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::node_type*
|
||||
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoAllocateNodeFromKey(const key_type&& key)
|
||||
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoAllocateNodeFromKey(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.");
|
||||
@@ -2580,7 +2580,7 @@ namespace eastl
|
||||
template <typename K, typename V, typename A, typename EK, typename Eq,
|
||||
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
|
||||
eastl::pair<typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator, bool>
|
||||
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertKey(true_type, const key_type&& key) // true_type means bUniqueKeys is true.
|
||||
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertKey(true_type, 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);
|
||||
@@ -2628,7 +2628,7 @@ namespace eastl
|
||||
template <typename K, typename V, typename A, typename EK, typename Eq,
|
||||
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
|
||||
typename hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::iterator
|
||||
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertKey(false_type, const key_type&& key) // false_type means bUniqueKeys is false.
|
||||
hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::DoInsertKey(false_type, key_type&& key) // false_type means bUniqueKeys is false.
|
||||
{
|
||||
const eastl::pair<bool, uint32_t> bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1);
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
|
||||
#include <EASTL/internal/config.h>
|
||||
|
||||
EA_ONCE()
|
||||
#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
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -27,29 +27,18 @@ namespace eastl
|
||||
// Example usage:
|
||||
// typedef typename unique_pointer_type<int, SomeDeleter>::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 <typename T, typename Deleter>
|
||||
class unique_pointer_type
|
||||
{
|
||||
public:
|
||||
typedef T* type;
|
||||
};
|
||||
#else
|
||||
template <typename T, typename Deleter>
|
||||
class unique_pointer_type
|
||||
{
|
||||
template <typename U>
|
||||
static typename U::pointer test(typename U::pointer*);
|
||||
template <typename T, typename Deleter>
|
||||
class unique_pointer_type
|
||||
{
|
||||
template <typename U>
|
||||
static typename U::pointer test(typename U::pointer*);
|
||||
|
||||
template <typename U>
|
||||
static T* test(...);
|
||||
template <typename U>
|
||||
static T* test(...);
|
||||
|
||||
public:
|
||||
typedef decltype(test<typename eastl::remove_reference<Deleter>::type>(0)) type;
|
||||
};
|
||||
#endif
|
||||
public:
|
||||
typedef decltype(test<typename eastl::remove_reference<Deleter>::type>(0)) type;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
@@ -163,9 +152,7 @@ namespace eastl
|
||||
template <typename T>
|
||||
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.
|
||||
#if 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;
|
||||
@@ -182,9 +169,7 @@ namespace eastl
|
||||
template <typename T>
|
||||
struct default_delete<T[]> // 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.
|
||||
#if 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;
|
||||
|
||||
@@ -74,6 +74,11 @@ namespace eastl
|
||||
template<typename T, size_t N>
|
||||
struct is_array<T[N]> : public eastl::true_type {};
|
||||
|
||||
#if !defined(EA_COMPILER_NO_TEMPLATE_ALIASES)
|
||||
template<typename T>
|
||||
EA_CONSTEXPR bool is_array_v = is_array<T>::value;
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// is_array_of_known_bounds
|
||||
|
||||
@@ -131,6 +131,12 @@ namespace eastl
|
||||
|
||||
template <> struct is_integral_helper<bool> : public true_type{};
|
||||
template <> struct is_integral_helper<char> : public true_type{};
|
||||
#if defined(EA_CHAR16_NATIVE) && EA_CHAR16_NATIVE
|
||||
template <> struct is_integral_helper<char16_t> : public true_type{};
|
||||
#endif
|
||||
#if defined(EA_CHAR32_NATIVE) && EA_CHAR32_NATIVE
|
||||
template <> struct is_integral_helper<char32_t> : 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 which is already handled above...
|
||||
template <> struct is_integral_helper<wchar_t> : public true_type{};
|
||||
#endif
|
||||
@@ -146,6 +152,10 @@ namespace eastl
|
||||
template <> struct is_integral<const volatile T> : public true_type{}; \
|
||||
}
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template <class T>
|
||||
EA_CONSTEXPR bool is_integral_v = is_integral<T>::value;
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -920,11 +920,9 @@ namespace eastl
|
||||
struct is_trivially_constructible<T, T>
|
||||
: public eastl::integral_constant<bool, eastl::is_constructible<T>::value && eastl::has_trivial_copy<T>::value> {};
|
||||
|
||||
#if !EASTL_NO_RVALUE_REFERENCES
|
||||
template <typename T>
|
||||
struct is_trivially_constructible<T, T&&>
|
||||
: public eastl::integral_constant<bool, eastl::is_constructible<T>::value && eastl::has_trivial_copy<T>::value> {};
|
||||
#endif
|
||||
template <typename T>
|
||||
struct is_trivially_constructible<T, T&&>
|
||||
: public eastl::integral_constant<bool, eastl::is_constructible<T>::value && eastl::has_trivial_copy<T>::value> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_trivially_constructible<T, T&>
|
||||
@@ -1026,117 +1024,84 @@ namespace eastl
|
||||
// be complete types, (possibly cv-qualified) void, or arrays of unknown bound.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(EA_COMPILER_NO_VARIADIC_TEMPLATES)
|
||||
#if defined(EA_COMPILER_NO_NOEXCEPT)
|
||||
|
||||
#define EASTL_TYPE_TRAIT_is_nothrow_constructible_CONFORMANCE 0
|
||||
|
||||
template <typename T, typename Arg0 = eastl::unused, typename Arg1 = eastl::unused>
|
||||
template <typename T, typename... Args>
|
||||
struct is_nothrow_constructible
|
||||
: public eastl::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_nothrow_constructible<T, eastl::unused, eastl::unused>
|
||||
struct is_nothrow_constructible<T>
|
||||
: public eastl::integral_constant<bool, eastl::has_nothrow_constructor<T>::value> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_nothrow_constructible<T, T, eastl::unused>
|
||||
struct is_nothrow_constructible<T, T>
|
||||
: public eastl::integral_constant<bool, eastl::has_nothrow_copy<T>::value> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_nothrow_constructible<T, const T&, eastl::unused>
|
||||
struct is_nothrow_constructible<T, const T&>
|
||||
: public eastl::integral_constant<bool, eastl::has_nothrow_copy<T>::value> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_nothrow_constructible<T, T&, eastl::unused>
|
||||
struct is_nothrow_constructible<T, T&>
|
||||
: public eastl::integral_constant<bool, eastl::has_nothrow_copy<T>::value> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_nothrow_constructible<T, T&&>
|
||||
: public eastl::integral_constant<bool, eastl::has_nothrow_copy<T>::value> {};
|
||||
|
||||
#else
|
||||
|
||||
#if defined(EA_COMPILER_NO_NOEXCEPT)
|
||||
|
||||
#define EASTL_TYPE_TRAIT_is_nothrow_constructible_CONFORMANCE 0
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_nothrow_constructible
|
||||
: public eastl::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_nothrow_constructible<T>
|
||||
: public eastl::integral_constant<bool, eastl::has_nothrow_constructor<T>::value> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_nothrow_constructible<T, T>
|
||||
: public eastl::integral_constant<bool, eastl::has_nothrow_copy<T>::value> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_nothrow_constructible<T, const T&>
|
||||
: public eastl::integral_constant<bool, eastl::has_nothrow_copy<T>::value> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_nothrow_constructible<T, T&>
|
||||
: public eastl::integral_constant<bool, eastl::has_nothrow_copy<T>::value> {};
|
||||
|
||||
#if !EASTL_NO_RVALUE_REFERENCES
|
||||
template <typename T>
|
||||
struct is_nothrow_constructible<T, T&&>
|
||||
: public eastl::integral_constant<bool, eastl::has_nothrow_copy<T>::value> {};
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#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 <class _Tp, class... _Args>
|
||||
// struct __libcpp_is_nothrow_constructible<[>is constructible*/true, /*is reference<]false, _Tp, _Args...>
|
||||
// : public integral_constant<bool, noexcept(_Tp(declval<_Args>()...))> { };
|
||||
//
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_nothrow_constructible_helper_noexcept_wrapper
|
||||
{ static const bool value = noexcept(T(eastl::declval<Args>()...)); };
|
||||
|
||||
template <bool, typename T, typename... Args>
|
||||
struct is_nothrow_constructible_helper;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_nothrow_constructible_helper<true, T, Args...>
|
||||
: public eastl::integral_constant<bool, is_nothrow_constructible_helper_noexcept_wrapper<T, Args...>::value> {};
|
||||
|
||||
template<typename T, typename Arg>
|
||||
struct is_nothrow_constructible_helper<true, T, Arg>
|
||||
: public eastl::integral_constant<bool, noexcept(T(eastl::declval<Arg>()))> {};
|
||||
|
||||
template<typename T>
|
||||
struct is_nothrow_constructible_helper<true, T>
|
||||
: public eastl::integral_constant<bool, noexcept(T())> {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_nothrow_constructible_helper<false, T, Args...>
|
||||
: public eastl::false_type {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_nothrow_constructible
|
||||
: public eastl::is_nothrow_constructible_helper<eastl::is_constructible<T, Args...>::value, T, Args...> {};
|
||||
|
||||
template <typename T, size_t N>
|
||||
struct is_nothrow_constructible<T[N]>
|
||||
: public eastl::is_nothrow_constructible_helper<eastl::is_constructible<T>::value, T> {};
|
||||
|
||||
#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 <class _Tp, class... _Args>
|
||||
// struct __libcpp_is_nothrow_constructible<[>is constructible*/true, /*is reference<]false, _Tp, _Args...>
|
||||
// : public integral_constant<bool, noexcept(_Tp(declval<_Args>()...))> { };
|
||||
//
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_nothrow_constructible_helper_noexcept_wrapper
|
||||
{ static const bool value = noexcept(T(eastl::declval<Args>()...)); };
|
||||
|
||||
template <bool, typename T, typename... Args>
|
||||
struct is_nothrow_constructible_helper;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_nothrow_constructible_helper<true, T, Args...>
|
||||
: public eastl::integral_constant<bool, is_nothrow_constructible_helper_noexcept_wrapper<T, Args...>::value> {};
|
||||
|
||||
template<typename T, typename Arg>
|
||||
struct is_nothrow_constructible_helper<true, T, Arg>
|
||||
: public eastl::integral_constant<bool, noexcept(T(eastl::declval<Arg>()))> {};
|
||||
|
||||
template<typename T>
|
||||
struct is_nothrow_constructible_helper<true, T>
|
||||
: public eastl::integral_constant<bool, noexcept(T())> {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_nothrow_constructible_helper<false, T, Args...>
|
||||
: public eastl::false_type {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_nothrow_constructible
|
||||
: public eastl::is_nothrow_constructible_helper<eastl::is_constructible<T, Args...>::value, T, Args...> {};
|
||||
|
||||
template <typename T, size_t N>
|
||||
struct is_nothrow_constructible<T[N]>
|
||||
: public eastl::is_nothrow_constructible_helper<eastl::is_constructible<T>::value, T> {};
|
||||
#endif
|
||||
|
||||
#define EASTL_DECLARE_IS_NOTHROW_CONSTRUCTIBLE(T, isNothrowConstructible) \
|
||||
@@ -1195,7 +1160,8 @@ namespace eastl
|
||||
|
||||
#define EASTL_TYPE_TRAIT_is_trivially_copy_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_trivially_constructible_CONFORMANCE
|
||||
|
||||
template <typename T> struct is_trivially_copy_constructible
|
||||
template <typename T>
|
||||
struct is_trivially_copy_constructible
|
||||
: public eastl::is_trivially_constructible<T, typename eastl::add_lvalue_reference<typename eastl::add_const<T>::type>::type> {};
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
@@ -1228,19 +1194,11 @@ namespace eastl
|
||||
// is_constructible<T, T&&>::value is true.
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if EASTL_NO_RVALUE_REFERENCES
|
||||
#define EASTL_TYPE_TRAIT_is_move_constructible_CONFORMANCE 0
|
||||
#define EASTL_TYPE_TRAIT_is_move_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_constructible_CONFORMANCE
|
||||
|
||||
template <typename T>
|
||||
struct is_move_constructible
|
||||
: public eastl::is_copy_constructible<T> {};
|
||||
#else
|
||||
#define EASTL_TYPE_TRAIT_is_move_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_constructible_CONFORMANCE
|
||||
|
||||
template <typename T>
|
||||
struct is_move_constructible
|
||||
: public eastl::is_constructible<T, typename eastl::add_rvalue_reference<T>::type> {};
|
||||
#endif
|
||||
template <typename T>
|
||||
struct is_move_constructible
|
||||
: public eastl::is_constructible<T, typename eastl::add_rvalue_reference<T>::type> {};
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template <class T>
|
||||
@@ -1256,19 +1214,11 @@ namespace eastl
|
||||
// array of unknown bound.
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if EASTL_NO_RVALUE_REFERENCES
|
||||
#define EASTL_TYPE_TRAIT_is_trivially_move_constructible_CONFORMANCE 0
|
||||
#define EASTL_TYPE_TRAIT_is_trivially_move_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_trivially_constructible_CONFORMANCE
|
||||
|
||||
template <typename T>
|
||||
struct is_trivially_move_constructible
|
||||
: public eastl::is_trivially_copy_constructible<T> {};
|
||||
#else
|
||||
#define EASTL_TYPE_TRAIT_is_trivially_move_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_trivially_constructible_CONFORMANCE
|
||||
|
||||
template <typename T>
|
||||
struct is_trivially_move_constructible
|
||||
: public eastl::is_trivially_constructible<T, typename eastl::add_rvalue_reference<T>::type> {};
|
||||
#endif
|
||||
template <typename T>
|
||||
struct is_trivially_move_constructible
|
||||
: public eastl::is_trivially_constructible<T, typename eastl::add_rvalue_reference<T>::type> {};
|
||||
|
||||
#define EASTL_DECLARE_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE(T, isTrivallyMoveConstructible) \
|
||||
namespace eastl{ \
|
||||
@@ -1488,11 +1438,9 @@ namespace eastl
|
||||
struct is_trivially_assignable<T&, const T&>
|
||||
: public eastl::integral_constant<bool, eastl::is_scalar<T>::value> {};
|
||||
|
||||
#if !EASTL_NO_RVALUE_REFERENCES
|
||||
template <typename T>
|
||||
struct is_trivially_assignable<T&, T&&>
|
||||
: public eastl::integral_constant<bool, eastl::is_scalar<T>::value> {};
|
||||
#endif
|
||||
template <typename T>
|
||||
struct is_trivially_assignable<T&, T&&>
|
||||
: public eastl::integral_constant<bool, eastl::is_scalar<T>::value> {};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1668,19 +1616,12 @@ namespace eastl
|
||||
// (possibly cv -qualified) void, or an array of unknown bound.
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if EASTL_NO_RVALUE_REFERENCES
|
||||
#define EASTL_TYPE_TRAIT_is_move_assignable_CONFORMANCE 0
|
||||
#define EASTL_TYPE_TRAIT_is_move_assignable_CONFORMANCE EASTL_TYPE_TRAIT_is_assignable_CONFORMANCE
|
||||
|
||||
template <typename T>
|
||||
struct is_move_assignable : public is_copy_assignable<T>{};
|
||||
#else
|
||||
#define EASTL_TYPE_TRAIT_is_move_assignable_CONFORMANCE EASTL_TYPE_TRAIT_is_assignable_CONFORMANCE
|
||||
|
||||
template <typename T>
|
||||
struct is_move_assignable
|
||||
: public eastl::is_assignable<typename eastl::add_lvalue_reference<T>::type,
|
||||
typename eastl::add_rvalue_reference<T>::type> {};
|
||||
#endif
|
||||
template <typename T>
|
||||
struct is_move_assignable
|
||||
: public eastl::is_assignable<typename eastl::add_lvalue_reference<T>::type,
|
||||
typename eastl::add_rvalue_reference<T>::type> {};
|
||||
|
||||
#define EASTL_DECLARE_IS_MOVE_ASSIGNABLE(T, isMoveAssignable) \
|
||||
namespace eastl{ \
|
||||
@@ -1851,6 +1792,11 @@ namespace eastl
|
||||
template <> struct is_trivially_destructible<const volatile T> : public eastl::integral_constant<bool, isTriviallyDestructible>{}; \
|
||||
}
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template <class T>
|
||||
EA_CONSTEXPR bool is_trivially_destructible_v = is_trivially_destructible<T>::value;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1870,7 +1816,7 @@ namespace eastl
|
||||
struct is_nothrow_destructible
|
||||
: integral_constant<bool, __is_nothrow_destructible(T)> {};
|
||||
|
||||
#elif defined(EA_COMPILER_NO_NOEXCEPT) || defined(EA_COMPILER_NO_DECLTYPE)
|
||||
#elif defined(EA_COMPILER_NO_NOEXCEPT)
|
||||
#define EASTL_TYPE_TRAIT_is_nothrow_destructible_CONFORMANCE 0
|
||||
|
||||
template <typename T>
|
||||
@@ -1927,11 +1873,9 @@ namespace eastl
|
||||
struct is_nothrow_destructible<T&> // A reference type cannot throw while being destructed. It's just a reference.
|
||||
: public eastl::true_type {};
|
||||
|
||||
#if !EASTL_NO_RVALUE_REFERENCES
|
||||
template <typename T>
|
||||
struct is_nothrow_destructible<T&&> // An rvalue reference type cannot throw while being destructed.
|
||||
: public eastl::true_type {};
|
||||
#endif
|
||||
template <typename T>
|
||||
struct is_nothrow_destructible<T&&> // An rvalue reference type cannot throw while being destructed.
|
||||
: public eastl::true_type {};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1949,7 +1893,6 @@ namespace eastl
|
||||
// is_nothrow_default_constructible
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define EASTL_TYPE_TRAIT_is_nothrow_default_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_nothrow_constructible_CONFORMANCE
|
||||
|
||||
template <typename T>
|
||||
@@ -1962,22 +1905,13 @@ namespace eastl
|
||||
// is_nothrow_move_constructible
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
#define EASTL_TYPE_TRAIT_is_nothrow_move_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_nothrow_constructible_CONFORMANCE
|
||||
|
||||
#if EASTL_NO_RVALUE_REFERENCES
|
||||
#define EASTL_TYPE_TRAIT_is_nothrow_move_constructible_CONFORMANCE 0
|
||||
template <typename T>
|
||||
struct is_nothrow_move_constructible
|
||||
: public eastl::is_nothrow_constructible<T, typename eastl::add_rvalue_reference<T>::type> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_nothrow_move_constructible
|
||||
: public eastl::is_nothrow_copy_constructible<T> {};
|
||||
#else
|
||||
#define EASTL_TYPE_TRAIT_is_nothrow_move_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_nothrow_constructible_CONFORMANCE
|
||||
|
||||
template <typename T>
|
||||
struct is_nothrow_move_constructible
|
||||
: public eastl::is_nothrow_constructible<T, typename eastl::add_rvalue_reference<T>::type> {};
|
||||
#endif
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template <class T>
|
||||
EA_CONSTEXPR bool is_nothrow_move_constructible_v = is_nothrow_move_constructible<T>::value;
|
||||
#endif
|
||||
|
||||
@@ -41,10 +41,48 @@ namespace eastl
|
||||
struct underlying_type{ typedef int type; }; // This is of course wrong, but we emulate libstdc++ and typedef it as int.
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(EA_COMPILER_NO_TEMPLATE_ALIASES)
|
||||
template <typename T>
|
||||
using underlying_type_t = typename underlying_type<T>::type;
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// has_unique_object_representations
|
||||
//
|
||||
// If T is TriviallyCopyable and if any two objects of type T with the same
|
||||
// value have the same object representation, value is true. For any other
|
||||
// type, value is false.
|
||||
//
|
||||
// http://en.cppreference.com/w/cpp/types/has_unique_object_representations
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
#if EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE
|
||||
#define EASTL_TYPE_TRAIT_has_unique_object_representations_CONFORMANCE 1
|
||||
|
||||
template <typename T>
|
||||
struct has_unique_object_representations
|
||||
: public integral_constant<bool, __has_unique_object_representations(remove_cv_t<remove_all_extents_t<T>>)>
|
||||
{
|
||||
};
|
||||
|
||||
#else
|
||||
#define EASTL_TYPE_TRAIT_has_unique_object_representations_CONFORMANCE 0
|
||||
|
||||
template <typename T>
|
||||
struct has_unique_object_representations
|
||||
: public integral_constant<bool, is_integral_v<remove_cv_t<remove_all_extents_t<T>>>> // only integral types (floating point types excluded).
|
||||
{
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template <class T>
|
||||
EA_CONSTEXPR auto has_unique_object_representations_v = has_unique_object_representations<T>::value;
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// is_signed
|
||||
//
|
||||
// is_signed<T>::value == true if and only if T is one of the following types:
|
||||
@@ -274,30 +312,43 @@ namespace eastl
|
||||
// result_of
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
#define EASTL_TYPE_TRAIT_result_of_CONFORMANCE 1 // result_of is conforming.
|
||||
|
||||
#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
|
||||
template<typename> struct result_of;
|
||||
|
||||
template<typename F, typename... ArgTypes>
|
||||
struct result_of<F(ArgTypes...)>
|
||||
{ typedef decltype(eastl::declval<F>()(eastl::declval<ArgTypes>()...)) type; };
|
||||
|
||||
|
||||
// result_of_t is the C++14 using typedef for typename result_of<T>::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<T>::type
|
||||
#else
|
||||
#define EASTL_TYPE_TRAIT_result_of_CONFORMANCE 1 // result_of is conforming.
|
||||
|
||||
template<typename> struct result_of;
|
||||
|
||||
template<typename F, typename... ArgTypes>
|
||||
struct result_of<F(ArgTypes...)>
|
||||
{ typedef decltype(eastl::declval<F>()(eastl::declval<ArgTypes>()...)) type; };
|
||||
template <typename T>
|
||||
using result_of_t = typename result_of<T>::type;
|
||||
#define EASTL_RESULT_OF_T(T) result_of_t<T>
|
||||
#endif
|
||||
|
||||
|
||||
// result_of_t is the C++14 using typedef for typename result_of<T>::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<T>::type
|
||||
#else
|
||||
template <typename T>
|
||||
using result_of_t = typename result_of<T>::type;
|
||||
#define EASTL_RESULT_OF_T(T) result_of_t<T>
|
||||
#endif
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// has_equality
|
||||
//
|
||||
// Determines if the specified type can be tested for equality.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
template <typename, typename = eastl::void_t<>>
|
||||
struct has_equality : eastl::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_equality<T, eastl::void_t<decltype(eastl::declval<T>() == eastl::declval<T>())>> : eastl::true_type
|
||||
{
|
||||
};
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template <class T>
|
||||
EA_CONSTEXPR auto has_equality_v = has_equality<T>::value;
|
||||
#endif
|
||||
|
||||
} // namespace eastl
|
||||
|
||||
@@ -263,6 +263,10 @@ namespace eastl
|
||||
template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
|
||||
template<typename T> struct remove_pointer<T* const volatile> { typedef T type; };
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template <class T>
|
||||
using remove_pointer_t = typename remove_pointer<T>::type;
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
@@ -302,6 +306,10 @@ namespace eastl
|
||||
template<class T> struct remove_extent<T[]> { typedef T type; };
|
||||
template<class T, size_t N> struct remove_extent<T[N]> { typedef T type; };
|
||||
|
||||
#if !defined(EA_COMPILER_NO_TEMPLATE_ALIASES)
|
||||
template <typename T>
|
||||
using remove_extent_t = typename remove_extent<T>::type;
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
@@ -320,6 +328,11 @@ namespace eastl
|
||||
template<typename T, size_t N> struct remove_all_extents<T[N]> { typedef typename eastl::remove_all_extents<T>::type type; };
|
||||
template<typename T> struct remove_all_extents<T[]> { typedef typename eastl::remove_all_extents<T>::type type; };
|
||||
|
||||
#if !defined(EA_COMPILER_NO_TEMPLATE_ALIASES)
|
||||
template <typename T>
|
||||
using remove_all_extents_t = typename remove_all_extents<T>::type;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1090,153 +1090,77 @@ namespace eastl
|
||||
#endif
|
||||
|
||||
#if EASTL_BEGIN_END_ENABLED
|
||||
#if defined(EA_COMPILER_NO_DECLTYPE) // C++11 decltype
|
||||
template <typename Container>
|
||||
inline auto begin(Container& container) -> decltype(container.begin())
|
||||
{
|
||||
return container.begin();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline typename Container::iterator begin(Container& container)
|
||||
{
|
||||
return container.begin();
|
||||
}
|
||||
template <typename Container>
|
||||
inline auto begin(const Container& container) -> decltype(container.begin())
|
||||
{
|
||||
return container.begin();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline typename Container::const_iterator begin(const Container& container)
|
||||
{
|
||||
return container.begin();
|
||||
}
|
||||
template <typename Container>
|
||||
inline auto cbegin(const Container& container) -> decltype(container.begin())
|
||||
{
|
||||
return container.begin();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline typename Container::const_iterator cbegin(const Container& container)
|
||||
{
|
||||
return container.begin();
|
||||
}
|
||||
template <typename Container>
|
||||
inline auto end(Container& container) -> decltype(container.end())
|
||||
{
|
||||
return container.end();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline typename Container::iterator end(Container& container)
|
||||
{
|
||||
return container.end();
|
||||
}
|
||||
template <typename Container>
|
||||
inline auto end(const Container& container) -> decltype(container.end())
|
||||
{
|
||||
return container.end();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline typename Container::const_iterator end(const Container& container)
|
||||
{
|
||||
return container.end();
|
||||
}
|
||||
template <typename Container>
|
||||
inline auto cend(const Container& container) -> decltype(container.end())
|
||||
{
|
||||
return container.end();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline typename Container::const_iterator cend(const Container& container)
|
||||
{
|
||||
return container.end();
|
||||
}
|
||||
template <typename Container>
|
||||
inline auto rbegin(Container& container) -> decltype(container.rbegin())
|
||||
{
|
||||
return container.rbegin();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline typename Container::reverse_iterator rbegin(Container& container)
|
||||
{
|
||||
return container.rbegin();
|
||||
}
|
||||
template <typename Container>
|
||||
inline auto rbegin(const Container& container) -> decltype(container.rbegin())
|
||||
{
|
||||
return container.rbegin();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline typename Container::reverse_iterator rbegin(const Container& container)
|
||||
{
|
||||
return container.rbegin();
|
||||
}
|
||||
template <typename Container>
|
||||
inline auto rend(Container& container) -> decltype(container.rend())
|
||||
{
|
||||
return container.rend();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline typename Container::reverse_iterator rend(Container& container)
|
||||
{
|
||||
return container.rend();
|
||||
}
|
||||
template <typename Container>
|
||||
inline auto rend(const Container& container) -> decltype(container.rend())
|
||||
{
|
||||
return container.rend();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline typename Container::reverse_iterator rend(const Container& container)
|
||||
{
|
||||
return container.rend();
|
||||
}
|
||||
template <typename Container>
|
||||
inline auto crbegin(const Container& container) -> decltype(eastl::rbegin(container))
|
||||
{
|
||||
return container.rbegin();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline typename Container::const_reverse_iterator crbegin(const Container& container)
|
||||
{
|
||||
return container.rbegin();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline typename Container::const_reverse_iterator crend(const Container& container)
|
||||
{
|
||||
return container.rend();
|
||||
}
|
||||
#else
|
||||
template <typename Container>
|
||||
inline auto begin(Container& container) -> decltype(container.begin())
|
||||
{
|
||||
return container.begin();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline auto begin(const Container& container) -> decltype(container.begin())
|
||||
{
|
||||
return container.begin();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline auto cbegin(const Container& container) -> decltype(container.begin())
|
||||
{
|
||||
return container.begin();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline auto end(Container& container) -> decltype(container.end())
|
||||
{
|
||||
return container.end();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline auto end(const Container& container) -> decltype(container.end())
|
||||
{
|
||||
return container.end();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline auto cend(const Container& container) -> decltype(container.end())
|
||||
{
|
||||
return container.end();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline auto rbegin(Container& container) -> decltype(container.rbegin())
|
||||
{
|
||||
return container.rbegin();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline auto rbegin(const Container& container) -> decltype(container.rbegin())
|
||||
{
|
||||
return container.rbegin();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline auto rend(Container& container) -> decltype(container.rend())
|
||||
{
|
||||
return container.rend();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline auto rend(const Container& container) -> decltype(container.rend())
|
||||
{
|
||||
return container.rend();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline auto crbegin(const Container& container) -> decltype(eastl::rbegin(container))
|
||||
{
|
||||
return container.rbegin();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline auto crend(const Container& container) -> decltype(eastl::rend(container))
|
||||
{
|
||||
return container.rend();
|
||||
}
|
||||
|
||||
#endif
|
||||
template <typename Container>
|
||||
inline auto crend(const Container& container) -> decltype(eastl::rend(container))
|
||||
{
|
||||
return container.rend();
|
||||
}
|
||||
|
||||
template<typename T, size_t arraySize>
|
||||
inline T* begin(T (&arrayObject)[arraySize])
|
||||
|
||||
@@ -532,7 +532,7 @@ namespace eastl
|
||||
{
|
||||
#endif
|
||||
for(; first != last; ++first, ++currentDest)
|
||||
::new((void*)eastl::addressof(*currentDest)) value_type(*first);
|
||||
::new(static_cast<void*>(eastl::addressof(*currentDest))) value_type(*first);
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
}
|
||||
catch(...)
|
||||
@@ -1354,7 +1354,7 @@ namespace eastl
|
||||
/// compiler can already see in our version here that the destructor
|
||||
/// is a no-op.
|
||||
///
|
||||
/// This is the say as eastl::destruct but we included for C++17 compliance.
|
||||
/// This is the same as eastl::destruct but we included for C++17 compliance.
|
||||
///
|
||||
/// http://en.cppreference.com/w/cpp/memory/destroy_at
|
||||
///
|
||||
|
||||
222
include/EASTL/meta.h
Normal file
222
include/EASTL/meta.h
Normal file
@@ -0,0 +1,222 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EASTL_META_H
|
||||
#define EASTL_META_H
|
||||
|
||||
#include <EASTL/internal/config.h>
|
||||
#include <EASTL/type_traits.h>
|
||||
|
||||
#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
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This file contains meta programming utilities that are internal to EASTL. We reserve
|
||||
// the right to change this file at any time as it is only intended to be used internally.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace eastl
|
||||
{
|
||||
namespace meta
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// get_type_index_v
|
||||
//
|
||||
// Linearly searches a typelist using compile-time recursion to inspect each T in
|
||||
// the typelist and returns its index, if the type is found. If the T isn't found
|
||||
// in the typelist -1 is returned.
|
||||
//
|
||||
namespace Internal
|
||||
{
|
||||
template <int I, typename T, typename... Types>
|
||||
struct get_type_index;
|
||||
|
||||
template <int I, typename T, typename Head, typename... Types>
|
||||
struct get_type_index<I, T, Head, Types...>
|
||||
{
|
||||
static const int value = is_same_v<T, Head> ? I : get_type_index<I + 1, T, Types...>::value;
|
||||
};
|
||||
|
||||
template <int I, typename T>
|
||||
struct get_type_index<I, T>
|
||||
{
|
||||
static const int value = -1;
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T, typename... Types>
|
||||
struct get_type_index
|
||||
{
|
||||
static const int value = Internal::get_type_index<0, T, Types...>::value;
|
||||
};
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
constexpr int get_type_index_v = get_type_index<T, Ts...>::value;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// get_type_at
|
||||
//
|
||||
// This traverses the variadic type list and retrieves the type at the user provided index.
|
||||
//
|
||||
template <size_t I, typename... Ts>
|
||||
struct get_type_at_helper;
|
||||
|
||||
template <size_t I, typename Head, typename... Tail>
|
||||
struct get_type_at_helper<I, Head, Tail...>
|
||||
{ typedef typename get_type_at_helper<I - 1, Tail...>::type type; };
|
||||
|
||||
template <typename Head, typename... Tail>
|
||||
struct get_type_at_helper<0, Head, Tail...>
|
||||
{ typedef Head type; };
|
||||
|
||||
template <int I, typename... Ts>
|
||||
using get_type_at_t = typename get_type_at_helper<I, Ts...>::type;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// type_count_v
|
||||
//
|
||||
// Returns the number of occurrences of type T in a typelist.
|
||||
//
|
||||
template <typename T, typename... Types>
|
||||
struct type_count;
|
||||
|
||||
template <typename T, typename H, typename... Types>
|
||||
struct type_count<T, H, Types...>
|
||||
{
|
||||
static const int value = (is_same_v<T, H> ? 1 : 0) + type_count<T, Types...>::value;
|
||||
};
|
||||
|
||||
template <typename T> struct type_count<T> { static const int value = 0; };
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
constexpr int type_count_v = type_count<T, Ts...>::value;
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// duplicate_type_check_v
|
||||
//
|
||||
// Checks if a type T occurs in a typelist more than once.
|
||||
//
|
||||
template <typename T, typename... Types>
|
||||
struct duplicate_type_check
|
||||
{
|
||||
static const bool value = (type_count<T, Types...>::value == 1);
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
constexpr bool duplicate_type_check_v = duplicate_type_check<Ts...>::value;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// type_list
|
||||
//
|
||||
// type_list is a simple struct that allows us to pass template parameter packs
|
||||
// around in a single struct, and deduce parameter packs from function arguments
|
||||
// like so:
|
||||
//
|
||||
// template <typename... Ts> void foo(type_list<Ts...>);
|
||||
// foo(type_list<A, B, C>); // deduces Ts... as A, B, C
|
||||
//
|
||||
template <typename...> struct type_list {};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// unique_type_list
|
||||
//
|
||||
// unique_type_list is a meta-function which takes a parameter pack as its
|
||||
// argument, and returns a type_list with duplicate types removed, like so:
|
||||
//
|
||||
// unique_type_list<int, int, string>::type; // type = type_list<int, string>
|
||||
// unique_type_list<int, string, string>::type; // type = type_list<int, string>
|
||||
//
|
||||
// To use unique_type_list, specialize a variadic class template for a single
|
||||
// type parameter, which is type_list<Ts...>:
|
||||
//
|
||||
// template <typename... Ts> struct foo {};
|
||||
// template <typename... Ts> struct foo<type_list<Ts...>> {};
|
||||
//
|
||||
// Then instantiate the template with unique_type_list_t<Ts...> as its parameter:
|
||||
//
|
||||
// template <typename... Ts> struct bar : public foo<unique_type_list_t<Ts...>> {}
|
||||
//
|
||||
// See overload_set below for examples.
|
||||
template <typename T, typename... Ts>
|
||||
struct unique_type_list : public unique_type_list<Ts...>
|
||||
{
|
||||
template <typename... Args>
|
||||
static enable_if_t<!disjunction_v<is_same<T, Args>...>, type_list<T, Args...>>
|
||||
types(type_list<Args...>);
|
||||
|
||||
template <typename... Args>
|
||||
static enable_if_t<disjunction_v<is_same<T, Args>...>, type_list<Args...>>
|
||||
types(type_list<Args...>);
|
||||
|
||||
typedef decltype(types(declval<typename unique_type_list<Ts...>::type>())) type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct unique_type_list<T>
|
||||
{
|
||||
using type = type_list<T>;
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
using unique_type_list_t = typename unique_type_list<Ts...>::type;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// overload_resolution_t
|
||||
//
|
||||
// Given an input type and a typelist (which is a stand-in for alternative
|
||||
// function overloads) this traits will return the same type chosen as if
|
||||
// overload_resolution has selected a function to run.
|
||||
//
|
||||
|
||||
// a single overload of an individual type
|
||||
template <typename T>
|
||||
struct overload
|
||||
{
|
||||
// Overload is implicitly convertible to the surrogated function
|
||||
// call for pointer to member functions (pmf). This gets around
|
||||
// variadic pack expansion in a class using statement being a C++17
|
||||
// language feature. It is the core mechanism of aggregating all the
|
||||
// individual overloads into the overload_set structure.
|
||||
using F = T (*)(T);
|
||||
operator F() const { return nullptr; }
|
||||
};
|
||||
|
||||
template <typename...> struct overload_set_impl;
|
||||
|
||||
template <typename... Ts>
|
||||
struct overload_set_impl<type_list<Ts...>> : public overload<Ts>... {};
|
||||
|
||||
template <typename... Ts>
|
||||
struct overload_set : public overload_set_impl<unique_type_list_t<Ts...>>
|
||||
{
|
||||
// encapsulates the overloads matching the types of the variadic pack
|
||||
};
|
||||
|
||||
EA_DISABLE_VC_WARNING(4242 4244) // conversion from 'T' to 'U', possible loss of data.
|
||||
template <typename T, typename OverloadSet, typename ResultT = decltype(declval<OverloadSet>()(declval<T>()))>
|
||||
struct overload_resolution
|
||||
{
|
||||
// capture the return type of the function the compiler selected by
|
||||
// performing overload resolution on the overload set parameter
|
||||
using type = ResultT;
|
||||
};
|
||||
|
||||
EA_RESTORE_VC_WARNING()
|
||||
|
||||
template <typename T, typename OverloadSet>
|
||||
using overload_resolution_t = typename overload_resolution<decay_t<T>, OverloadSet>::type;
|
||||
|
||||
} // namespace meta
|
||||
} // namespace eastl
|
||||
|
||||
#endif // EASTL_META_H
|
||||
|
||||
@@ -50,14 +50,17 @@ namespace eastl
|
||||
///
|
||||
/// nullopt_t is class type used to indicate eastl::optional type with uninitialized state.
|
||||
///
|
||||
struct nullopt_tag_t {};
|
||||
|
||||
struct nullopt_t
|
||||
{
|
||||
EA_CONSTEXPR nullopt_t(int) {}
|
||||
EA_CONSTEXPR nullopt_t(nullopt_tag_t) {}
|
||||
};
|
||||
EA_CONSTEXPR nullopt_t nullopt{0};
|
||||
|
||||
EA_CONSTEXPR nullopt_t nullopt{nullopt_tag_t{}};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// bad_optional_access
|
||||
///
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
@@ -73,14 +76,25 @@ namespace eastl
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// optional_storage
|
||||
///
|
||||
template<typename T, bool IsTriviallyDestructible = eastl::is_trivially_destructible<T>::value>
|
||||
template<typename T, bool IsTriviallyDestructible = eastl::is_trivially_destructible_v<T>>
|
||||
struct optional_storage
|
||||
{
|
||||
typedef typename eastl::remove_const<T>::type value_type;
|
||||
|
||||
inline optional_storage() EA_NOEXCEPT : empty_val('\0') {}
|
||||
inline optional_storage(const optional_storage& other) : val(other.val), engaged(other.engaged) { }
|
||||
inline optional_storage(const value_type& v) : val(v), engaged(true) {}
|
||||
|
||||
template<typename TT = T, typename = eastl::enable_if_t<eastl::is_copy_constructible_v<TT>>>
|
||||
inline optional_storage(const optional_storage& other) : engaged(other.engaged)
|
||||
{
|
||||
auto* pOtherValue = reinterpret_cast<const T*>(eastl::addressof(other.val));
|
||||
::new (eastl::addressof(val)) value_type(*pOtherValue);
|
||||
}
|
||||
|
||||
inline optional_storage(const value_type& v) : engaged(true)
|
||||
{
|
||||
::new (eastl::addressof(val)) value_type(v);
|
||||
}
|
||||
|
||||
inline optional_storage(value_type&& v) : engaged(true)
|
||||
{
|
||||
::new (eastl::addressof(val)) value_type(eastl::move(v));
|
||||
@@ -90,25 +104,33 @@ namespace eastl
|
||||
{
|
||||
if (engaged)
|
||||
destruct_value();
|
||||
|
||||
// engaged = false; // probably not needed as we are destroying the object
|
||||
}
|
||||
|
||||
inline optional_storage& operator=(const optional_storage& other) {}
|
||||
template<typename TT = T, typename = eastl::enable_if_t<eastl::is_copy_constructible_v<TT>>>
|
||||
inline optional_storage& operator=(const optional_storage& other)
|
||||
{
|
||||
auto* pOtherValue = reinterpret_cast<const T*>(eastl::addressof(other.val));
|
||||
::new (eastl::addressof(val)) value_type(*pOtherValue);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if EASTL_VARIADIC_TEMPLATES_ENABLED
|
||||
template <class... Args>
|
||||
inline explicit optional_storage(in_place_t, Args&&... args)
|
||||
: val(eastl::forward<Args>(args)...), engaged(true) {}
|
||||
template <class... Args>
|
||||
inline explicit optional_storage(in_place_t, Args&&... args)
|
||||
: engaged(true)
|
||||
{
|
||||
::new (eastl::addressof(val)) T{std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
template <typename U,
|
||||
typename... Args,
|
||||
typename = typename eastl::enable_if<
|
||||
eastl::is_constructible<T, std::initializer_list<U>&, Args&&...>::value>::type>
|
||||
inline explicit optional_storage(in_place_t, std::initializer_list<U> ilist, Args&&... args)
|
||||
: engaged(true)
|
||||
{
|
||||
::new (eastl::addressof(val)) value_type(ilist, eastl::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
template <typename U,
|
||||
typename... Args,
|
||||
typename = eastl::enable_if_t<eastl::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>>
|
||||
inline explicit optional_storage(in_place_t, std::initializer_list<U> ilist, Args&&... args)
|
||||
: engaged(true)
|
||||
{
|
||||
::new (eastl::addressof(val)) value_type{ilist, eastl::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
inline void destruct_value() { (*(value_type*)eastl::addressof(val)).~value_type(); }
|
||||
|
||||
@@ -132,14 +154,24 @@ namespace eastl
|
||||
template<typename T>
|
||||
struct optional_storage<T, true>
|
||||
{
|
||||
typedef typename eastl::remove_const<T>::type value_type;
|
||||
typedef eastl::remove_const_t<T> value_type;
|
||||
|
||||
inline optional_storage() EA_NOEXCEPT : empty_val('\0') {}
|
||||
inline optional_storage(const optional_storage& other) : val(other.val), engaged(other.engaged) { }
|
||||
inline optional_storage(const value_type& v) : val(v), engaged(true) {}
|
||||
inline optional_storage(value_type&& v) : engaged(true)
|
||||
|
||||
inline optional_storage(const optional_storage& other) : engaged(other.engaged)
|
||||
{
|
||||
::new (eastl::addressof(val)) value_type(eastl::move(v));
|
||||
auto* pOtherValue = reinterpret_cast<const T*>(eastl::addressof(other.val));
|
||||
::new (eastl::addressof(val)) value_type(*pOtherValue);
|
||||
}
|
||||
|
||||
inline optional_storage(const value_type& v) : engaged(true)
|
||||
{
|
||||
::new (eastl::addressof(val)) value_type(v);
|
||||
}
|
||||
|
||||
inline optional_storage(value_type&& v) : engaged(true)
|
||||
{
|
||||
::new (eastl::addressof(val)) value_type(eastl::move(v));
|
||||
}
|
||||
|
||||
// Removed to make optional<T> trivially destructible when T is trivially destructible.
|
||||
@@ -150,26 +182,28 @@ namespace eastl
|
||||
// destruct_value();
|
||||
// }
|
||||
|
||||
inline optional_storage& operator=(const optional_storage& other) {}
|
||||
inline optional_storage& operator=(const optional_storage& other)
|
||||
{
|
||||
auto* pOtherValue = reinterpret_cast<const T*>(eastl::addressof(other.val));
|
||||
::new (eastl::addressof(val)) value_type(*pOtherValue);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if EASTL_VARIADIC_TEMPLATES_ENABLED
|
||||
template <class... Args>
|
||||
inline explicit optional_storage(in_place_t, Args&&... args)
|
||||
: engaged(true)
|
||||
{
|
||||
new (eastl::addressof(val)) value_type(eastl::forward<Args>(args)...);
|
||||
}
|
||||
template <class... Args>
|
||||
inline explicit optional_storage(in_place_t, Args&&... args)
|
||||
: engaged(true)
|
||||
{
|
||||
new (eastl::addressof(val)) value_type{eastl::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
template <typename U,
|
||||
typename... Args,
|
||||
typename = typename eastl::enable_if<
|
||||
eastl::is_constructible<T, std::initializer_list<U>&, Args&&...>::value>::type>
|
||||
inline explicit optional_storage(in_place_t, std::initializer_list<U> ilist, Args&&... args)
|
||||
: engaged(true)
|
||||
{
|
||||
new (eastl::addressof(val)) value_type(ilist, eastl::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
template <typename U,
|
||||
typename... Args,
|
||||
typename = eastl::enable_if_t<eastl::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>>
|
||||
inline explicit optional_storage(in_place_t, std::initializer_list<U> ilist, Args&&... args)
|
||||
: engaged(true)
|
||||
{
|
||||
new (eastl::addressof(val)) value_type{ilist, eastl::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
inline void destruct_value() {} // no implementation necessary since T is trivially destructible.
|
||||
|
||||
@@ -183,7 +217,7 @@ namespace eastl
|
||||
};
|
||||
bool engaged = false;
|
||||
};
|
||||
}
|
||||
} // namespace Internal
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -210,26 +244,51 @@ namespace eastl
|
||||
inline optional() EA_NOEXCEPT {}
|
||||
inline optional(nullopt_t) EA_NOEXCEPT {}
|
||||
inline optional(const value_type& value) : base_type(value) {}
|
||||
inline optional(value_type&& value) EA_NOEXCEPT_IF(eastl::is_nothrow_move_constructible<T>::value)
|
||||
: base_type(eastl::move(value)) {}
|
||||
inline optional(value_type&& value) EA_NOEXCEPT_IF(eastl::is_nothrow_move_constructible_v<T>)
|
||||
: base_type(eastl::move(value))
|
||||
{
|
||||
}
|
||||
|
||||
optional(const optional& other) = default;
|
||||
optional(optional&& other) = default;
|
||||
optional(const optional& other)
|
||||
{
|
||||
engaged = other.engaged;
|
||||
|
||||
#if EASTL_VARIADIC_TEMPLATES_ENABLED
|
||||
template <typename... Args>
|
||||
inline explicit optional(in_place_t, Args&&... args)
|
||||
: base_type(in_place, eastl::forward<Args>(args)...) {}
|
||||
auto* pOtherStorage = reinterpret_cast<const base_type*>(eastl::addressof(other.val));
|
||||
base_type::operator=(*pOtherStorage);
|
||||
}
|
||||
|
||||
template <typename U,
|
||||
typename... Args,
|
||||
typename = typename eastl::enable_if<
|
||||
eastl::is_constructible<T, std::initializer_list<U>&, Args&&...>::value>::type>
|
||||
inline explicit optional(in_place_t, std::initializer_list<U> ilist, Args&&... args)
|
||||
: base_type(in_place, ilist, eastl::forward<Args>(args)...) {}
|
||||
#endif
|
||||
optional(optional&& other)
|
||||
{
|
||||
eastl::swap(engaged, other.engaged);
|
||||
|
||||
inline optional& operator=(nullopt_t)
|
||||
auto* pOtherValue = reinterpret_cast<T*>(eastl::addressof(other.val));
|
||||
::new (eastl::addressof(val)) value_type(eastl::move(*pOtherValue));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline explicit optional(in_place_t, Args&&... args)
|
||||
: base_type(in_place, eastl::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename U,
|
||||
typename... Args,
|
||||
typename = eastl::enable_if_t<eastl::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>>
|
||||
inline explicit optional(in_place_t, std::initializer_list<U> ilist, Args&&... args)
|
||||
: base_type(in_place, ilist, eastl::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename U = value_type,
|
||||
typename = eastl::enable_if_t<eastl::is_constructible_v<T, U&&> &&
|
||||
!eastl::is_same_v<eastl::remove_cvref_t<U>, eastl::in_place_t> &&
|
||||
!eastl::is_same_v<eastl::remove_cvref_t<U>, optional>>>
|
||||
inline explicit EA_CONSTEXPR optional(U&& value)
|
||||
: base_type(in_place, eastl::forward<U>(value))
|
||||
{
|
||||
}
|
||||
|
||||
inline optional& operator=(nullopt_t)
|
||||
{
|
||||
reset();
|
||||
return *this;
|
||||
@@ -238,7 +297,10 @@ namespace eastl
|
||||
inline optional& operator=(const optional& other)
|
||||
{
|
||||
engaged = other.engaged;
|
||||
val = other.val;
|
||||
|
||||
auto* pOtherStorage = reinterpret_cast<const base_type*>(eastl::addressof(other.val));
|
||||
base_type::operator=(*pOtherStorage);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -246,8 +308,11 @@ namespace eastl
|
||||
EA_NOEXCEPT_IF(EA_NOEXCEPT(eastl::is_nothrow_move_assignable<value_type>::value &&
|
||||
eastl::is_nothrow_move_constructible<value_type>::value))
|
||||
{
|
||||
engaged = other.engaged;
|
||||
val = eastl::move(other.val);
|
||||
eastl::swap(engaged, other.engaged);
|
||||
|
||||
auto* pOtherValue = reinterpret_cast<T*>(eastl::addressof(other.val));
|
||||
::new (eastl::addressof(val)) value_type(eastl::move(*pOtherValue));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -273,13 +338,13 @@ namespace eastl
|
||||
|
||||
template <class U>
|
||||
inline value_type value_or(U&& default_value) const
|
||||
{ return engaged ? val : static_cast<value_type>(eastl::forward<U>(default_value)); }
|
||||
{ return engaged ? *get_value_address() : static_cast<value_type>(eastl::forward<U>(default_value)); }
|
||||
|
||||
template <class U>
|
||||
inline value_type value_or(U&& default_value)
|
||||
{ return engaged ? *get_value_address() : static_cast<value_type>(eastl::forward<U>(default_value)); }
|
||||
|
||||
inline const T& value()& { return get_value_ref(); }
|
||||
inline T& value()& { return get_value_ref(); }
|
||||
inline const T& value() const& { return get_value_ref(); }
|
||||
inline T&& value()&& { return get_rvalue_ref(); }
|
||||
inline const T&& value() const&& { return get_rvalue_ref(); }
|
||||
@@ -291,21 +356,19 @@ namespace eastl
|
||||
inline const T& operator*() const& { return get_value_ref(); }
|
||||
inline const T&& operator*() const&& { return get_rvalue_ref(); }
|
||||
|
||||
#if EASTL_VARIADIC_TEMPLATES_ENABLED
|
||||
template <class... Args>
|
||||
void emplace(Args&&... args)
|
||||
{
|
||||
construct_value(eastl::move(T(eastl::forward<Args>(args)...)));
|
||||
engaged = true;
|
||||
}
|
||||
template <class... Args>
|
||||
void emplace(Args&&... args)
|
||||
{
|
||||
construct_value(eastl::move(T(eastl::forward<Args>(args)...)));
|
||||
engaged = true;
|
||||
}
|
||||
|
||||
template <class U, class... Args>
|
||||
void emplace(std::initializer_list<U> ilist, Args&&... args)
|
||||
{
|
||||
construct_value(eastl::move(T(ilist, eastl::forward<Args>(args)...)));
|
||||
engaged = true;
|
||||
}
|
||||
#endif
|
||||
template <class U, class... Args>
|
||||
void emplace(std::initializer_list<U> ilist, Args&&... args)
|
||||
{
|
||||
construct_value(eastl::move(T(ilist, eastl::forward<Args>(args)...)));
|
||||
engaged = true;
|
||||
}
|
||||
|
||||
inline void swap(optional& other)
|
||||
EA_NOEXCEPT_IF(eastl::is_nothrow_move_constructible<T>::value&& eastl::is_nothrow_swappable<T>::value)
|
||||
@@ -403,7 +466,7 @@ namespace eastl
|
||||
#endif
|
||||
return eastl::move(*((value_type*)eastl::addressof(val)));
|
||||
}
|
||||
};
|
||||
}; // class optional
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -604,13 +667,26 @@ namespace eastl
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// make_optional
|
||||
///
|
||||
template <class T>
|
||||
inline optional<typename eastl::decay<T>::type> make_optional(T&& value)
|
||||
{
|
||||
return optional<typename eastl::decay<T>::type>(eastl::forward<T>(value));
|
||||
}
|
||||
template <class T>
|
||||
inline EA_CONSTEXPR optional<decay_t<T>> make_optional(T&& value)
|
||||
{
|
||||
return optional<decay_t<T>>(eastl::forward<T>(value));
|
||||
}
|
||||
|
||||
#undef EASTL_OPTIONAL_NOEXCEPT
|
||||
template <class T, class... Args>
|
||||
inline EA_CONSTEXPR optional<T> make_optional(Args&&... args)
|
||||
{
|
||||
return optional<T>(eastl::in_place, eastl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class T, class U, class... Args>
|
||||
inline EA_CONSTEXPR optional<T> make_optional(std::initializer_list<U> il, Args&&... args)
|
||||
{
|
||||
return eastl::optional<T>(eastl::in_place, il, eastl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
||||
#undef EASTL_OPTIONAL_NOEXCEPT
|
||||
|
||||
} // namespace eastl
|
||||
|
||||
|
||||
@@ -1322,7 +1322,7 @@ namespace eastl
|
||||
// If this is the last merge, just do it.
|
||||
if((stack_curr == 2) && ((run_stack[0].length + run_stack[1].length) == size))
|
||||
{
|
||||
tim_sort_merge(first, run_stack, stack_curr, pBuffer, compare);
|
||||
tim_sort_merge<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr, pBuffer, compare);
|
||||
run_stack[0].length += run_stack[1].length;
|
||||
stack_curr--;
|
||||
|
||||
@@ -1335,7 +1335,7 @@ namespace eastl
|
||||
// Check if the invariant is off for a run_stack of 2 elements.
|
||||
else if((stack_curr == 2) && (run_stack[0].length <= run_stack[1].length))
|
||||
{
|
||||
tim_sort_merge(first, run_stack, stack_curr, pBuffer, compare);
|
||||
tim_sort_merge<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr, pBuffer, compare);
|
||||
run_stack[0].length += run_stack[1].length;
|
||||
stack_curr--;
|
||||
|
||||
@@ -1356,7 +1356,7 @@ namespace eastl
|
||||
{
|
||||
if(A < C)
|
||||
{
|
||||
tim_sort_merge(first, run_stack, stack_curr - 1, pBuffer, compare);
|
||||
tim_sort_merge<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr - 1, pBuffer, compare);
|
||||
|
||||
stack_curr--;
|
||||
run_stack[stack_curr - 2].length += run_stack[stack_curr - 1].length; // Merge A and B.
|
||||
@@ -1370,7 +1370,7 @@ namespace eastl
|
||||
}
|
||||
else
|
||||
{
|
||||
tim_sort_merge(first, run_stack, stack_curr, pBuffer, compare); // Merge B and C.
|
||||
tim_sort_merge<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr, pBuffer, compare); // Merge B and C.
|
||||
|
||||
stack_curr--;
|
||||
run_stack[stack_curr - 1].length += run_stack[stack_curr].length;
|
||||
@@ -1383,7 +1383,7 @@ namespace eastl
|
||||
}
|
||||
else if(B <= C) // Check second invariant
|
||||
{
|
||||
tim_sort_merge(first, run_stack, stack_curr, pBuffer, compare);
|
||||
tim_sort_merge<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr, pBuffer, compare);
|
||||
|
||||
stack_curr--;
|
||||
run_stack[stack_curr - 1].length += run_stack[stack_curr].length; // Merge B and C.
|
||||
@@ -1409,7 +1409,7 @@ namespace eastl
|
||||
bool tim_sort_add_run(tim_sort_run* run_stack, RandomAccessIterator first, T* pBuffer, const intptr_t size, const intptr_t minrun,
|
||||
intptr_t& len, intptr_t& run, intptr_t& curr, intptr_t& stack_curr, StrictWeakOrdering compare)
|
||||
{
|
||||
len = tim_sort_count_run(first, curr, size, compare); // This will count the length of the run and reverse the run if it is backwards.
|
||||
len = tim_sort_count_run<RandomAccessIterator, StrictWeakOrdering>(first, curr, size, compare); // This will count the length of the run and reverse the run if it is backwards.
|
||||
run = minrun;
|
||||
|
||||
if(run < minrun) // Always make runs be of minrun length (we'll sort the additional data as needed below)
|
||||
@@ -1420,7 +1420,7 @@ namespace eastl
|
||||
|
||||
if(run > len) // If there is any additional data we want to sort to bring up the run length to minrun.
|
||||
{
|
||||
insertion_sort_already_started(first + curr, first + curr + run, first + curr + len, compare);
|
||||
insertion_sort_already_started<RandomAccessIterator, StrictWeakOrdering>(first + curr, first + curr + run, first + curr + len, compare);
|
||||
len = run;
|
||||
}
|
||||
|
||||
@@ -1440,7 +1440,7 @@ namespace eastl
|
||||
{
|
||||
while(stack_curr > 1) // If there is any more than one run... (else all the data is sorted)
|
||||
{
|
||||
tim_sort_merge(first, run_stack, stack_curr, pBuffer, compare);
|
||||
tim_sort_merge<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr, pBuffer, compare);
|
||||
|
||||
run_stack[stack_curr - 2].length += run_stack[stack_curr - 1].length;
|
||||
stack_curr--;
|
||||
@@ -1517,20 +1517,20 @@ namespace eastl
|
||||
memset(run_stack, 0, sizeof(run_stack));
|
||||
#endif
|
||||
|
||||
if(tim_sort_add_run(run_stack, first, pBuffer, size, minrun, len, run, curr, stack_curr, compare))
|
||||
if(tim_sort_add_run<RandomAccessIterator, T, StrictWeakOrdering>(run_stack, first, pBuffer, size, minrun, len, run, curr, stack_curr, compare))
|
||||
return;
|
||||
if(tim_sort_add_run(run_stack, first, pBuffer, size, minrun, len, run, curr, stack_curr, compare))
|
||||
if(tim_sort_add_run<RandomAccessIterator, T, StrictWeakOrdering>(run_stack, first, pBuffer, size, minrun, len, run, curr, stack_curr, compare))
|
||||
return;
|
||||
if(tim_sort_add_run(run_stack, first, pBuffer, size, minrun, len, run, curr, stack_curr, compare))
|
||||
if(tim_sort_add_run<RandomAccessIterator, T, StrictWeakOrdering>(run_stack, first, pBuffer, size, minrun, len, run, curr, stack_curr, compare))
|
||||
return;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(timsort_check_invariant(run_stack, stack_curr))
|
||||
stack_curr = tim_sort_collapse(first, run_stack, stack_curr, pBuffer, size, compare);
|
||||
stack_curr = tim_sort_collapse<RandomAccessIterator, T, StrictWeakOrdering>(first, run_stack, stack_curr, pBuffer, size, compare);
|
||||
else
|
||||
{
|
||||
if(tim_sort_add_run(run_stack, first, pBuffer, size, minrun, len, run, curr, stack_curr, compare))
|
||||
if(tim_sort_add_run<RandomAccessIterator, T, StrictWeakOrdering>(run_stack, first, pBuffer, size, minrun, len, run, curr, stack_curr, compare))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1639,7 +1639,7 @@ namespace eastl
|
||||
|
||||
// If a single bucket contains all of the elements, then don't bother redistributing all elements to the
|
||||
// same bucket.
|
||||
if (bucketSize[((extractKey(*srcFirst) >> j) & bucketMask)] == last - srcFirst)
|
||||
if (bucketSize[((extractKey(*srcFirst) >> j) & bucketMask)] == uint32_t(last - srcFirst))
|
||||
{
|
||||
// Set flag to ensure histogram is computed for next digit position.
|
||||
doSeparateHistogramCalculation = true;
|
||||
@@ -1658,7 +1658,6 @@ namespace eastl
|
||||
bucketPosition[i + 1] = bucketPosition[i] + bucketSize[i];
|
||||
}
|
||||
|
||||
uint32_t jNext = j + DigitBits;
|
||||
for (temp = srcFirst; temp != last; ++temp)
|
||||
{
|
||||
IntegerType key = extractKey(*temp);
|
||||
|
||||
374
include/EASTL/span.h
Normal file
374
include/EASTL/span.h
Normal file
@@ -0,0 +1,374 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// This file implements the eastl::span which is part of the C++ standard
|
||||
// STL library specification.
|
||||
//
|
||||
// eastl::span is a non-owning container that refers to a contiguous block of
|
||||
// memory. It bundles up the classic pattern of a pointer and a size into a
|
||||
// single type. A span can either have a static extent, in which case the
|
||||
// number of elements in the sequence is known and encoded in the type, or a
|
||||
// dynamic extent.
|
||||
//
|
||||
// http://en.cppreference.com/w/cpp/container/span
|
||||
// http://eel.is/c++draft/views#span.syn
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EASTL_SPAN_H
|
||||
#define EASTL_SPAN_H
|
||||
|
||||
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <EASTL/internal/config.h>
|
||||
#include <EASTL/type_traits.h>
|
||||
#include <EASTL/iterator.h>
|
||||
#include <EASTL/array.h>
|
||||
|
||||
namespace eastl
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
// HasSizeAndData
|
||||
//
|
||||
// custom type trait to determine if eastl::data(Container) and eastl::size(Container) are well-formed.
|
||||
//
|
||||
template <typename, typename = void>
|
||||
struct HasSizeAndData : eastl::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct HasSizeAndData<T, void_t<decltype(eastl::size(eastl::declval<T>())), decltype(eastl::data(eastl::declval<T>()))>> : eastl::true_type {};
|
||||
}
|
||||
|
||||
static EA_CONSTEXPR ptrdiff_t dynamic_extent = ptrdiff_t(-1);
|
||||
|
||||
template <typename T, ptrdiff_t Extent = eastl::dynamic_extent>
|
||||
class span
|
||||
{
|
||||
public:
|
||||
typedef T element_type;
|
||||
typedef remove_cv_t<T> value_type;
|
||||
typedef ptrdiff_t index_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef T& reference;
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
typedef eastl::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef eastl::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
static EA_CONSTEXPR ptrdiff_t extent = Extent;
|
||||
|
||||
// constructors / destructor
|
||||
EA_CONSTEXPR span() EA_NOEXCEPT = default;
|
||||
EA_CONSTEXPR span(const span& other) EA_NOEXCEPT = default;
|
||||
EA_CONSTEXPR span(pointer ptr, index_type count);
|
||||
EA_CONSTEXPR span(pointer pBegin, pointer pEnd);
|
||||
~span() EA_NOEXCEPT = default;
|
||||
|
||||
// copy-assignment operator
|
||||
EA_CPP14_CONSTEXPR span& operator=(const span& other) EA_NOEXCEPT = default;
|
||||
|
||||
// conversion constructors for c-array and eastl::array
|
||||
template <size_t N> EA_CONSTEXPR span(element_type (&arr)[N]) EA_NOEXCEPT;
|
||||
template <size_t N> EA_CONSTEXPR span(eastl::array<value_type, N>& arr) EA_NOEXCEPT;
|
||||
template <size_t N> EA_CONSTEXPR span(const eastl::array<value_type, N>& arr) EA_NOEXCEPT;
|
||||
|
||||
// SfinaeForGenericContainers
|
||||
//
|
||||
template <typename Container>
|
||||
using SfinaeForGenericContainers =
|
||||
enable_if_t<!is_same_v<Container, span> && !is_same_v<Container, array<value_type>> &&
|
||||
!is_array_v<Container> &&
|
||||
Internal::HasSizeAndData<Container>::value &&
|
||||
is_convertible_v<remove_pointer_t<decltype(eastl::data(eastl::declval<Container>()))> (*)[], element_type (*)[]>>;
|
||||
|
||||
// generic container conversion constructors
|
||||
template <typename Container, typename = SfinaeForGenericContainers<Container>>
|
||||
EA_CONSTEXPR span(Container& cont);
|
||||
|
||||
template <typename Container, typename = SfinaeForGenericContainers<Container>>
|
||||
EA_CONSTEXPR span(const Container& cont);
|
||||
|
||||
template <typename U, ptrdiff_t N, typename = enable_if_t<(Extent == eastl::dynamic_extent || N == Extent) && (is_convertible_v<U(*)[], element_type(*)[]>)>>
|
||||
EA_CONSTEXPR span(const span<U, N>& s) EA_NOEXCEPT;
|
||||
|
||||
// subviews
|
||||
template<ptrdiff_t Count>
|
||||
EA_CPP14_CONSTEXPR span<element_type, Count> first() const;
|
||||
EA_CPP14_CONSTEXPR span<element_type, dynamic_extent> first(ptrdiff_t Count) const;
|
||||
|
||||
template<ptrdiff_t Count>
|
||||
EA_CPP14_CONSTEXPR span<element_type, Count> last() const;
|
||||
EA_CPP14_CONSTEXPR span<element_type, dynamic_extent> last(ptrdiff_t Count) const;
|
||||
|
||||
// template <ptrdiff_t Offset, ptrdiff_t Count = dynamic_extent>
|
||||
// EA_CONSTEXPR span<element_type, E [> see below <]> subspan() const;
|
||||
// EA_CONSTEXPR span<element_type, dynamic_extent> subspan(ptrdiff_t Offset, ptrdiff_t Count = dynamic_extent) const;
|
||||
|
||||
// observers
|
||||
EA_CONSTEXPR pointer data() const EA_NOEXCEPT;
|
||||
EA_CONSTEXPR index_type size() const EA_NOEXCEPT;
|
||||
EA_CONSTEXPR index_type size_bytes() const EA_NOEXCEPT;
|
||||
EA_CONSTEXPR bool empty() const EA_NOEXCEPT;
|
||||
|
||||
// subscript operators, element access
|
||||
EA_CONSTEXPR reference operator[](index_type idx) const;
|
||||
EA_CONSTEXPR reference operator()(index_type idx) const;
|
||||
|
||||
// iterator support
|
||||
EA_CONSTEXPR iterator begin() const EA_NOEXCEPT;
|
||||
EA_CONSTEXPR iterator end() const EA_NOEXCEPT;
|
||||
EA_CONSTEXPR const_iterator cbegin() const EA_NOEXCEPT;
|
||||
EA_CONSTEXPR const_iterator cend() const EA_NOEXCEPT;
|
||||
EA_CONSTEXPR reverse_iterator rbegin() const EA_NOEXCEPT;
|
||||
EA_CONSTEXPR reverse_iterator rend() const EA_NOEXCEPT;
|
||||
EA_CONSTEXPR const_reverse_iterator crbegin() const EA_NOEXCEPT;
|
||||
EA_CONSTEXPR const_reverse_iterator crend() const EA_NOEXCEPT;
|
||||
|
||||
private:
|
||||
pointer mpData = nullptr;
|
||||
index_type mnSize = 0;
|
||||
|
||||
private:
|
||||
EA_CONSTEXPR bool bounds_check(ptrdiff_t) const; // utility used in asserts
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// template deduction guides
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// template<class T, size_t N> span(T (&)[N]) -> span <T, N>;
|
||||
// template<class T, size_t N> span(array<T, N>&) -> span <T, N>;
|
||||
// template<class T, size_t N> span(const array<T, N>&) -> span <const T, N>;
|
||||
// template<class Container> span(Container&) -> span <typename Container::value_type>;
|
||||
// template<class Container> span(const Container&) -> span <const typename Container::value_type>;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// comparison operators
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T, ptrdiff_t X, class U, ptrdiff_t Y>
|
||||
EA_CONSTEXPR bool operator==(span<T, X> l, span<U, Y> r)
|
||||
{
|
||||
return (l.size() == r.size()) && eastl::equal(l.begin(), l.end(), r.begin());
|
||||
}
|
||||
|
||||
template <class T, ptrdiff_t X, class U, ptrdiff_t Y>
|
||||
EA_CONSTEXPR bool operator<(span<T, X> l, span<U, Y> r)
|
||||
{
|
||||
return lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
|
||||
}
|
||||
|
||||
template <class T, ptrdiff_t X, class U, ptrdiff_t Y>
|
||||
EA_CONSTEXPR bool operator!=(span<T, X> l, span<U, Y> r) { return !(l == r); }
|
||||
|
||||
template <class T, ptrdiff_t X, class U, ptrdiff_t Y>
|
||||
EA_CONSTEXPR bool operator<=(span<T, X> l, span<U, Y> r) { return !(r < l); }
|
||||
|
||||
template <class T, ptrdiff_t X, class U, ptrdiff_t Y>
|
||||
EA_CONSTEXPR bool operator>(span<T, X> l, span<U, Y> r) { return r < l; }
|
||||
|
||||
template <class T, ptrdiff_t X, class U, ptrdiff_t Y>
|
||||
EA_CONSTEXPR bool operator>=(span<T, X> l, span<U, Y> r) { return !(l < r); }
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ctor implementations
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR span<T, Extent>::span(pointer ptr, index_type size)
|
||||
: mpData(ptr), mnSize(size)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR span<T, Extent>::span(pointer pBegin, pointer pEnd)
|
||||
: mpData(pBegin), mnSize(pEnd - pBegin)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
template <size_t N>
|
||||
EA_CONSTEXPR span<T, Extent>::span(element_type(&arr)[N]) EA_NOEXCEPT
|
||||
: span(arr, static_cast<index_type>(N))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
template <size_t N>
|
||||
EA_CONSTEXPR span<T, Extent>::span(eastl::array<value_type, N> &arr) EA_NOEXCEPT
|
||||
: span(arr.data(), arr.size())
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
template <size_t N>
|
||||
EA_CONSTEXPR span<T, Extent>::span(const eastl::array<value_type, N>& arr) EA_NOEXCEPT
|
||||
: span(arr.data(), arr.size())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
template <typename Container, typename>
|
||||
EA_CONSTEXPR span<T, Extent>::span(Container& cont)
|
||||
: span(static_cast<pointer>(eastl::data(cont)), static_cast<index_type>(eastl::size(cont)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
template <typename Container, typename>
|
||||
EA_CONSTEXPR span<T, Extent>::span(const Container& cont)
|
||||
: span(static_cast<pointer>(eastl::data(cont)), static_cast<index_type>(eastl::size(cont)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
template <typename U, ptrdiff_t N, typename>
|
||||
EA_CONSTEXPR span<T, Extent>::span(const span<U, N>& s) EA_NOEXCEPT
|
||||
: span(s.data(), s.size())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// member function implementations
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR typename span<T, Extent>::pointer span<T, Extent>::data() const EA_NOEXCEPT
|
||||
{
|
||||
return mpData;
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR typename span<T, Extent>::index_type span<T, Extent>::size() const EA_NOEXCEPT
|
||||
{
|
||||
return mnSize;
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR typename span<T, Extent>::index_type span<T, Extent>::size_bytes() const EA_NOEXCEPT
|
||||
{
|
||||
return size() * sizeof(element_type);
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR bool span<T, Extent>::empty() const EA_NOEXCEPT
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR typename span<T, Extent>::reference span<T, Extent>::operator[](index_type idx) const
|
||||
{
|
||||
EASTL_ASSERT_MSG(!empty(), "undefined behavior accessing an empty span");
|
||||
EASTL_ASSERT_MSG(bounds_check(idx), "undefined behavior accessing out of bounds");
|
||||
|
||||
return mpData[idx];
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR typename span<T, Extent>::reference span<T, Extent>::operator()(index_type idx) const
|
||||
{
|
||||
EASTL_ASSERT_MSG(!empty(), "undefined behavior accessing an empty span");
|
||||
EASTL_ASSERT_MSG(bounds_check(idx), "undefined behavior accessing out of bounds");
|
||||
|
||||
return mpData[idx];
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR typename span<T, Extent>::iterator span<T, Extent>::begin() const EA_NOEXCEPT
|
||||
{
|
||||
return mpData;
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR typename span<T, Extent>::iterator span<T, Extent>::end() const EA_NOEXCEPT
|
||||
{
|
||||
return mpData + mnSize;
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR typename span<T, Extent>::const_iterator span<T, Extent>::cbegin() const EA_NOEXCEPT
|
||||
{
|
||||
return mpData;
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR typename span<T, Extent>::const_iterator span<T, Extent>::cend() const EA_NOEXCEPT
|
||||
{
|
||||
return mpData + mnSize;
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR typename span<T, Extent>::reverse_iterator span<T, Extent>::rbegin() const EA_NOEXCEPT
|
||||
{
|
||||
return mpData + mnSize;
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR typename span<T, Extent>::reverse_iterator span<T, Extent>::rend() const EA_NOEXCEPT
|
||||
{
|
||||
return mpData;
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR typename span<T, Extent>::const_reverse_iterator span<T, Extent>::crbegin() const EA_NOEXCEPT
|
||||
{
|
||||
return const_reverse_iterator(mpData + mnSize);
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR typename span<T, Extent>::const_reverse_iterator span<T, Extent>::crend() const EA_NOEXCEPT
|
||||
{
|
||||
return const_reverse_iterator(mpData);
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
template <ptrdiff_t Count>
|
||||
EA_CPP14_CONSTEXPR span<typename span<T, Extent>::element_type, Count> span<T, Extent>::first() const
|
||||
{
|
||||
EASTL_ASSERT_MSG(bounds_check(Count), "undefined behavior accessing out of bounds");
|
||||
return {data(), Count};
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CPP14_CONSTEXPR span<typename span<T, Extent>::element_type, dynamic_extent>
|
||||
span<T, Extent>::first(ptrdiff_t sz) const
|
||||
{
|
||||
EASTL_ASSERT_MSG(bounds_check(sz), "undefined behavior accessing out of bounds");
|
||||
return {data(), sz};
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
template <ptrdiff_t Count>
|
||||
EA_CPP14_CONSTEXPR span<typename span<T, Extent>::element_type, Count> span<T, Extent>::last() const
|
||||
{
|
||||
EASTL_ASSERT_MSG(bounds_check(Count), "undefined behavior accessing out of bounds");
|
||||
return {data() + size() - Count, Count};
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CPP14_CONSTEXPR span<typename span<T, Extent>::element_type, dynamic_extent>
|
||||
span<T, Extent>::last(ptrdiff_t sz) const
|
||||
{
|
||||
EASTL_ASSERT_MSG(bounds_check(sz), "undefined behavior accessing out of bounds");
|
||||
return {data() + size() - sz, sz};
|
||||
}
|
||||
|
||||
template <typename T, ptrdiff_t Extent>
|
||||
EA_CONSTEXPR bool span<T, Extent>::bounds_check(ptrdiff_t sz) const
|
||||
{
|
||||
return (sz >= 0 && sz < size());
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EASTL_SPAN_H
|
||||
@@ -31,6 +31,8 @@
|
||||
// - 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.
|
||||
// - basic_string substr() deviates from the standard and returns a string with
|
||||
// a copy of this->get_allocator()
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -144,17 +146,6 @@ EA_RESTORE_ALL_VC_WARNINGS()
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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;
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Vsnprintf
|
||||
//
|
||||
@@ -273,6 +264,7 @@ namespace eastl
|
||||
{
|
||||
public:
|
||||
typedef basic_string<T, Allocator> this_type;
|
||||
typedef basic_string_view<T> view_type;
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
@@ -340,22 +332,22 @@ namespace eastl
|
||||
{
|
||||
// template specialization to remove the padding structure to avoid warnings on zero length arrays
|
||||
// also, this allows us to take advantage of the empty-base-class optimization.
|
||||
};
|
||||
};
|
||||
|
||||
// The view of memory when the string data is able to store the string data locally (without a heap allocation).
|
||||
struct SSOLayout
|
||||
{
|
||||
enum { SSO_CAPACITY = (sizeof(HeapLayout) - sizeof(char)) / sizeof(value_type) };
|
||||
enum : size_type { SSO_CAPACITY = (sizeof(HeapLayout) - sizeof(char)) / sizeof(value_type) };
|
||||
|
||||
// mnSize must correspond to the last byte of HeapLayout.mnCapacity, so we don't want the compiler to insert
|
||||
// padding after mnSize if sizeof(value_type) != 1; Also ensures both layouts are the same size.
|
||||
struct SSOSize : SSOPadding<value_type>
|
||||
{
|
||||
char mnSize;
|
||||
char mnRemainingSize;
|
||||
};
|
||||
|
||||
value_type mData[SSO_CAPACITY]; // Local buffer for string data.
|
||||
SSOSize mSizeField;
|
||||
SSOSize mRemainingSizeField;
|
||||
};
|
||||
|
||||
// This view of memory is a utility structure for easy copying of the string data.
|
||||
@@ -381,27 +373,26 @@ namespace eastl
|
||||
RawLayout raw;
|
||||
};
|
||||
|
||||
// start as SSO by default
|
||||
Layout() { ResetToSSO(); SetSSOSize(0); }
|
||||
Layout() { ResetToSSO(); SetSSOSize(0); } // start as SSO by default
|
||||
Layout(const Layout& other) { Copy(*this, other); }
|
||||
Layout(Layout&& other) { Move(*this, other); }
|
||||
Layout& operator=(const Layout& other) { Copy(*this, other); return *this; }
|
||||
Layout& operator=(Layout&& other) { Move(*this, other); return *this; }
|
||||
|
||||
// We are using Heap when the bit is set, easier to conceptualize checking IsHeap instead of IsSSO
|
||||
inline bool IsHeap() const EA_NOEXCEPT { return !!(sso.mSizeField.mnSize & kSSOMask); }
|
||||
inline bool IsHeap() const EA_NOEXCEPT { return !!(sso.mRemainingSizeField.mnRemainingSize & kSSOMask); }
|
||||
inline bool IsSSO() const EA_NOEXCEPT { return !IsHeap(); }
|
||||
inline value_type* SSOBufferPtr() EA_NOEXCEPT { return sso.mData; }
|
||||
inline const value_type* SSOBufferPtr() const EA_NOEXCEPT { return sso.mData; }
|
||||
|
||||
// Largest value for SSO.mnSize == 23, which has two LSB bits set, but on big-endian (BE)
|
||||
// Largest value for SSO.mnSize == 23, which has two LSB bits set, but on big-endian (BE)
|
||||
// use least significant bit (LSB) to denote heap so shift.
|
||||
inline size_type GetSSOSize() const EA_NOEXCEPT
|
||||
{
|
||||
#ifdef EA_SYSTEM_BIG_ENDIAN
|
||||
return SSOLayout::SSO_CAPACITY - (sso.mSizeField.mnSize >> 2);
|
||||
return SSOLayout::SSO_CAPACITY - (sso.mRemainingSizeField.mnRemainingSize >> 2);
|
||||
#else
|
||||
return (SSOLayout::SSO_CAPACITY - sso.mSizeField.mnSize);
|
||||
return (SSOLayout::SSO_CAPACITY - sso.mRemainingSizeField.mnRemainingSize);
|
||||
#endif
|
||||
}
|
||||
inline size_type GetHeapSize() const EA_NOEXCEPT { return heap.mnSize; }
|
||||
@@ -410,9 +401,9 @@ namespace eastl
|
||||
inline void SetSSOSize(size_type size) EA_NOEXCEPT
|
||||
{
|
||||
#ifdef EA_SYSTEM_BIG_ENDIAN
|
||||
sso.mSizeField.mnSize = (char)((SSOLayout::SSO_CAPACITY - size) << 2);
|
||||
sso.mRemainingSizeField.mnRemainingSize = (char)((SSOLayout::SSO_CAPACITY - size) << 2);
|
||||
#else
|
||||
sso.mSizeField.mnSize = (char)(SSOLayout::SSO_CAPACITY - size);
|
||||
sso.mRemainingSizeField.mnRemainingSize = (char)(SSOLayout::SSO_CAPACITY - size);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -437,7 +428,7 @@ namespace eastl
|
||||
inline const value_type* SSOEndPtr() const EA_NOEXCEPT { return sso.mData + GetSSOSize(); }
|
||||
|
||||
// Points to end of character stream, *ptr == '0'
|
||||
inline value_type* EndPtr() EA_NOEXCEPT { return IsHeap() ? HeapEndPtr() : SSOEndPtr(); }
|
||||
inline value_type* EndPtr() EA_NOEXCEPT { return IsHeap() ? HeapEndPtr() : SSOEndPtr(); }
|
||||
inline const value_type* EndPtr() const EA_NOEXCEPT { return IsHeap() ? HeapEndPtr() : SSOEndPtr(); }
|
||||
|
||||
inline value_type* HeapCapacityPtr() EA_NOEXCEPT { return heap.mpBegin + GetHeapCapacity(); }
|
||||
@@ -447,7 +438,7 @@ namespace eastl
|
||||
inline const value_type* SSOCapcityPtr() const EA_NOEXCEPT { return sso.mData + SSOLayout::SSO_CAPACITY; }
|
||||
|
||||
// Points to end of the buffer at the terminating '0', *ptr == '0' <- not true for SSO
|
||||
inline value_type* CapacityPtr() EA_NOEXCEPT { return IsHeap() ? HeapCapacityPtr() : SSOCapcityPtr(); }
|
||||
inline value_type* CapacityPtr() EA_NOEXCEPT { return IsHeap() ? HeapCapacityPtr() : SSOCapcityPtr(); }
|
||||
inline const value_type* CapacityPtr() const EA_NOEXCEPT { return IsHeap() ? HeapCapacityPtr() : SSOCapcityPtr(); }
|
||||
|
||||
inline void SetHeapBeginPtr(value_type* pBegin) EA_NOEXCEPT { heap.mpBegin = pBegin; }
|
||||
@@ -486,7 +477,7 @@ namespace eastl
|
||||
|
||||
public:
|
||||
// Constructor, destructor
|
||||
basic_string() EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(allocator_type()));
|
||||
basic_string() EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(EASTL_BASIC_STRING_DEFAULT_ALLOCATOR));
|
||||
explicit basic_string(const allocator_type& allocator) EA_NOEXCEPT;
|
||||
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);
|
||||
@@ -502,6 +493,19 @@ namespace eastl
|
||||
basic_string(this_type&& x) EA_NOEXCEPT;
|
||||
basic_string(this_type&& x, const allocator_type& allocator);
|
||||
|
||||
explicit basic_string(const view_type& sv, const allocator_type& alloc = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR)
|
||||
: basic_string(sv.data(), sv.size(), alloc)
|
||||
{
|
||||
}
|
||||
|
||||
basic_string(const view_type& sv,
|
||||
size_type pos,
|
||||
size_type n,
|
||||
const allocator_type& alloc = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR)
|
||||
: basic_string(sv.substr(pos, n), n, alloc)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename OtherCharType>
|
||||
basic_string(CtorConvert, const OtherCharType* p, const allocator_type& allocator = EASTL_BASIC_STRING_DEFAULT_ALLOCATOR);
|
||||
|
||||
@@ -518,14 +522,15 @@ namespace eastl
|
||||
allocator_type& get_allocator() EA_NOEXCEPT;
|
||||
void set_allocator(const allocator_type& allocator);
|
||||
|
||||
// implicit conversion operator
|
||||
// Implicit conversion operator
|
||||
operator basic_string_view<T>() const EA_NOEXCEPT;
|
||||
|
||||
// Operator =
|
||||
// Operator=
|
||||
this_type& operator=(const this_type& x);
|
||||
this_type& operator=(const value_type* p);
|
||||
this_type& operator=(value_type c);
|
||||
this_type& operator=(std::initializer_list<value_type> ilist);
|
||||
this_type& operator=(view_type v);
|
||||
this_type& operator=(this_type&& x); // TODO(c++17): noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || allocator_traits<Allocator>::is_always_equal::value);
|
||||
|
||||
#if EASTL_OPERATOR_EQUALS_OTHER_ENABLED
|
||||
@@ -747,8 +752,7 @@ namespace eastl
|
||||
void RangeInitialize(const value_type* pBegin);
|
||||
void SizeInitialize(size_type n, value_type c);
|
||||
|
||||
// SSO related functions
|
||||
bool IsSSO() const EA_NOEXCEPT;
|
||||
bool IsSSO() const EA_NOEXCEPT;
|
||||
|
||||
void ThrowLengthException() const;
|
||||
void ThrowRangeException() const;
|
||||
@@ -783,7 +787,7 @@ namespace eastl
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
inline basic_string<T, Allocator>::basic_string() EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(allocator_type()))
|
||||
inline basic_string<T, Allocator>::basic_string() EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(EASTL_BASIC_STRING_DEFAULT_ALLOCATOR))
|
||||
: mPair(allocator_type(EASTL_BASIC_STRING_DEFAULT_NAME))
|
||||
{
|
||||
AllocateSelf();
|
||||
@@ -939,7 +943,6 @@ namespace eastl
|
||||
: mPair(x.get_allocator())
|
||||
{
|
||||
internalLayout() = eastl::move(x.internalLayout());
|
||||
|
||||
x.AllocateSelf();
|
||||
}
|
||||
|
||||
@@ -1282,6 +1285,13 @@ namespace eastl
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
inline typename basic_string<T, Allocator>::this_type& basic_string<T, Allocator>::operator=(view_type v)
|
||||
{
|
||||
return assign(v.data(), static_cast<this_type::size_type>(v.size()));
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
void basic_string<T, Allocator>::resize(size_type n, value_type c)
|
||||
{
|
||||
@@ -1729,7 +1739,54 @@ namespace eastl
|
||||
// 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.
|
||||
|
||||
// https://www.freebsd.org/cgi/man.cgi?query=vswprintf&sektion=3&manpath=freebsd-release-ports
|
||||
// https://www.freebsd.org/cgi/man.cgi?query=snprintf&manpath=SuSE+Linux/i386+11.3
|
||||
// Well its time to go on an adventure...
|
||||
// C99 vsnprintf states that a buffer size of zero returns the number of characters that would
|
||||
// be written to the buffer irrelevant of whether the buffer is a nullptr
|
||||
// But C99 vswprintf for wchar_t changes the behaviour of the return to instead say that it
|
||||
// "will fail if n or more wide characters were requested to be written", so
|
||||
// calling vswprintf with a buffer size of zero always returns -1
|
||||
// unless... you are MSVC where they deviate from the std and say if the buffer is NULL
|
||||
// and the size is zero it will return the number of characters written or if we are using
|
||||
// EAStdC which also does the sane behaviour.
|
||||
|
||||
#if !EASTL_OPENSOURCE || defined(EA_PLATFORM_MICROSOFT)
|
||||
size_type nInitialSize = internalLayout().GetSize();
|
||||
int nReturnValue;
|
||||
|
||||
#if EASTL_VA_COPY_ENABLED
|
||||
va_list argumentsSaved;
|
||||
va_copy(argumentsSaved, arguments);
|
||||
#endif
|
||||
|
||||
nReturnValue = eastl::Vsnprintf(nullptr, 0, pFormat, arguments);
|
||||
|
||||
if (nReturnValue > 0)
|
||||
{
|
||||
resize(nReturnValue + nInitialSize);
|
||||
|
||||
#if EASTL_VA_COPY_ENABLED
|
||||
va_end(arguments);
|
||||
va_copy(arguments, argumentsSaved);
|
||||
#endif
|
||||
|
||||
nReturnValue = eastl::Vsnprintf(internalLayout().BeginPtr() + nInitialSize, (size_t)(nReturnValue + 1),
|
||||
pFormat, arguments);
|
||||
}
|
||||
|
||||
if (nReturnValue >= 0)
|
||||
internalLayout().SetSize(nInitialSize + nReturnValue);
|
||||
|
||||
#if EASTL_VA_COPY_ENABLED
|
||||
// va_end for arguments will be called by the caller.
|
||||
va_end(argumentsSaved);
|
||||
#endif
|
||||
|
||||
#else
|
||||
size_type nInitialSize = internalLayout().GetSize();
|
||||
size_type nInitialRemainingCapacity = internalLayout().GetRemainingCapacity();
|
||||
int nReturnValue;
|
||||
|
||||
#if EASTL_VA_COPY_ENABLED
|
||||
@@ -1737,40 +1794,40 @@ namespace eastl
|
||||
va_copy(argumentsSaved, arguments);
|
||||
#endif
|
||||
|
||||
nReturnValue = eastl::Vsnprintf(internalLayout().EndPtr(), (size_t)internalLayout().GetRemainingCapacity() + 1, pFormat, arguments);
|
||||
nReturnValue = eastl::Vsnprintf(internalLayout().EndPtr(), (size_t)nInitialRemainingCapacity + 1,
|
||||
pFormat, arguments);
|
||||
|
||||
if(nReturnValue > (int)internalLayout().GetRemainingCapacity()) // If there wasn't enough capacity...
|
||||
if(nReturnValue >= (int)(nInitialRemainingCapacity + 1)) // 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(internalLayout().BeginPtr() + nInitialSize, (size_t)(nReturnValue + 1),
|
||||
pFormat, arguments);
|
||||
}
|
||||
else if(nReturnValue < 0) // If vsnprintf is non-C99-standard
|
||||
{
|
||||
// In this case we either have C89 extension behaviour or C99 behaviour.
|
||||
size_type n = eastl::max_alt((size_type)(SSOLayout::SSO_CAPACITY - 1), (size_type)(nInitialSize * 2));
|
||||
|
||||
for(; (nReturnValue < 0) && (n < 1000000); n *= 2)
|
||||
{
|
||||
#if EASTL_VA_COPY_ENABLED
|
||||
va_end(arguments);
|
||||
va_copy(arguments, argumentsSaved);
|
||||
#endif
|
||||
// We must reset the size back to where we were incase we overrun the SSO buffer and '0' gets written into sso.mnSize. Then our size would have changed, which will affect .EndPtr() calcs
|
||||
internalLayout().SetSize(nInitialSize);
|
||||
reserve(nInitialSize + nReturnValue);
|
||||
nReturnValue = eastl::Vsnprintf(internalLayout().EndPtr(), (size_t)internalLayout().GetRemainingCapacity() + 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(internalLayout().BeginPtr() + nInitialSize, nCapacity, pFormat, arguments); // '+1' because vsnprintf wants to know the size of the buffer including the terminating zero.
|
||||
const size_t nCapacity = (size_t)(n - nInitialSize);
|
||||
nReturnValue = eastl::Vsnprintf(internalLayout().BeginPtr() + nInitialSize, nCapacity + 1, pFormat, arguments);
|
||||
|
||||
if(nReturnValue == (int)(unsigned)nCapacity)
|
||||
{
|
||||
resize(++n);
|
||||
nReturnValue = eastl::Vsnprintf(internalLayout().BeginPtr() + nInitialSize, nCapacity + 1, pFormat, arguments);
|
||||
nReturnValue = eastl::Vsnprintf(internalLayout().BeginPtr() + nInitialSize, nCapacity + 2, pFormat, arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1783,6 +1840,8 @@ namespace eastl
|
||||
va_end(argumentsSaved);
|
||||
#endif
|
||||
|
||||
#endif // EASTL_OPENSOURCE
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -2153,7 +2212,7 @@ namespace eastl
|
||||
// guarantee 0 or 1 allocation depending if we need to realloc
|
||||
// We don't do this for Heap strings as then this path may do 1 or 2 allocations instead of
|
||||
// only 1 allocation when we fall through to the last else case below
|
||||
const this_type stackTemp(pBegin, pEnd, allocator_type());
|
||||
const this_type stackTemp(pBegin, pEnd, get_allocator());
|
||||
return insert(p, stackTemp.data(), stackTemp.data() + stackTemp.size());
|
||||
}
|
||||
|
||||
@@ -2877,10 +2936,10 @@ namespace eastl
|
||||
#endif
|
||||
|
||||
// C++ std says the return string allocator must be default constructed, not a copy of this->get_allocator()
|
||||
return basic_string(
|
||||
internalLayout().BeginPtr() + position,
|
||||
internalLayout().BeginPtr() + position +
|
||||
eastl::min_alt(n, internalLayout().GetSize() - position), allocator_type());
|
||||
return basic_string(
|
||||
internalLayout().BeginPtr() + position,
|
||||
internalLayout().BeginPtr() + position +
|
||||
eastl::min_alt(n, internalLayout().GetSize() - position), get_allocator());
|
||||
}
|
||||
|
||||
|
||||
@@ -3010,8 +3069,9 @@ namespace eastl
|
||||
const size_type nLength = length();
|
||||
if(n < nLength)
|
||||
return substr(0, n);
|
||||
// C++ std says that substr must return default constructed allocated, so do the same here
|
||||
return basic_string(*this, allocator_type());
|
||||
// C++ std says that substr must return default constructed allocated, but we do not.
|
||||
// Instead it is much more practical to provide the copy of the current allocator
|
||||
return basic_string(*this, get_allocator());
|
||||
}
|
||||
|
||||
|
||||
@@ -3021,8 +3081,9 @@ namespace eastl
|
||||
const size_type nLength = length();
|
||||
if(n < nLength)
|
||||
return substr(nLength - n, n);
|
||||
// C++ std says that substr must return default constructed allocated, so do the same here
|
||||
return basic_string(*this, allocator_type());
|
||||
// C++ std says that substr must return default constructed allocated, but we do not.
|
||||
// Instead it is much more practical to provide the copy of the current allocator
|
||||
return basic_string(*this, get_allocator());
|
||||
}
|
||||
|
||||
|
||||
@@ -3187,7 +3248,7 @@ namespace eastl
|
||||
inline typename basic_string<T, Allocator>::size_type
|
||||
basic_string<T, Allocator>::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;
|
||||
return (currentCapacity <= SSOLayout::SSO_CAPACITY) ? SSOLayout::SSO_CAPACITY : (2 * currentCapacity);
|
||||
}
|
||||
|
||||
|
||||
@@ -3570,14 +3631,14 @@ namespace eastl
|
||||
basic_string<T, Allocator> operator+(basic_string<T, Allocator>&& a, basic_string<T, Allocator>&& b)
|
||||
{
|
||||
a.append(b); // Using an rvalue by name results in it becoming an lvalue.
|
||||
return a;
|
||||
return eastl::move(a);
|
||||
}
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
basic_string<T, Allocator> operator+(basic_string<T, Allocator>&& a, const basic_string<T, Allocator>& b)
|
||||
{
|
||||
a.append(b);
|
||||
return a;
|
||||
return eastl::move(a);
|
||||
}
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
@@ -3591,14 +3652,14 @@ namespace eastl
|
||||
basic_string<T, Allocator> operator+(basic_string<T, Allocator>&& a, const typename basic_string<T, Allocator>::value_type* p)
|
||||
{
|
||||
a.append(p);
|
||||
return a;
|
||||
return eastl::move(a);
|
||||
}
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
basic_string<T, Allocator> operator+(basic_string<T, Allocator>&& a, typename basic_string<T, Allocator>::value_type c)
|
||||
{
|
||||
a.push_back(c);
|
||||
return a;
|
||||
return eastl::move(a);
|
||||
}
|
||||
|
||||
|
||||
@@ -3936,7 +3997,7 @@ namespace eastl
|
||||
inline wstring operator"" s(const wchar_t* str, size_t len) EA_NOEXCEPT { return {str, wstring::size_type(len)}; }
|
||||
}
|
||||
}
|
||||
EA_RESTORE_VC_WARNING() // warning: 4455
|
||||
EA_RESTORE_VC_WARNING() // warning: 4455
|
||||
#endif
|
||||
|
||||
} // namespace eastl
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
#ifndef EASTL_STRING_VIEW_H
|
||||
#define EASTL_STRING_VIEW_H
|
||||
|
||||
EA_ONCE()
|
||||
#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
|
||||
|
||||
#include <EASTL/internal/config.h>
|
||||
#include <EASTL/internal/char_traits.h>
|
||||
@@ -404,6 +406,38 @@ namespace eastl
|
||||
{
|
||||
return find_last_not_of(s, pos, (size_type)CharStrlen(s));
|
||||
}
|
||||
|
||||
// starts_with
|
||||
EA_CONSTEXPR bool starts_with(basic_string_view x) const EA_NOEXCEPT
|
||||
{
|
||||
return (size() >= x.size()) && (compare(0, x.size(), x) == 0);
|
||||
}
|
||||
|
||||
EA_CONSTEXPR bool starts_with(T x) const EA_NOEXCEPT
|
||||
{
|
||||
return starts_with(basic_string_view(&x, 1));
|
||||
}
|
||||
|
||||
EA_CONSTEXPR bool starts_with(const T* s) const
|
||||
{
|
||||
return starts_with(basic_string_view(s));
|
||||
}
|
||||
|
||||
// ends_with
|
||||
EA_CONSTEXPR bool ends_with(basic_string_view x) const EA_NOEXCEPT
|
||||
{
|
||||
return (size() >= x.size()) && (compare(size() - x.size(), npos, x) == 0);
|
||||
}
|
||||
|
||||
EA_CONSTEXPR bool ends_with(T x) const EA_NOEXCEPT
|
||||
{
|
||||
return ends_with(basic_string_view(&x, 1));
|
||||
}
|
||||
|
||||
EA_CONSTEXPR bool ends_with(const T* s) const
|
||||
{
|
||||
return ends_with(basic_string_view(s));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -564,7 +564,7 @@ template <>
|
||||
struct TupleEqual<0>
|
||||
{
|
||||
template <typename Tuple1, typename Tuple2>
|
||||
bool operator()(const Tuple1& t1, const Tuple2& t2)
|
||||
bool operator()(const Tuple1&, const Tuple2&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -587,7 +587,7 @@ template <>
|
||||
struct TupleLess<0>
|
||||
{
|
||||
template <typename Tuple1, typename Tuple2>
|
||||
bool operator()(const Tuple1& t1, const Tuple2& t2)
|
||||
bool operator()(const Tuple1&, const Tuple2&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -621,6 +621,10 @@ namespace eastl
|
||||
template <typename T> struct is_const : public eastl::is_const_value<T*>{};
|
||||
template <typename T> struct is_const<T&> : public eastl::false_type{}; // Note here that T is const, not the reference to T. So is_const is false. See section 8.3.2p1 of the C++ standard.
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template <class T>
|
||||
EA_CONSTEXPR bool is_const_v = is_const<T>::value;
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
@@ -787,6 +791,10 @@ namespace eastl
|
||||
template <typename T> struct remove_const<const T[]> { typedef T type[]; };
|
||||
template <typename T, size_t N> struct remove_const<const T[N]> { typedef T type[N]; };
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template<typename T>
|
||||
using remove_const_t = typename remove_const<T>::type;
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// remove_volatile
|
||||
@@ -810,6 +818,11 @@ namespace eastl
|
||||
template <typename T> struct remove_volatile<volatile T[]> { typedef T type[]; };
|
||||
template <typename T, size_t N> struct remove_volatile<volatile T[N]> { typedef T type[N]; };
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template<typename T>
|
||||
using remove_volatile_t = typename remove_volatile<T>::type;
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// remove_cv
|
||||
|
||||
@@ -132,66 +132,56 @@ namespace eastl
|
||||
unique_ptr(pointer pValue, typename eastl::conditional<eastl::is_reference<deleter_type>::value, deleter_type, typename eastl::add_lvalue_reference<const deleter_type>::type>::type deleter) EA_NOEXCEPT
|
||||
: mPair(pValue, deleter) {}
|
||||
|
||||
#if EASTL_MOVE_SEMANTICS_ENABLED
|
||||
/// unique_ptr
|
||||
/// Constructs a unique_ptr with the owned pointer and deleter specified (rvalue)
|
||||
/// Example usage:
|
||||
/// unique_ptr<int> ptr(new int(3), eastl::smart_ptr_deleter<int>());
|
||||
unique_ptr(pointer pValue, typename eastl::remove_reference<deleter_type>::type&& deleter) EA_NOEXCEPT
|
||||
: mPair(pValue, eastl::move(deleter))
|
||||
{
|
||||
static_assert(!eastl::is_reference<deleter_type>::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter.");
|
||||
}
|
||||
/// unique_ptr
|
||||
/// Constructs a unique_ptr with the owned pointer and deleter specified (rvalue)
|
||||
/// Example usage:
|
||||
/// unique_ptr<int> ptr(new int(3), eastl::smart_ptr_deleter<int>());
|
||||
unique_ptr(pointer pValue, typename eastl::remove_reference<deleter_type>::type&& deleter) EA_NOEXCEPT
|
||||
: mPair(pValue, eastl::move(deleter))
|
||||
{
|
||||
static_assert(!eastl::is_reference<deleter_type>::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter.");
|
||||
}
|
||||
|
||||
/// unique_ptr
|
||||
/// Move constructor
|
||||
/// Example usage:
|
||||
/// unique_ptr<int> ptr(new int(3));
|
||||
/// unique_ptr<int> newPtr = eastl::move(ptr);
|
||||
unique_ptr(this_type&& x) EA_NOEXCEPT
|
||||
: mPair(x.release(), eastl::forward<deleter_type>(x.get_deleter())) {}
|
||||
/// unique_ptr
|
||||
/// Move constructor
|
||||
/// Example usage:
|
||||
/// unique_ptr<int> ptr(new int(3));
|
||||
/// unique_ptr<int> newPtr = eastl::move(ptr);
|
||||
unique_ptr(this_type&& x) EA_NOEXCEPT
|
||||
: mPair(x.release(), eastl::forward<deleter_type>(x.get_deleter())) {}
|
||||
|
||||
/// unique_ptr
|
||||
/// Move constructor
|
||||
/// Example usage:
|
||||
/// unique_ptr<int> ptr(new int(3));
|
||||
/// unique_ptr<int> newPtr = eastl::move(ptr);
|
||||
template <typename U, typename E>
|
||||
unique_ptr(unique_ptr<U, E>&& u, typename enable_if<!is_array<U>::value && is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value && is_convertible<E, deleter_type>::value && (is_same<deleter_type, E>::value || !is_reference<deleter_type>::value)>::type* = 0) EA_NOEXCEPT
|
||||
: mPair(u.release(), eastl::forward<E>(u.get_deleter())) {}
|
||||
/// unique_ptr
|
||||
/// Move constructor
|
||||
/// Example usage:
|
||||
/// unique_ptr<int> ptr(new int(3));
|
||||
/// unique_ptr<int> newPtr = eastl::move(ptr);
|
||||
template <typename U, typename E>
|
||||
unique_ptr(unique_ptr<U, E>&& u, typename enable_if<!is_array<U>::value && is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value && is_convertible<E, deleter_type>::value && (is_same<deleter_type, E>::value || !is_reference<deleter_type>::value)>::type* = 0) EA_NOEXCEPT
|
||||
: mPair(u.release(), eastl::forward<E>(u.get_deleter())) {}
|
||||
|
||||
/// unique_ptr
|
||||
/// Move assignment
|
||||
/// Example usage:
|
||||
/// unique_ptr<int> ptr(new int(3));
|
||||
/// unique_ptr<int> newPtr(new int(4));
|
||||
/// ptr = eastl::move(newPtr); // Deletes int(3) and assigns mpValue to int(4)
|
||||
this_type& operator=(this_type&& x) EA_NOEXCEPT
|
||||
{
|
||||
reset(x.release());
|
||||
mPair.second() = eastl::move(eastl::forward<deleter_type>(x.get_deleter()));
|
||||
return *this;
|
||||
}
|
||||
/// unique_ptr
|
||||
/// Move assignment
|
||||
/// Example usage:
|
||||
/// unique_ptr<int> ptr(new int(3));
|
||||
/// unique_ptr<int> newPtr(new int(4));
|
||||
/// ptr = eastl::move(newPtr); // Deletes int(3) and assigns mpValue to int(4)
|
||||
this_type& operator=(this_type&& x) EA_NOEXCEPT
|
||||
{
|
||||
reset(x.release());
|
||||
mPair.second() = eastl::move(eastl::forward<deleter_type>(x.get_deleter()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// unique_ptr
|
||||
/// Move assignment
|
||||
template <typename U, typename E>
|
||||
typename enable_if<!is_array<U>::value && is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value && is_assignable<deleter_type&, E&&>::value, this_type&>::type
|
||||
operator=(unique_ptr<U, E>&& u) EA_NOEXCEPT
|
||||
{
|
||||
reset(u.release());
|
||||
mPair.second() = eastl::move(eastl::forward<E>(u.get_deleter()));
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
template <typename U, typename E>
|
||||
this_type& operator=(unique_ptr<U, E> u) EA_NOEXCEPT // Pass by value.
|
||||
{
|
||||
reset(u.release());
|
||||
mPair.second() = eastl::forward<deleter_type>(u.get_deleter());
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
/// unique_ptr
|
||||
/// Move assignment
|
||||
template <typename U, typename E>
|
||||
typename enable_if<!is_array<U>::value && is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value && is_assignable<deleter_type&, E&&>::value, this_type&>::type
|
||||
operator=(unique_ptr<U, E>&& u) EA_NOEXCEPT
|
||||
{
|
||||
reset(u.release());
|
||||
mPair.second() = eastl::move(eastl::forward<E>(u.get_deleter()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// operator=(nullptr_t)
|
||||
this_type& operator=(std::nullptr_t) EA_NOEXCEPT
|
||||
@@ -336,9 +326,9 @@ namespace eastl
|
||||
eastl::compressed_pair<pointer, deleter_type> mPair;
|
||||
|
||||
/// These functions are private in order to prevent copying, for safety.
|
||||
unique_ptr(const this_type&);
|
||||
unique_ptr& operator=(const this_type&);
|
||||
unique_ptr& operator=(pointer pValue);
|
||||
unique_ptr(const this_type&) = delete;
|
||||
unique_ptr& operator=(const this_type&) = delete;
|
||||
unique_ptr& operator=(pointer pValue) = delete;
|
||||
|
||||
}; // class unique_ptr
|
||||
|
||||
@@ -395,47 +385,37 @@ namespace eastl
|
||||
typename eastl::enable_if<Internal::is_array_cv_convertible<P, pointer>::value>::type* = 0) EA_NOEXCEPT
|
||||
: mPair(pArray, deleter) {}
|
||||
|
||||
#if EASTL_MOVE_SEMANTICS_ENABLED
|
||||
template <typename P>
|
||||
unique_ptr(P pArray, typename eastl::remove_reference<deleter_type>::type&& deleter, typename eastl::enable_if<Internal::is_array_cv_convertible<P, pointer>::value>::type* = 0) EA_NOEXCEPT
|
||||
: mPair(pArray, eastl::move(deleter))
|
||||
{
|
||||
static_assert(!eastl::is_reference<deleter_type>::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter.");
|
||||
}
|
||||
template <typename P>
|
||||
unique_ptr(P pArray, typename eastl::remove_reference<deleter_type>::type&& deleter, typename eastl::enable_if<Internal::is_array_cv_convertible<P, pointer>::value>::type* = 0) EA_NOEXCEPT
|
||||
: mPair(pArray, eastl::move(deleter))
|
||||
{
|
||||
static_assert(!eastl::is_reference<deleter_type>::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter.");
|
||||
}
|
||||
|
||||
unique_ptr(this_type&& x) EA_NOEXCEPT
|
||||
: mPair(x.release(), eastl::forward<deleter_type>(x.get_deleter())) {}
|
||||
unique_ptr(this_type&& x) EA_NOEXCEPT
|
||||
: mPair(x.release(), eastl::forward<deleter_type>(x.get_deleter())) {}
|
||||
|
||||
template <typename U, typename E>
|
||||
unique_ptr(unique_ptr<U, E>&& u, typename enable_if<Internal::is_safe_array_conversion<T, pointer, U, typename unique_ptr<U, E>::pointer>::value &&
|
||||
eastl::is_convertible<E, deleter_type>::value &&
|
||||
(!eastl::is_reference<deleter_type>::value || eastl::is_same<E, deleter_type>::value)>::type* = 0) EA_NOEXCEPT
|
||||
: mPair(u.release(), eastl::forward<E>(u.get_deleter())) {}
|
||||
template <typename U, typename E>
|
||||
unique_ptr(unique_ptr<U, E>&& u, typename enable_if<Internal::is_safe_array_conversion<T, pointer, U, typename unique_ptr<U, E>::pointer>::value &&
|
||||
eastl::is_convertible<E, deleter_type>::value &&
|
||||
(!eastl::is_reference<deleter_type>::value || eastl::is_same<E, deleter_type>::value)>::type* = 0) EA_NOEXCEPT
|
||||
: mPair(u.release(), eastl::forward<E>(u.get_deleter())) {}
|
||||
|
||||
this_type& operator=(this_type&& x) EA_NOEXCEPT
|
||||
{
|
||||
reset(x.release());
|
||||
mPair.second() = eastl::move(eastl::forward<deleter_type>(x.get_deleter()));
|
||||
return *this;
|
||||
}
|
||||
this_type& operator=(this_type&& x) EA_NOEXCEPT
|
||||
{
|
||||
reset(x.release());
|
||||
mPair.second() = eastl::move(eastl::forward<deleter_type>(x.get_deleter()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U, typename E>
|
||||
typename enable_if<Internal::is_safe_array_conversion<T, pointer, U, typename unique_ptr<U, E>::pointer>::value && is_assignable<deleter_type&, E&&>::value, this_type&>::type
|
||||
operator=(unique_ptr<U, E>&& u) EA_NOEXCEPT
|
||||
{
|
||||
reset(u.release());
|
||||
mPair.second() = eastl::move(eastl::forward<E>(u.get_deleter()));
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
template <typename U, typename E>
|
||||
this_type& operator=(unique_ptr<U, E> u) EA_NOEXCEPT // Pass by value.
|
||||
{
|
||||
reset(u.release());
|
||||
mPair.second() = eastl::forward<deleter_type>(u.get_deleter());
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
template <typename U, typename E>
|
||||
typename enable_if<Internal::is_safe_array_conversion<T, pointer, U, typename unique_ptr<U, E>::pointer>::value && is_assignable<deleter_type&, E&&>::value, this_type&>::type
|
||||
operator=(unique_ptr<U, E>&& u) EA_NOEXCEPT
|
||||
{
|
||||
reset(u.release());
|
||||
mPair.second() = eastl::move(eastl::forward<E>(u.get_deleter()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
this_type& operator=(std::nullptr_t) EA_NOEXCEPT
|
||||
{
|
||||
@@ -567,68 +547,22 @@ namespace eastl
|
||||
{ typedef void unique_type_bounded_array; };
|
||||
}
|
||||
|
||||
#if EASTL_MOVE_SEMANTICS_ENABLED
|
||||
#if EASTL_VARIADIC_TEMPLATES_ENABLED
|
||||
template <typename T, typename... Args>
|
||||
inline typename Internal::unique_type<T>::unique_type_single make_unique(Args&&... args)
|
||||
{ return unique_ptr<T>(new T(eastl::forward<Args>(args)...)); }
|
||||
template <typename T, typename... Args>
|
||||
inline typename Internal::unique_type<T>::unique_type_single make_unique(Args&&... args)
|
||||
{ return unique_ptr<T>(new T(eastl::forward<Args>(args)...)); }
|
||||
|
||||
template <typename T>
|
||||
inline typename Internal::unique_type<T>::unique_type_unbounded_array make_unique(size_t n)
|
||||
{
|
||||
typedef typename eastl::remove_extent<T>::type TBase;
|
||||
return unique_ptr<T>(new TBase[n]);
|
||||
}
|
||||
template <typename T>
|
||||
inline typename Internal::unique_type<T>::unique_type_unbounded_array make_unique(size_t n)
|
||||
{
|
||||
typedef typename eastl::remove_extent<T>::type TBase;
|
||||
return unique_ptr<T>(new TBase[n]);
|
||||
}
|
||||
|
||||
// It's not possible to create a unique_ptr for arrays of a known bound (e.g. int[4] as opposed to int[]).
|
||||
#if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS)
|
||||
template <typename T, typename... Args>
|
||||
typename Internal::unique_type<T>::unique_type_bounded_array
|
||||
make_unique(Args&&...) = delete;
|
||||
#endif
|
||||
// It's not possible to create a unique_ptr for arrays of a known bound (e.g. int[4] as opposed to int[]).
|
||||
template <typename T, typename... Args>
|
||||
typename Internal::unique_type<T>::unique_type_bounded_array
|
||||
make_unique(Args&&...) = delete;
|
||||
|
||||
#else
|
||||
|
||||
// Reduced version that is more limited than the varargs version.
|
||||
template <typename T>
|
||||
inline typename Internal::unique_type<T>::unique_type_single make_unique()
|
||||
{ return unique_ptr<T>(new T); }
|
||||
|
||||
template <typename T, typename A1>
|
||||
inline typename Internal::unique_type<T>::unique_type_single make_unique(A1&& a1)
|
||||
{ return unique_ptr<T>(new T(eastl::forward<A1>(a1))); }
|
||||
|
||||
template <typename T, typename A1, typename A2>
|
||||
inline typename Internal::unique_type<T>::unique_type_single make_unique(A1&& a1, A2&& a2)
|
||||
{ return unique_ptr<T>(new T(eastl::forward<A1>(a1), eastl::forward<A2>(a2))); }
|
||||
|
||||
template <typename T, typename A1, typename A2, typename A3>
|
||||
inline typename Internal::unique_type<T>::unique_type_single make_unique(A1&& a1, A2&& a2, A3&& a3)
|
||||
{ return unique_ptr<T>(new T(eastl::forward<A1>(a1), eastl::forward<A2>(a2), eastl::forward<A3>(a3))); }
|
||||
|
||||
template <typename T, typename A1, typename A2, typename A3, typename A4>
|
||||
inline typename Internal::unique_type<T>::unique_type_single make_unique(A1&& a1, A2&& a2, A3&& a3, A4&& a4)
|
||||
{ return unique_ptr<T>(new T(eastl::forward<A1>(a1), eastl::forward<A2>(a2), eastl::forward<A3>(a3), eastl::forward<A4>(a4))); }
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline typename Internal::unique_type<T>::unique_type_unbounded_array make_unique(size_t n)
|
||||
{
|
||||
typedef typename eastl::remove_extent<T>::type TBase;
|
||||
return unique_ptr<T>(new TBase[n]);
|
||||
}
|
||||
|
||||
// It's not possible to create a unique_ptr for arrays of a known bound (e.g. int[4] as opposed to int[]).
|
||||
#if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS)
|
||||
template <typename T>
|
||||
typename Internal::unique_type<T>::unique_type_bounded_array
|
||||
make_unique() = delete;
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
// It's not possible to implement make_unique because unique_ptr can be constructed
|
||||
// only via a raw pointer or via an rvalue move from another unique_ptr.
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#include <EASTL/internal/config.h>
|
||||
#include <EASTL/hash_map.h>
|
||||
|
||||
EA_ONCE()
|
||||
#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
|
||||
{
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#include <EASTL/internal/config.h>
|
||||
#include <EASTL/hash_set.h>
|
||||
|
||||
EA_ONCE()
|
||||
#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
|
||||
{
|
||||
|
||||
@@ -385,11 +385,6 @@ namespace eastl
|
||||
{
|
||||
}
|
||||
|
||||
// GCC has a bug with overloading rvalue and lvalue function templates.
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54425
|
||||
//
|
||||
// error: 'eastl::pair<T1, T2>::pair(T1&&) [with T1 = const int&; T2 = const int&]' cannot be overloaded
|
||||
// error: with 'eastl::pair<T1, T2>::pair(const T1&) [with T1 = const int&; T2 = const int&]'
|
||||
#if !defined(EA_COMPILER_GNUC)
|
||||
// To consider: Use type traits to enable this ctor only if T2 (second is_default_constructible<T2>::value == true.)
|
||||
EA_CPP14_CONSTEXPR pair(T1&& x)
|
||||
|
||||
@@ -59,14 +59,16 @@
|
||||
#include <EASTL/internal/config.h>
|
||||
#include <EASTL/internal/type_pod.h>
|
||||
#include <EASTL/internal/in_place_t.h>
|
||||
#include <EASTL/internal/meta.h>
|
||||
#include <EASTL/internal/integer_sequence.h>
|
||||
#include <EASTL/meta.h>
|
||||
#include <EASTL/utility.h>
|
||||
#include <EASTL/functional.h>
|
||||
#include <EASTL/initializer_list.h>
|
||||
#include <EASTL/tuple.h>
|
||||
|
||||
EA_ONCE()
|
||||
#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
|
||||
|
||||
#ifndef EA_COMPILER_CPP14_ENABLED
|
||||
static_assert(false, "eastl::variant requires a C++14 compatible compiler (at least) ");
|
||||
@@ -76,6 +78,30 @@ EA_DISABLE_VC_WARNING(4625) // copy constructor was implicitly defined as delete
|
||||
|
||||
namespace eastl
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// default_construct_util<T>::default_construct
|
||||
//
|
||||
// Utility class to remove default constructor calls for types that
|
||||
// do not support default construction.
|
||||
//
|
||||
template<typename T, bool = eastl::is_default_constructible_v<T>>
|
||||
struct default_construct_if_supported
|
||||
{
|
||||
static void call(T* pThis)
|
||||
{
|
||||
new (pThis) T();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct default_construct_if_supported<T, false>
|
||||
{
|
||||
static void call(T* pThis)
|
||||
{
|
||||
// intentionally blank
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 20.7.3, variant_npos
|
||||
@@ -156,6 +182,7 @@ namespace eastl
|
||||
{
|
||||
enum class StorageOp
|
||||
{
|
||||
DEFAULT_CONSTRUCT,
|
||||
DESTROY,
|
||||
COPY,
|
||||
MOVE
|
||||
@@ -171,7 +198,7 @@ namespace eastl
|
||||
template<typename VariantStorageT>
|
||||
inline void DoOp(StorageOp op, VariantStorageT&& other) // bind to both rvalue and lvalues
|
||||
{
|
||||
if (!mpHandler && other.mpHandler)
|
||||
if (other.mpHandler)
|
||||
mpHandler = other.mpHandler;
|
||||
|
||||
if(mpHandler)
|
||||
@@ -189,6 +216,12 @@ namespace eastl
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case StorageOp::DEFAULT_CONSTRUCT:
|
||||
{
|
||||
default_construct_if_supported<T>::call(pThis);
|
||||
}
|
||||
break;
|
||||
|
||||
case StorageOp::DESTROY:
|
||||
{
|
||||
pThis->~T();
|
||||
@@ -212,7 +245,10 @@ namespace eastl
|
||||
}
|
||||
|
||||
public:
|
||||
variant_storage() = default;
|
||||
variant_storage()
|
||||
{
|
||||
DoOp(StorageOp::DEFAULT_CONSTRUCT);
|
||||
}
|
||||
|
||||
~variant_storage()
|
||||
{
|
||||
@@ -426,7 +462,7 @@ namespace eastl
|
||||
static_assert(I < sizeof...(Types), "get_if is ill-formed if I is not a valid index in the variant typelist");
|
||||
using return_type = add_pointer_t<variant_alternative_t<I, variant<Types...>>>;
|
||||
|
||||
return (!pv && pv->index() == I) ? nullptr : pv->mStorage.template get_as<return_type>();
|
||||
return (!pv || pv->index() != I) ? nullptr : pv->mStorage.template get_as<return_type>();
|
||||
}
|
||||
|
||||
template <size_t I, class... Types>
|
||||
@@ -435,7 +471,7 @@ namespace eastl
|
||||
static_assert(I < sizeof...(Types), "get_if is ill-formed if I is not a valid index in the variant typelist");
|
||||
using return_type = add_pointer_t<variant_alternative_t<I, variant<Types...>>>;
|
||||
|
||||
return (!pv && pv->index() == I) ? nullptr : pv->mStorage.template get_as<return_type>();
|
||||
return (!pv || pv->index() != I) ? nullptr : pv->mStorage.template get_as<return_type>();
|
||||
}
|
||||
|
||||
template <class T, class... Types, size_t I = meta::get_type_index_v<T, Types...>>
|
||||
@@ -561,9 +597,11 @@ namespace eastl
|
||||
//
|
||||
|
||||
// Only participates in overload resolution when the first alternative is default constructible
|
||||
template <typename = enable_if_t<is_default_constructible_v<T_0>>>
|
||||
template <typename TT0 = T_0, typename = enable_if_t<is_default_constructible_v<TT0>>>
|
||||
EA_CONSTEXPR variant() EA_NOEXCEPT : mIndex(variant_npos), mStorage()
|
||||
{
|
||||
mIndex = static_cast<variant_index_t>(0);
|
||||
mStorage.template set_as<T_0>();
|
||||
}
|
||||
|
||||
// Only participates in overload resolution if is_copy_constructible_v<T_i> is true for all T_i in Types....
|
||||
|
||||
@@ -293,6 +293,15 @@ namespace eastl
|
||||
template <typename InputIterator>
|
||||
iterator insert(const_iterator position, InputIterator first, InputIterator last);
|
||||
|
||||
template <typename = eastl::enable_if<eastl::has_equality_v<T>>>
|
||||
iterator erase_first(const T& value);
|
||||
template <typename = eastl::enable_if<eastl::has_equality_v<T>>>
|
||||
iterator erase_first_unsorted(const T& value); // Same as erase, except it doesn't preserve order, but is faster because it simply copies the last item in the vector over the erased position.
|
||||
template <typename = eastl::enable_if<eastl::has_equality_v<T>>>
|
||||
reverse_iterator erase_last(const T& value);
|
||||
template <typename = eastl::enable_if<eastl::has_equality_v<T>>>
|
||||
reverse_iterator erase_last_unsorted(const T& value); // Same as erase, except it doesn't preserve order, but is faster because it simply copies the last item in the vector over the erased position.
|
||||
|
||||
iterator erase(const_iterator position);
|
||||
iterator erase(const_iterator first, const_iterator last);
|
||||
iterator erase_unsorted(const_iterator position); // Same as erase, except it doesn't preserve order, but is faster because it simply copies the last item in the vector over the erased position.
|
||||
@@ -1227,6 +1236,56 @@ namespace eastl
|
||||
return destPosition;
|
||||
}
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
template <typename>
|
||||
inline typename vector<T, Allocator>::iterator vector<T, Allocator>::erase_first(const T& value)
|
||||
{
|
||||
iterator it = eastl::find(begin(), end(), value);
|
||||
|
||||
if (it != end())
|
||||
return erase(it);
|
||||
else
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
template <typename>
|
||||
inline typename vector<T, Allocator>::iterator
|
||||
vector<T, Allocator>::erase_first_unsorted(const T& value)
|
||||
{
|
||||
iterator it = eastl::find(begin(), end(), value);
|
||||
|
||||
if (it != end())
|
||||
return erase_unsorted(it);
|
||||
else
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
template <typename>
|
||||
inline typename vector<T, Allocator>::reverse_iterator
|
||||
vector<T, Allocator>::erase_last(const T& value)
|
||||
{
|
||||
reverse_iterator it = eastl::find(rbegin(), rend(), value);
|
||||
|
||||
if (it != rend())
|
||||
return erase(it);
|
||||
else
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
template <typename>
|
||||
inline typename vector<T, Allocator>::reverse_iterator
|
||||
vector<T, Allocator>::erase_last_unsorted(const T& value)
|
||||
{
|
||||
reverse_iterator it = eastl::find(rbegin(), rend(), value);
|
||||
|
||||
if (it != rend())
|
||||
return erase_unsorted(it);
|
||||
else
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
inline typename vector<T, Allocator>::reverse_iterator
|
||||
|
||||
@@ -198,6 +198,14 @@
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_IDENTITY
|
||||
//
|
||||
#ifndef EA_IDENTITY
|
||||
#define EA_IDENTITY(x) x
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_COMPILER_MANAGED_CPP
|
||||
// Defined if this is being compiled with Managed C++ extensions
|
||||
@@ -627,6 +635,39 @@
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_ENABLE_VC_WARNING_AS_ERROR / EA_DISABLE_VC_WARNING_AS_ERROR
|
||||
//
|
||||
// Disable and re-enable treating a warning as error within code.
|
||||
// This is simply a wrapper for VC++ #pragma warning(error: nnnn) for the
|
||||
// purpose of making code easier to read due to avoiding nested compiler ifdefs
|
||||
// directly in code.
|
||||
//
|
||||
// Example usage:
|
||||
// EA_ENABLE_VC_WARNING_AS_ERROR(4996)
|
||||
// <code>
|
||||
// EA_DISABLE_VC_WARNING_AS_ERROR()
|
||||
//
|
||||
#ifndef EA_ENABLE_VC_WARNING_AS_ERROR
|
||||
#if defined(_MSC_VER)
|
||||
#define EA_ENABLE_VC_WARNING_AS_ERROR(w) \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(error:w))
|
||||
#else
|
||||
#define EA_ENABLE_VC_WARNING_AS_ERROR(w)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EA_DISABLE_VC_WARNING_AS_ERROR
|
||||
#if defined(_MSC_VER)
|
||||
#define EA_DISABLE_VC_WARNING_AS_ERROR() \
|
||||
__pragma(warning(pop))
|
||||
#else
|
||||
#define EA_DISABLE_VC_WARNING_AS_ERROR()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_DISABLE_GCC_WARNING / EA_RESTORE_GCC_WARNING
|
||||
//
|
||||
@@ -677,6 +718,46 @@
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_ENABLE_GCC_WARNING_AS_ERROR / EA_DISABLE_GCC_WARNING_AS_ERROR
|
||||
//
|
||||
// Example usage:
|
||||
// // Only one warning can be treated as an error per statement, due to how GCC works.
|
||||
// EA_ENABLE_GCC_WARNING_AS_ERROR(-Wuninitialized)
|
||||
// EA_ENABLE_GCC_WARNING_AS_ERROR(-Wunused)
|
||||
// <code>
|
||||
// EA_DISABLE_GCC_WARNING_AS_ERROR()
|
||||
// EA_DISABLE_GCC_WARNING_AS_ERROR()
|
||||
//
|
||||
#ifndef EA_ENABLE_GCC_WARNING_AS_ERROR
|
||||
#if defined(EA_COMPILER_GNUC)
|
||||
#define EAGCCWERRORHELP0(x) #x
|
||||
#define EAGCCWERRORHELP1(x) EAGCCWERRORHELP0(GCC diagnostic error x)
|
||||
#define EAGCCWERRORHELP2(x) EAGCCWERRORHELP1(#x)
|
||||
#endif
|
||||
|
||||
#if defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006) // Can't test directly for __GNUC__ because some compilers lie.
|
||||
#define EA_ENABLE_GCC_WARNING_AS_ERROR(w) \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma(EAGCCWERRORHELP2(w))
|
||||
#elif defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4004)
|
||||
#define EA_DISABLE_GCC_WARNING(w) \
|
||||
_Pragma(EAGCCWERRORHELP2(w))
|
||||
#else
|
||||
#define EA_DISABLE_GCC_WARNING(w)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EA_DISABLE_GCC_WARNING_AS_ERROR
|
||||
#if defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006)
|
||||
#define EA_DISABLE_GCC_WARNING_AS_ERROR() \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
#define EA_DISABLE_GCC_WARNING_AS_ERROR()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_DISABLE_CLANG_WARNING / EA_RESTORE_CLANG_WARNING
|
||||
//
|
||||
@@ -719,6 +800,41 @@
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_ENABLE_CLANG_WARNING_AS_ERROR / EA_DISABLE_CLANG_WARNING_AS_ERROR
|
||||
//
|
||||
// Example usage:
|
||||
// // Only one warning can be treated as an error per statement, due to how clang works.
|
||||
// EA_ENABLE_CLANG_WARNING_AS_ERROR(-Wuninitialized)
|
||||
// EA_ENABLE_CLANG_WARNING_AS_ERROR(-Wunused)
|
||||
// <code>
|
||||
// EA_DISABLE_CLANG_WARNING_AS_ERROR()
|
||||
// EA_DISABLE_CLANG_WARNING_AS_ERROR()
|
||||
//
|
||||
#ifndef EA_ENABLE_CLANG_WARNING_AS_ERROR
|
||||
#if defined(EA_COMPILER_CLANG)
|
||||
#define EACLANGWERRORHELP0(x) #x
|
||||
#define EACLANGWERRORHELP1(x) EACLANGWERRORHELP0(clang diagnostic error x)
|
||||
#define EACLANGWERRORHELP2(x) EACLANGWERRORHELP1(#x)
|
||||
|
||||
#define EA_ENABLE_CLANG_WARNING_AS_ERROR(w) \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma(EACLANGWERRORHELP2(w))
|
||||
#else
|
||||
#define EA_DISABLE_CLANG_WARNING(w)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EA_DISABLE_CLANG_WARNING_AS_ERROR
|
||||
#if defined(EA_COMPILER_CLANG)
|
||||
#define EA_DISABLE_CLANG_WARNING_AS_ERROR() \
|
||||
_Pragma("clang diagnostic pop")
|
||||
#else
|
||||
#define EA_DISABLE_CLANG_WARNING_AS_ERROR()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_DISABLE_SN_WARNING / EA_RESTORE_SN_WARNING
|
||||
//
|
||||
@@ -1188,7 +1304,8 @@
|
||||
#if defined(EA_COMPILER_CPP14_ENABLED)
|
||||
#define EA_DEPRECATED_MESSAGE(msg) [[deprecated(#msg)]]
|
||||
#else
|
||||
#define EA_DEPRECATED_MESSAGE(msg)
|
||||
// Compiler does not support depreaction messages, explicitly drop the msg but still mark the function as deprecated
|
||||
#define EA_DEPRECATED_MESSAGE(msg) EA_DEPRECATED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1479,8 +1596,9 @@
|
||||
|
||||
// EA_FP128 may be used to determine if __float128 is a supported type for use. This type is enabled by a GCC extension (_GLIBCXX_USE_FLOAT128)
|
||||
// but has support by some implementations of clang (__FLOAT128__)
|
||||
// PS4 does not support __float128 as of SDK 5.500 https://ps4.siedev.net/resources/documents/SDK/5.500/CPU_Compiler_ABI-Overview/0003.html
|
||||
#ifndef EA_FP128
|
||||
#if defined __FLOAT128__ || defined _GLIBCXX_USE_FLOAT128
|
||||
#if (defined __FLOAT128__ || defined _GLIBCXX_USE_FLOAT128) && !defined(EA_PLATFORM_KETTLE)
|
||||
#define EA_FP128 1
|
||||
#else
|
||||
#define EA_FP128 0
|
||||
@@ -1534,6 +1652,24 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_FMA3
|
||||
// EA_FMA3 may be used to determine if Fused Multiply Add operations are available for the target architecture
|
||||
// __FMA__ is defined only by GCC, Clang, and ICC; MSVC only defines __AVX__ and __AVX2__
|
||||
// FMA3 was introduced alongside AVX2 on Intel Haswell
|
||||
// All AMD processors support FMA3 if AVX2 is also supported
|
||||
//
|
||||
// EA_FMA3 defines the level of FMA3 support:
|
||||
// 0 indicates no FMA3 support
|
||||
// 1 indicates FMA3 is supported
|
||||
#ifndef EA_FMA3
|
||||
#if defined(__FMA__) || EA_AVX2 >= 1
|
||||
#define EA_FMA3 1
|
||||
#else
|
||||
#define EA_FMA3 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_TBM
|
||||
// EA_TBM may be used to determine if Trailing Bit Manipulation instructions are available for the target architecture
|
||||
@@ -2210,7 +2346,7 @@
|
||||
#define EA_OPTIMIZE_OFF() \
|
||||
_Pragma("GCC push_options") \
|
||||
_Pragma("GCC optimize 0")
|
||||
#elif defined(EA_COMPILER_CLANG) && !defined(EA_PLATFORM_ANDROID) // android clang 305 compiler crashes when this pragma is used
|
||||
#elif defined(EA_COMPILER_CLANG) && (!defined(EA_PLATFORM_ANDROID) || (EA_COMPILER_VERSION >= 380))
|
||||
#define EA_OPTIMIZE_OFF() \
|
||||
EA_DISABLE_CLANG_WARNING(-Wunknown-pragmas) \
|
||||
_Pragma("clang optimize off") \
|
||||
@@ -2225,7 +2361,7 @@
|
||||
#define EA_OPTIMIZE_ON() __pragma(optimize("", on))
|
||||
#elif defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION > 4004) && (defined(__i386__) || defined(__x86_64__)) // GCC 4.4+ - Seems to work only on x86/Linux so far. However, GCC 4.4 itself appears broken and screws up parameter passing conventions.
|
||||
#define EA_OPTIMIZE_ON() _Pragma("GCC pop_options")
|
||||
#elif defined(EA_COMPILER_CLANG) && !defined(EA_PLATFORM_ANDROID) // android clang 305 compiler crashes when this pragma is used
|
||||
#elif defined(EA_COMPILER_CLANG) && (!defined(EA_PLATFORM_ANDROID) || (EA_COMPILER_VERSION >= 380))
|
||||
#define EA_OPTIMIZE_ON() \
|
||||
EA_DISABLE_CLANG_WARNING(-Wunknown-pragmas) \
|
||||
_Pragma("clang optimize on") \
|
||||
|
||||
@@ -639,9 +639,11 @@
|
||||
// implementation will return. This should be used when writing custom
|
||||
// allocators to ensure that the alignment matches that of malloc
|
||||
#ifndef EA_PLATFORM_MIN_MALLOC_ALIGNMENT
|
||||
#if defined EA_PLATFORM_APPLE
|
||||
#if defined(EA_PLATFORM_APPLE)
|
||||
#define EA_PLATFORM_MIN_MALLOC_ALIGNMENT 16
|
||||
#elif defined EA_PLATFORM_ANDROID
|
||||
#elif defined(EA_PLATFORM_ANDROID) && defined(EA_PROCESSOR_ARM)
|
||||
#define EA_PLATFORM_MIN_MALLOC_ALIGNMENT 8
|
||||
#elif defined(EA_PLATFORM_ANDROID) && defined(EA_PROCESSOR_X86_64)
|
||||
#define EA_PLATFORM_MIN_MALLOC_ALIGNMENT 8
|
||||
#else
|
||||
#define EA_PLATFORM_MIN_MALLOC_ALIGNMENT (EA_PLATFORM_PTR_SIZE * 2)
|
||||
@@ -657,7 +659,7 @@
|
||||
// 2 - supported and fast.
|
||||
//
|
||||
#ifndef EA_MISALIGNED_SUPPORT_LEVEL
|
||||
#if defined(EA_PROCESSOR_X64) || defined(EA_PROCESSOR_X86_64)
|
||||
#if defined(EA_PROCESSOR_X86_64)
|
||||
#define EA_MISALIGNED_SUPPORT_LEVEL 2
|
||||
#else
|
||||
#define EA_MISALIGNED_SUPPORT_LEVEL 0
|
||||
|
||||
@@ -439,14 +439,7 @@
|
||||
#define PRIx64 EA_PRI_64_LENGTH_SPECIFIER "x"
|
||||
#define PRIX64 EA_PRI_64_LENGTH_SPECIFIER "X"
|
||||
|
||||
#if defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1900)
|
||||
#define PRIdPTR "Id"
|
||||
#define PRIiPTR "Ii"
|
||||
#define PRIoPTR "Io"
|
||||
#define PRIuPTR "Iu"
|
||||
#define PRIxPTR "Ix"
|
||||
#define PRIXPTR "IX"
|
||||
#elif (EA_PLATFORM_PTR_SIZE == 4)
|
||||
#if (EA_PLATFORM_PTR_SIZE == 4)
|
||||
#define PRIdPTR PRId32 // Usage of pointer values will generate warnings with
|
||||
#define PRIiPTR PRIi32 // some compilers because they are defined in terms of
|
||||
#define PRIoPTR PRIo32 // integers. However, you can't simply use "p" because
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
EA_ONCE()
|
||||
#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
|
||||
|
||||
// Defining common SI unit macros.
|
||||
//
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EABASE_VERSION
|
||||
#define EABASE_VERSION "2.08.03"
|
||||
#define EABASE_VERSION_N 20803
|
||||
#define EABASE_VERSION "2.08.04"
|
||||
#define EABASE_VERSION_N 20804
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,11 +11,6 @@ namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
unsigned gVerbosityLevel = 0;
|
||||
}
|
||||
|
||||
void PlatformStartup() {}
|
||||
void PlatformShutdown(int nErrorCount)
|
||||
{
|
||||
@@ -60,6 +55,7 @@ namespace EA
|
||||
for (int i = nStartingIndex; i < m_argc; i++)
|
||||
{
|
||||
const char *arg = m_argv[i];
|
||||
bool prefixMatch = false;
|
||||
if (HasPrefix(arg, pSwitch, bCaseSensitive) && (arg[switchLen] == '\0' || arg[switchLen] == delimiter))
|
||||
{
|
||||
if (pResult)
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace EA
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
extern unsigned gVerbosityLevel;
|
||||
static unsigned gVerbosityLevel = 0;
|
||||
};
|
||||
|
||||
typedef void (*ReportFunction)(const char8_t*);
|
||||
@@ -25,6 +25,11 @@ namespace EA
|
||||
{ printf("%s", pOutput); });
|
||||
}
|
||||
|
||||
inline ReportFunction GetReportFunction()
|
||||
{
|
||||
return GetDefaultReportFunction();
|
||||
}
|
||||
|
||||
inline void VReport(const char8_t* pFormat, va_list arguments)
|
||||
{
|
||||
vprintf(pFormat, arguments);
|
||||
|
||||
@@ -605,7 +605,7 @@ namespace EA
|
||||
/// If the test name is not supplied, it is empty. If the ReportFunction is
|
||||
/// not supplied, the default global report function is used.
|
||||
///
|
||||
Test(const char8_t* pTestName = NULL, EA::EAMain::ReportFunction pReportFunction = NULL);
|
||||
Test(const char8_t* pTestName = NULL, EA::EAMain::ReportFunction pReportFunction = EA::EAMain::GetReportFunction());
|
||||
|
||||
/// ~Test
|
||||
///
|
||||
@@ -1076,7 +1076,7 @@ namespace EA
|
||||
/// character is reserved for separating hierarchical test suites.
|
||||
/// The test result is initialized to kTestResultNone.
|
||||
///
|
||||
TestSuite(const char8_t* pTestName = NULL);
|
||||
TestSuite(const char8_t* pTestName = NULL, EA::EAMain::ReportFunction pReportFunction = EA::EAMain::GetReportFunction());
|
||||
|
||||
/// ~TestSuite
|
||||
///
|
||||
|
||||
@@ -1090,8 +1090,8 @@ size_t TestCollection::EnumerateTests(Test* pTestArray[], size_t nTestArrayCapac
|
||||
// TestSuite
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TestSuite::TestSuite(const char8_t* pTestName)
|
||||
: Test(pTestName),
|
||||
TestSuite::TestSuite(const char8_t* pTestName, EA::EAMain::ReportFunction pReportFunction)
|
||||
: Test(pTestName, pReportFunction),
|
||||
TestCollection(),
|
||||
mnTestResult(kTestResultNone),
|
||||
mResults()
|
||||
|
||||
@@ -61,7 +61,7 @@ struct NotDefaultConstructible
|
||||
{
|
||||
NotDefaultConstructible() = delete;
|
||||
};
|
||||
static_assert(!eastl::is_default_constructible<NotDefaultConstructible>::value, "eastl::is_default_constructible<NotDefaultConstructible>::value");
|
||||
static_assert(!eastl::is_default_constructible<NotDefaultConstructible>::value, "'NotDefaultConstructible' is default constructible.");
|
||||
|
||||
|
||||
class CopyConstructible
|
||||
|
||||
@@ -64,6 +64,7 @@ int TestSegmentedVector();
|
||||
int TestSet();
|
||||
int TestSmartPtr();
|
||||
int TestSort();
|
||||
int TestSpan();
|
||||
int TestSparseMatrix();
|
||||
int TestString();
|
||||
int TestStringHashMap();
|
||||
|
||||
@@ -1293,6 +1293,25 @@ int TestAlgorithm()
|
||||
EATEST_VERIFY(i == 1000);
|
||||
}
|
||||
|
||||
// for_each_n
|
||||
{
|
||||
{
|
||||
vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
for_each_n(v.begin(), 5, [](auto& e) { e += 10; });
|
||||
|
||||
vector<int> expected = {10, 11, 12, 13, 14, 5, 6, 7, 8, 9};
|
||||
EATEST_VERIFY(v == expected);
|
||||
}
|
||||
|
||||
// verify lambda can return a result that is ignored.
|
||||
{
|
||||
vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
for_each_n(v.begin(), 5, [](auto& e) { e += 10; return 42; });
|
||||
|
||||
vector<int> expected = {10, 11, 12, 13, 14, 5, 6, 7, 8, 9};
|
||||
EATEST_VERIFY(v == expected);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// void generate(ForwardIterator first, ForwardIterator last, Generator generator)
|
||||
|
||||
@@ -1276,6 +1276,34 @@ int TestBitset()
|
||||
EATEST_VERIFY(i == 137);
|
||||
}
|
||||
|
||||
// test BITSET_WORD_COUNT macro
|
||||
{
|
||||
{
|
||||
typedef eastl::bitset<32, char> bitset_t;
|
||||
static_assert(bitset_t::kWordCount == BITSET_WORD_COUNT(bitset_t::kSize, bitset_t::word_type), "bitset failure");
|
||||
}
|
||||
{
|
||||
typedef eastl::bitset<32, int> bitset_t;
|
||||
static_assert(bitset_t::kWordCount == BITSET_WORD_COUNT(bitset_t::kSize, bitset_t::word_type), "bitset failure");
|
||||
}
|
||||
{
|
||||
typedef eastl::bitset<32, int16_t> bitset_t;
|
||||
static_assert(bitset_t::kWordCount == BITSET_WORD_COUNT(bitset_t::kSize, bitset_t::word_type), "bitset failure");
|
||||
}
|
||||
{
|
||||
typedef eastl::bitset<32, int32_t> bitset_t;
|
||||
static_assert(bitset_t::kWordCount == BITSET_WORD_COUNT(bitset_t::kSize, bitset_t::word_type), "bitset failure");
|
||||
}
|
||||
{
|
||||
typedef eastl::bitset<128, int64_t> bitset_t;
|
||||
static_assert(bitset_t::kWordCount == BITSET_WORD_COUNT(bitset_t::kSize, bitset_t::word_type), "bitset failure");
|
||||
}
|
||||
{
|
||||
typedef eastl::bitset<256, int64_t> bitset_t;
|
||||
static_assert(bitset_t::kWordCount == BITSET_WORD_COUNT(bitset_t::kSize, bitset_t::word_type), "bitset failure");
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ int TestDuration()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
#if !(defined(_MSC_VER) && (_MSC_VER < 1900)) // all platforms except VS2013 and below...
|
||||
{
|
||||
hours h{1}; // 1 hour
|
||||
milliseconds ms{3}; // 3 milliseconds
|
||||
@@ -31,12 +30,12 @@ int TestDuration()
|
||||
microseconds us = ms;
|
||||
duration<double, milli> ms2 = us; // 3.0 milliseconds
|
||||
|
||||
EA_UNUSED(h);
|
||||
EA_UNUSED(ms2);
|
||||
EA_UNUSED(ks);
|
||||
EA_UNUSED(hz30);
|
||||
EA_UNUSED(us);
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
typedef duration<double, ratio<1, 30>> dur_t;
|
||||
|
||||
@@ -9,6 +9,79 @@
|
||||
#include <EASTL/fixed_function.h>
|
||||
#include <EASTL/numeric.h>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFixedFunctionDtor
|
||||
//
|
||||
int TestFixedFunctionDtor()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
TestObject to;
|
||||
TestObject::Reset();
|
||||
{
|
||||
eastl::fixed_function<sizeof(TestObject), void(void)> ff = [to] {};
|
||||
ff();
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFixedFunctionExistingClosure
|
||||
//
|
||||
int TestFixedFunctionExistingClosure()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
TestObject to;
|
||||
{
|
||||
using ff_t = eastl::fixed_function<sizeof(TestObject), void(void)>;
|
||||
{
|
||||
ff_t ff1 = [to] {};
|
||||
ff_t ff3 = [to] {};
|
||||
TestObject::Reset();
|
||||
{
|
||||
ff_t ff2 = ff1;
|
||||
ff2 = ff3; // copy over function that holds existing closure state
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
{
|
||||
ff_t ff1 = [to] {};
|
||||
ff_t ff3 = [to] {};
|
||||
TestObject::Reset();
|
||||
{
|
||||
ff_t ff2 = ff1;
|
||||
ff2 = eastl::move(ff3); // copy over function that holds existing closure state
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
{
|
||||
ff_t ff1 = [to] {};
|
||||
TestObject::Reset();
|
||||
{
|
||||
ff_t ff2 = ff1;
|
||||
ff2 = nullptr;
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFixedFunctionCaptureless
|
||||
//
|
||||
@@ -34,40 +107,14 @@ int TestFixedFunctionCaptureless()
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFunctional
|
||||
// TestFixedFunctionBasic
|
||||
//
|
||||
int TestFixedFunction()
|
||||
int TestFixedFunctionBasic()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
using ff_0 = eastl::fixed_function<0, int(int)>;
|
||||
using ff_1 = eastl::fixed_function<1, int(int)>;
|
||||
using ff_4 = eastl::fixed_function<4, int(int)>;
|
||||
using ff_8 = eastl::fixed_function<8, int(int)>;
|
||||
using ff_64 = eastl::fixed_function<64, int(int)>;
|
||||
using ff_128 = eastl::fixed_function<128, int(int)>;
|
||||
using ff_4096 = eastl::fixed_function<4096, int(int)>;
|
||||
|
||||
static_assert(sizeof(ff_0) >= sizeof(void*), "error");
|
||||
static_assert(sizeof(ff_1) >= sizeof(void*), "error");
|
||||
static_assert(sizeof(ff_4) >= sizeof(void*), "error");
|
||||
static_assert(sizeof(ff_8) >= 8, "error");
|
||||
static_assert(sizeof(ff_64) >= 64, "error");
|
||||
static_assert(sizeof(ff_128) >= 128, "error");
|
||||
static_assert(sizeof(ff_4096) >= 4096, "error");
|
||||
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_0>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_1>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_4>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_8>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_64>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_128>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_4096>();
|
||||
}
|
||||
|
||||
{
|
||||
struct Functor { int operator()() { return 42; } };
|
||||
fixed_function<0, int(void)> fn = Functor();
|
||||
@@ -151,6 +198,48 @@ int TestFixedFunction()
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
using ff_0 = eastl::fixed_function<0, int(int)>;
|
||||
using ff_1 = eastl::fixed_function<1, int(int)>;
|
||||
using ff_4 = eastl::fixed_function<4, int(int)>;
|
||||
using ff_8 = eastl::fixed_function<8, int(int)>;
|
||||
using ff_64 = eastl::fixed_function<64, int(int)>;
|
||||
using ff_128 = eastl::fixed_function<128, int(int)>;
|
||||
using ff_4096 = eastl::fixed_function<4096, int(int)>;
|
||||
|
||||
static_assert(sizeof(ff_0) >= sizeof(void*), "error");
|
||||
static_assert(sizeof(ff_1) >= sizeof(void*), "error");
|
||||
static_assert(sizeof(ff_4) >= sizeof(void*), "error");
|
||||
static_assert(sizeof(ff_8) >= 8, "error");
|
||||
static_assert(sizeof(ff_64) >= 64, "error");
|
||||
static_assert(sizeof(ff_128) >= 128, "error");
|
||||
static_assert(sizeof(ff_4096) >= 4096, "error");
|
||||
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_0>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_1>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_4>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_8>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_64>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_128>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_4096>();
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFunctional
|
||||
//
|
||||
int TestFixedFunction()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
nErrorCount += TestFixedFunctionBasic();
|
||||
nErrorCount += TestFixedFunctionDtor();
|
||||
nErrorCount += TestFixedFunctionExistingClosure();
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
@@ -1332,12 +1332,13 @@ int TestHash()
|
||||
EA_DISABLE_VC_WARNING(4626)
|
||||
struct Key
|
||||
{
|
||||
Key() {}
|
||||
Key(Key && o) {}
|
||||
Key(const Key && o) {}
|
||||
bool operator==(const Key& other) const { return true; }
|
||||
private:
|
||||
Key(const Key& o) {}
|
||||
Key() {}
|
||||
Key(Key&& o) {}
|
||||
Key(const Key&& o) {}
|
||||
bool operator==(const Key& other) const { return true; }
|
||||
|
||||
private:
|
||||
Key(const Key& o) {}
|
||||
};
|
||||
EA_RESTORE_VC_WARNING()
|
||||
|
||||
@@ -1346,18 +1347,11 @@ int TestHash()
|
||||
std::size_t operator()(const Key& k) const { return 0; }
|
||||
};
|
||||
|
||||
struct Tester
|
||||
{
|
||||
int test()
|
||||
{
|
||||
Key key;
|
||||
eastl::hash_map<Key, int, Hash> hm;
|
||||
return hm[eastl::move(key)] = 12345;
|
||||
}
|
||||
};
|
||||
Key key1, key2;
|
||||
eastl::hash_map<Key, int, Hash> hm;
|
||||
hm[eastl::move(key1)] = 12345;
|
||||
|
||||
Tester tester;
|
||||
EATEST_VERIFY(tester.test() == 12345);
|
||||
EATEST_VERIFY(hm[eastl::move(key2)] == 12345);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#ifdef EA_COMPILER_CPP14_ENABLED
|
||||
#include "ConceptImpls.h"
|
||||
#include <EASTL/internal/meta.h>
|
||||
#include <EASTL/meta.h>
|
||||
|
||||
|
||||
int TestGetTypeIndex()
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <EASTL/vector.h>
|
||||
#include <EASTL/string.h>
|
||||
#include <EASTL/optional.h>
|
||||
#include <EASTL/unique_ptr.h>
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@@ -48,6 +49,23 @@ struct move_test
|
||||
|
||||
bool move_test::was_moved = false;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
class forwarding_test
|
||||
{
|
||||
eastl::optional<T> m_optional;
|
||||
|
||||
public:
|
||||
forwarding_test() : m_optional() {}
|
||||
forwarding_test(T&& t) : m_optional(t) {}
|
||||
~forwarding_test() { m_optional.reset(); }
|
||||
|
||||
template <typename U>
|
||||
T GetValueOrDefault(U&& def) const
|
||||
{
|
||||
return m_optional.value_or(eastl::forward<U>(def));
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// TestOptional
|
||||
@@ -138,12 +156,59 @@ int TestOptional()
|
||||
VERIFY(o.value() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
int a = 42;
|
||||
auto o = make_optional(a);
|
||||
VERIFY((is_same<decltype(o)::value_type, int>::value));
|
||||
VERIFY(o.value() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// test make_optional stripping refs/cv-qualifers
|
||||
int a = 42;
|
||||
const volatile int& intRef = a;
|
||||
auto o = make_optional(intRef);
|
||||
VERIFY((is_same<decltype(o)::value_type, int>::value));
|
||||
VERIFY(o.value() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
int a = 10;
|
||||
const volatile int& aRef = a;
|
||||
auto o = eastl::make_optional(aRef);
|
||||
VERIFY(o.value() == 10);
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
struct local { int payload1; };
|
||||
auto o = eastl::make_optional<local>(42);
|
||||
VERIFY(o.value().payload1 == 42);
|
||||
}
|
||||
{
|
||||
struct local { int payload1; int payload2; };
|
||||
auto o = eastl::make_optional<local>(42, 43);
|
||||
VERIFY(o.value().payload1 == 42);
|
||||
VERIFY(o.value().payload2 == 43);
|
||||
}
|
||||
|
||||
{
|
||||
struct local
|
||||
{
|
||||
local(std::initializer_list<int> ilist)
|
||||
{
|
||||
payload1 = ilist.begin()[0];
|
||||
payload2 = ilist.begin()[1];
|
||||
}
|
||||
|
||||
int payload1;
|
||||
int payload2;
|
||||
};
|
||||
|
||||
auto o = eastl::make_optional<local>({42, 43});
|
||||
VERIFY(o.value().payload1 == 42);
|
||||
VERIFY(o.value().payload2 == 43);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -199,6 +264,12 @@ int TestOptional()
|
||||
VERIFY(move_test::was_moved);
|
||||
}
|
||||
|
||||
{
|
||||
forwarding_test<float>ft(1.f);
|
||||
float val = ft.GetValueOrDefault(0.f);
|
||||
VERIFY(val == 1.f);
|
||||
}
|
||||
|
||||
#if EASTL_VARIADIC_TEMPLATES_ENABLED
|
||||
{
|
||||
struct vec3
|
||||
@@ -380,6 +451,60 @@ int TestOptional()
|
||||
static_assert(alignof(optional<Align64>) == alignof(Align64), "optional alignment failure");
|
||||
}
|
||||
|
||||
{
|
||||
// user reported regression that failed to compile
|
||||
struct local_struct
|
||||
{
|
||||
local_struct() {}
|
||||
~local_struct() {}
|
||||
};
|
||||
static_assert(!eastl::is_trivially_destructible_v<local_struct>, "");
|
||||
|
||||
{
|
||||
local_struct ls;
|
||||
eastl::optional<local_struct> o{ls};
|
||||
}
|
||||
{
|
||||
const local_struct ls;
|
||||
eastl::optional<local_struct> o{ls};
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
// user regression
|
||||
eastl::optional<eastl::string> o = eastl::string("Hello World");
|
||||
eastl::optional<eastl::string> co;
|
||||
|
||||
co = o; // force copy-assignment
|
||||
|
||||
VERIFY( o.value().data() != co.value().data());
|
||||
VERIFY( o.value().data() == eastl::string("Hello World"));
|
||||
VERIFY(co.value().data() == eastl::string("Hello World"));
|
||||
}
|
||||
{
|
||||
// user regression
|
||||
struct local
|
||||
{
|
||||
eastl::unique_ptr<int> ptr;
|
||||
|
||||
local(const local&) = delete;
|
||||
local(local&&) = default;
|
||||
local& operator=(const local&) = delete;
|
||||
local& operator=(local&&) = default;
|
||||
};
|
||||
|
||||
eastl::optional<local> o1 = local{eastl::make_unique<int>(42)};
|
||||
eastl::optional<local> o2;
|
||||
|
||||
o2 = eastl::move(o1);
|
||||
|
||||
VERIFY(!!o1 == false);
|
||||
VERIFY(!!o2 == true);
|
||||
VERIFY(o2->ptr.get() != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EASTL_OPTIONAL_ENABLED
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
@@ -283,6 +283,11 @@ int TestSort()
|
||||
intArray = intArraySaved;
|
||||
quick_sort(intArray.begin(), intArray.end());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
|
||||
intArray = intArraySaved;
|
||||
buffer.resize(intArray.size()/2);
|
||||
tim_sort_buffer(intArray.begin(), intArray.end(), buffer.data());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,6 +353,11 @@ int TestSort()
|
||||
toArray = toArraySaved;
|
||||
quick_sort(toArray.begin(), toArray.end());
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end()));
|
||||
|
||||
toArray = toArraySaved;
|
||||
vector<TestObject> buffer(toArray.size()/2);
|
||||
tim_sort_buffer(toArray.begin(), toArray.end(), buffer.data());
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -633,6 +643,12 @@ int TestSort()
|
||||
intDeque = intDequeSaved;
|
||||
quick_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare);
|
||||
EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0));
|
||||
|
||||
StatefulCompare::Reset();
|
||||
vector<int> buffer(intDeque.size()/2);
|
||||
intDeque = intDequeSaved;
|
||||
tim_sort_buffer<IntDequeIterator, int, StatefulCompare&>(intDeque.begin(), intDeque.end(), buffer.data(), compare);
|
||||
EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0));
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
373
test/source/TestSpan.cpp
Normal file
373
test/source/TestSpan.cpp
Normal file
@@ -0,0 +1,373 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/array.h>
|
||||
#include <EASTL/span.h>
|
||||
#include <EASTL/vector.h>
|
||||
|
||||
void TestSpanCtor(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
{
|
||||
span<int> s;
|
||||
VERIFY(s.empty());
|
||||
VERIFY(s.size() == 0);
|
||||
VERIFY(s.data() == nullptr);
|
||||
}
|
||||
{
|
||||
span<float> s;
|
||||
VERIFY(s.empty());
|
||||
VERIFY(s.size() == 0);
|
||||
VERIFY(s.data() == nullptr);
|
||||
}
|
||||
{
|
||||
span<TestObject> s;
|
||||
VERIFY(s.empty());
|
||||
VERIFY(s.size() == 0);
|
||||
VERIFY(s.data() == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
int arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int> s(eastl::begin(arr), 5);
|
||||
VERIFY(s.data() == eastl::begin(arr));
|
||||
VERIFY(s.size() == 5);
|
||||
VERIFY(!s.empty());
|
||||
}
|
||||
|
||||
{
|
||||
int arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int> s(eastl::begin(arr), eastl::end(arr));
|
||||
VERIFY(s.data() == eastl::begin(arr));
|
||||
VERIFY(s.size() == 5);
|
||||
VERIFY(!s.empty());
|
||||
}
|
||||
|
||||
{
|
||||
int arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int> s(arr);
|
||||
VERIFY(s.data() == eastl::begin(arr));
|
||||
VERIFY(s.size() == 5);
|
||||
VERIFY(s.data()[2] == arr[2]);
|
||||
VERIFY(!s.empty());
|
||||
}
|
||||
|
||||
{
|
||||
eastl::array<int, 5> arr = {{0, 1, 2, 3, 4}};
|
||||
span<int> s(arr);
|
||||
VERIFY(s.data() == eastl::begin(arr));
|
||||
VERIFY(s.size() == 5);
|
||||
VERIFY(s.data()[2] == arr.data()[2]);
|
||||
VERIFY(!s.empty());
|
||||
}
|
||||
|
||||
{
|
||||
const eastl::array<int, 5> arr = {{0, 1, 2, 3, 4}};
|
||||
span<const int> s(arr);
|
||||
VERIFY(s.data() == eastl::begin(arr));
|
||||
VERIFY(s.size() == 5);
|
||||
VERIFY(s.data()[2] == arr.data()[2]);
|
||||
VERIFY(!s.empty());
|
||||
}
|
||||
|
||||
{
|
||||
const eastl::array<int, 5> arr = {{0, 1, 2, 3, 4}};
|
||||
const span<const int> s(arr);
|
||||
VERIFY(s.data() == eastl::begin(arr));
|
||||
VERIFY(s.size() == 5);
|
||||
VERIFY(s.data()[2] == arr.data()[2]);
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanSizeBytes(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
{
|
||||
int arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int> s(arr);
|
||||
VERIFY(s.size_bytes() == sizeof(arr));
|
||||
VERIFY(s.size_bytes() == (5 * sizeof(int)));
|
||||
}
|
||||
|
||||
{
|
||||
float arr[8] = {0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f};
|
||||
span<float> s(arr);
|
||||
VERIFY(s.size_bytes() == sizeof(arr));
|
||||
VERIFY(s.size_bytes() == (8 * sizeof(float)));
|
||||
}
|
||||
|
||||
{
|
||||
int64_t arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int64_t> s(arr);
|
||||
VERIFY(s.size_bytes() == sizeof(arr));
|
||||
VERIFY(s.size_bytes() == (5 * sizeof(int64_t)));
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanSubscript(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
{
|
||||
int arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int> s(arr);
|
||||
|
||||
VERIFY(s[0] == 0);
|
||||
VERIFY(s[1] == 1);
|
||||
VERIFY(s[2] == 2);
|
||||
VERIFY(s[3] == 3);
|
||||
VERIFY(s[4] == 4);
|
||||
|
||||
VERIFY(s(0) == 0);
|
||||
VERIFY(s(1) == 1);
|
||||
VERIFY(s(2) == 2);
|
||||
VERIFY(s(3) == 3);
|
||||
VERIFY(s(4) == 4);
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanIterators(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
span<int> s(arr);
|
||||
|
||||
// ranged-for test
|
||||
{
|
||||
int* pBegin = arr;
|
||||
for(auto& e : arr)
|
||||
{
|
||||
VERIFY(e == *pBegin++);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto testIteratorBegin = [&](auto p)
|
||||
{
|
||||
VERIFY(*p++ == 0);
|
||||
VERIFY(*p++ == 1);
|
||||
VERIFY(*p++ == 2);
|
||||
VERIFY(*p++ == 3);
|
||||
VERIFY(*p++ == 4);
|
||||
VERIFY(*p++ == 5);
|
||||
VERIFY(*p++ == 6);
|
||||
VERIFY(*p++ == 7);
|
||||
VERIFY(*p++ == 8);
|
||||
VERIFY(*p++ == 9);
|
||||
};
|
||||
|
||||
auto testIteratorEnd = [&](auto p)
|
||||
{
|
||||
p--; // move pointer to a valid element
|
||||
|
||||
VERIFY(*p-- == 9);
|
||||
VERIFY(*p-- == 8);
|
||||
VERIFY(*p-- == 7);
|
||||
VERIFY(*p-- == 6);
|
||||
VERIFY(*p-- == 5);
|
||||
VERIFY(*p-- == 4);
|
||||
VERIFY(*p-- == 3);
|
||||
VERIFY(*p-- == 2);
|
||||
VERIFY(*p-- == 1);
|
||||
VERIFY(*p-- == 0);
|
||||
};
|
||||
|
||||
testIteratorBegin(s.begin());
|
||||
testIteratorBegin(s.cbegin());
|
||||
testIteratorEnd(s.end());
|
||||
testIteratorEnd(s.cend());
|
||||
}
|
||||
|
||||
{
|
||||
auto testReverseIteratorBegin = [&](auto p)
|
||||
{
|
||||
VERIFY(*p++ == 9);
|
||||
VERIFY(*p++ == 8);
|
||||
VERIFY(*p++ == 7);
|
||||
VERIFY(*p++ == 6);
|
||||
VERIFY(*p++ == 5);
|
||||
VERIFY(*p++ == 4);
|
||||
VERIFY(*p++ == 3);
|
||||
VERIFY(*p++ == 2);
|
||||
VERIFY(*p++ == 1);
|
||||
VERIFY(*p++ == 0);
|
||||
};
|
||||
|
||||
auto testReverseIteratorEnd = [&](auto p)
|
||||
{
|
||||
p--; // move pointer to a valid element
|
||||
|
||||
VERIFY(*p-- == 0);
|
||||
VERIFY(*p-- == 1);
|
||||
VERIFY(*p-- == 2);
|
||||
VERIFY(*p-- == 3);
|
||||
VERIFY(*p-- == 4);
|
||||
VERIFY(*p-- == 5);
|
||||
VERIFY(*p-- == 6);
|
||||
VERIFY(*p-- == 7);
|
||||
VERIFY(*p-- == 8);
|
||||
VERIFY(*p-- == 9);
|
||||
};
|
||||
|
||||
testReverseIteratorBegin(s.crbegin());
|
||||
testReverseIteratorEnd(s.crend());
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanCopyAssignment(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
{
|
||||
int arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int> s(arr);
|
||||
span<int> sc = s;
|
||||
|
||||
VERIFY(s[0] == sc[0]);
|
||||
VERIFY(s[1] == sc[1]);
|
||||
VERIFY(s[2] == sc[2]);
|
||||
VERIFY(s[3] == sc[3]);
|
||||
VERIFY(s[4] == sc[4]);
|
||||
|
||||
VERIFY(s(0) == sc(0));
|
||||
VERIFY(s(1) == sc(1));
|
||||
VERIFY(s(2) == sc(2));
|
||||
VERIFY(s(3) == sc(3));
|
||||
VERIFY(s(4) == sc(4));
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanContainerConversion(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
{
|
||||
vector<int> v = {0, 1, 2, 3, 4, 5};
|
||||
span<const int> s(v);
|
||||
|
||||
VERIFY(s.size() == static_cast<span<int>::index_type>(eastl::size(v)));
|
||||
VERIFY(s.data() == eastl::data(v));
|
||||
|
||||
VERIFY(s[0] == v[0]);
|
||||
VERIFY(s[1] == v[1]);
|
||||
VERIFY(s[2] == v[2]);
|
||||
VERIFY(s[3] == v[3]);
|
||||
VERIFY(s[4] == v[4]);
|
||||
VERIFY(s[5] == v[5]);
|
||||
}
|
||||
|
||||
{
|
||||
const vector<int> v = {0, 1, 2, 3, 4, 5};
|
||||
span<const int> s(v);
|
||||
|
||||
VERIFY(s.size() == static_cast<span<int>::index_type>(eastl::size(v)));
|
||||
VERIFY(s.data() == eastl::data(v));
|
||||
|
||||
VERIFY(s[0] == v[0]);
|
||||
VERIFY(s[1] == v[1]);
|
||||
VERIFY(s[2] == v[2]);
|
||||
VERIFY(s[3] == v[3]);
|
||||
VERIFY(s[4] == v[4]);
|
||||
VERIFY(s[5] == v[5]);
|
||||
}
|
||||
|
||||
{
|
||||
vector<int> v = {0, 1, 2, 3, 4, 5};
|
||||
span<const int, 3> s1(v);
|
||||
span<const int> s2(s1);
|
||||
|
||||
VERIFY(s2.size() == (span<const int>::index_type)v.size());
|
||||
VERIFY(s2[0] == v[0]);
|
||||
VERIFY(s2[1] == v[1]);
|
||||
|
||||
VERIFY(s1.data() == v.data());
|
||||
VERIFY(s1.data() == s2.data());
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanComparison(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int arr1[5] = {0, 1, 2, 3, 4};
|
||||
int arr2[8] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
{
|
||||
span<int> s1 = arr1;
|
||||
span<int> s2 = arr2;
|
||||
span<int> s3 = arr2;
|
||||
VERIFY(s2 == s3);
|
||||
VERIFY(s1 != s2);
|
||||
VERIFY(s1 < s2);
|
||||
VERIFY(s1 <= s2);
|
||||
VERIFY(s2 > s1);
|
||||
VERIFY(s2 >= s1);
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanSubViews(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int arr1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
{
|
||||
span<int> s = arr1;
|
||||
auto first_span = s.first<4>();
|
||||
VERIFY(first_span.size() == 4);
|
||||
VERIFY(first_span[0] == 0);
|
||||
VERIFY(first_span[1] == 1);
|
||||
VERIFY(first_span[2] == 2);
|
||||
VERIFY(first_span[3] == 3);
|
||||
}
|
||||
|
||||
{
|
||||
span<int> s = arr1;
|
||||
auto first_span = s.first(4);
|
||||
VERIFY(first_span.size() == 4);
|
||||
VERIFY(first_span[0] == 0);
|
||||
VERIFY(first_span[1] == 1);
|
||||
VERIFY(first_span[2] == 2);
|
||||
VERIFY(first_span[3] == 3);
|
||||
}
|
||||
|
||||
{
|
||||
span<int> s = arr1;
|
||||
auto first_span = s.last<4>();
|
||||
VERIFY(first_span.size() == 4);
|
||||
VERIFY(first_span[0] == 6);
|
||||
VERIFY(first_span[1] == 7);
|
||||
VERIFY(first_span[2] == 8);
|
||||
VERIFY(first_span[3] == 9);
|
||||
}
|
||||
|
||||
{
|
||||
span<int> s = arr1;
|
||||
auto first_span = s.last(4);
|
||||
VERIFY(first_span.size() == 4);
|
||||
VERIFY(first_span[0] == 6);
|
||||
VERIFY(first_span[1] == 7);
|
||||
VERIFY(first_span[2] == 8);
|
||||
VERIFY(first_span[3] == 9);
|
||||
}
|
||||
}
|
||||
|
||||
int TestSpan()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
TestSpanCtor(nErrorCount);
|
||||
TestSpanSizeBytes(nErrorCount);
|
||||
TestSpanSubscript(nErrorCount);
|
||||
TestSpanIterators(nErrorCount);
|
||||
TestSpanCopyAssignment(nErrorCount);
|
||||
TestSpanContainerConversion(nErrorCount);
|
||||
TestSpanComparison(nErrorCount);
|
||||
TestSpanSubViews(nErrorCount);
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
@@ -27,9 +27,12 @@ int TEST_STRING_NAME()
|
||||
void deallocate(void* p, size_t) { EA_FAIL(); }
|
||||
};
|
||||
|
||||
#if defined(EA_PLATFORM_ANDROID) || defined(EA_PLATFORM_APPLE)
|
||||
EA_DISABLE_CLANG_WARNING(-Winherited-variadic-ctor) // warning: inheriting constructor does not inherit ellipsis
|
||||
#if defined(EA_PLATFORM_ANDROID)
|
||||
EA_DISABLE_CLANG_WARNING(-Wunknown-warning-option) // warning: disable unknown warning suppression pragmas
|
||||
EA_DISABLE_CLANG_WARNING(-Wunknown-pragmas) // warning: disable unknown warning suppression pragmas
|
||||
EA_DISABLE_CLANG_WARNING(-Winherited-variadic-ctor) // warning: inheriting constructor does not inherit ellipsis
|
||||
#endif
|
||||
|
||||
struct SSOStringType : public StringType
|
||||
{
|
||||
using StringType::StringType;
|
||||
@@ -42,8 +45,11 @@ int TEST_STRING_NAME()
|
||||
using eastl::basic_string<typename StringType::value_type, Failocator>::basic_string;
|
||||
using eastl::basic_string<typename StringType::value_type, Failocator>::IsSSO;
|
||||
};
|
||||
#if defined(EA_PLATFORM_ANDROID) || defined(EA_PLATFORM_APPLE)
|
||||
EA_RESTORE_CLANG_WARNING()
|
||||
|
||||
#if defined(EA_PLATFORM_ANDROID)
|
||||
EA_RESTORE_CLANG_WARNING()
|
||||
EA_RESTORE_CLANG_WARNING()
|
||||
EA_RESTORE_CLANG_WARNING()
|
||||
#endif
|
||||
|
||||
// SSO (short string optimization) tests
|
||||
@@ -1886,6 +1892,34 @@ int TEST_STRING_NAME()
|
||||
}(str);
|
||||
}
|
||||
|
||||
// test constructing a eastl::basic_string from an eastl::basic_string_view
|
||||
{
|
||||
using StringViewType = basic_string_view<typename StringType::value_type>;
|
||||
StringViewType sv = LITERAL("abcdefghijklmnopqrstuvwxyz");
|
||||
|
||||
{
|
||||
StringType str(sv);
|
||||
VERIFY(str == LITERAL("abcdefghijklmnopqrstuvwxyz"));
|
||||
}
|
||||
|
||||
{
|
||||
StringType str(sv, typename StringType::allocator_type("test"));
|
||||
VERIFY(str == LITERAL("abcdefghijklmnopqrstuvwxyz"));
|
||||
}
|
||||
}
|
||||
|
||||
// test assigning from an eastl::basic_string_view
|
||||
{
|
||||
using StringViewType = basic_string_view<typename StringType::value_type>;
|
||||
StringViewType sv = LITERAL("abcdefghijklmnopqrstuvwxyz");
|
||||
|
||||
{
|
||||
StringType str;
|
||||
str = sv; // force call to 'operator='
|
||||
VERIFY(str == LITERAL("abcdefghijklmnopqrstuvwxyz"));
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
@@ -493,6 +493,23 @@ int TEST_STRING_NAME()
|
||||
VERIFY(eastl::hash<StringViewT>{}(sw3) == eastl::hash<decltype(s)>{}(s));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
StringViewT sw1(LITERAL("AAAAABBBBBCCCDDDDDEEEEEFFFGGH"));
|
||||
|
||||
VERIFY( sw1.starts_with(LITERAL('A')));
|
||||
VERIFY(!sw1.starts_with(LITERAL('X')));
|
||||
VERIFY( sw1.starts_with(LITERAL("AAAA")));
|
||||
VERIFY( sw1.starts_with(StringViewT(LITERAL("AAAA"))));
|
||||
VERIFY(!sw1.starts_with(LITERAL("AAAB")));
|
||||
|
||||
VERIFY( sw1.ends_with(LITERAL('H')));
|
||||
VERIFY(!sw1.ends_with(LITERAL('X')));
|
||||
VERIFY( sw1.ends_with(LITERAL("FGGH")));
|
||||
VERIFY( sw1.ends_with(StringViewT(LITERAL("FGGH"))));
|
||||
VERIFY(!sw1.ends_with(LITERAL("FGGH$")));
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
@@ -454,13 +454,16 @@ typedef void (*FunctionVoidVoidPtr)();
|
||||
namespace
|
||||
{
|
||||
const eastl::string gEmptyStringInstance("");
|
||||
|
||||
const eastl::integral_constant<int*, nullptr> gIntNullptrConstant;
|
||||
static_assert(gIntNullptrConstant() == nullptr, "");
|
||||
}
|
||||
|
||||
int TestTypeTraits()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
|
||||
// static_min / static_max
|
||||
#if EASTL_TYPE_TRAIT_static_min_CONFORMANCE
|
||||
static_assert((static_min<3, 7, 1, 5>::value == 1), "static_min failure");
|
||||
@@ -521,6 +524,24 @@ int TestTypeTraits()
|
||||
static_assert(is_integral<float>::value == false, "is_integral failure");
|
||||
EATEST_VERIFY(GetType(is_integral<float>()) == false);
|
||||
|
||||
static_assert(is_integral<bool>::value, "is_integral failure");
|
||||
static_assert(is_integral<char16_t>::value, "is_integral failure");
|
||||
static_assert(is_integral<char32_t>::value, "is_integral failure");
|
||||
static_assert(is_integral<char>::value, "is_integral failure");
|
||||
static_assert(is_integral<int>::value, "is_integral failure");
|
||||
static_assert(is_integral<long long>::value, "is_integral failure");
|
||||
static_assert(is_integral<long>::value, "is_integral failure");
|
||||
static_assert(is_integral<short>::value, "is_integral failure");
|
||||
static_assert(is_integral<signed char>::value, "is_integral failure");
|
||||
static_assert(is_integral<unsigned char>::value, "is_integral failure");
|
||||
static_assert(is_integral<unsigned int>::value, "is_integral failure");
|
||||
static_assert(is_integral<unsigned long long>::value, "is_integral failure");
|
||||
static_assert(is_integral<unsigned long>::value, "is_integral failure");
|
||||
static_assert(is_integral<unsigned short>::value, "is_integral failure");
|
||||
#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...
|
||||
static_assert(is_integral<wchar_t>::value, "is_integral failure");
|
||||
#endif
|
||||
|
||||
|
||||
// is_floating_point
|
||||
static_assert(is_floating_point<double>::value == true, "is_floating_point failure");
|
||||
@@ -1822,7 +1843,37 @@ int TestTypeTraits()
|
||||
#endif
|
||||
}
|
||||
|
||||
static_assert(gIntNullptrConstant == nullptr, "integral constant with value of nullptr failure");
|
||||
// has_unique_object_representations
|
||||
{
|
||||
static_assert( has_unique_object_representations<bool>::value, "has_unique_object_representations failure");
|
||||
static_assert( has_unique_object_representations<char16_t>::value, "has_unique_object_representations failure");
|
||||
static_assert( has_unique_object_representations<char32_t>::value, "has_unique_object_representations failure");
|
||||
static_assert( has_unique_object_representations<char>::value, "has_unique_object_representations failure");
|
||||
static_assert( has_unique_object_representations<int>::value, "has_unique_object_representations failure");
|
||||
static_assert( has_unique_object_representations<long long>::value, "has_unique_object_representations failure");
|
||||
static_assert( has_unique_object_representations<long>::value, "has_unique_object_representations failure");
|
||||
static_assert( has_unique_object_representations<short>::value, "has_unique_object_representations failure");
|
||||
static_assert( has_unique_object_representations<signed char>::value, "has_unique_object_representations failure");
|
||||
static_assert( has_unique_object_representations<unsigned char>::value, "has_unique_object_representations failure");
|
||||
static_assert( has_unique_object_representations<unsigned int>::value, "has_unique_object_representations failure");
|
||||
static_assert( has_unique_object_representations<unsigned long long>::value, "has_unique_object_representations failure");
|
||||
static_assert( has_unique_object_representations<unsigned long>::value, "has_unique_object_representations failure");
|
||||
static_assert( has_unique_object_representations<unsigned short>::value, "has_unique_object_representations failure");
|
||||
static_assert(!has_unique_object_representations<void>::value, "has_unique_object_representations failure");
|
||||
#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...
|
||||
static_assert( has_unique_object_representations<wchar_t>::value, "has_unique_object_representations failure");
|
||||
#endif
|
||||
|
||||
#if EASTL_TYPE_TRAIT_has_unique_object_representations_CONFORMANCE
|
||||
{
|
||||
struct packed_type { int a; };
|
||||
static_assert( has_unique_object_representations<packed_type>::value, "has_unique_object_representations failure");
|
||||
|
||||
struct padded_type { int a; char b; int c; };
|
||||
static_assert(!has_unique_object_representations<padded_type>::value, "has_unique_object_representations failure");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
@@ -107,6 +107,54 @@ int TestVariantBasic()
|
||||
|
||||
{ variant<monostate> v; EA_UNUSED(v); }
|
||||
{ variant<monostate, NotDefaultConstructible> v; EA_UNUSED(v); }
|
||||
{ variant<int, NotDefaultConstructible> v; EA_UNUSED(v); }
|
||||
|
||||
{
|
||||
struct MyObj
|
||||
{
|
||||
MyObj() : i(1337) {}
|
||||
~MyObj() {}
|
||||
|
||||
int i;
|
||||
};
|
||||
|
||||
struct MyObj2
|
||||
{
|
||||
MyObj2(int& ii) : i(ii) {}
|
||||
~MyObj2() {}
|
||||
|
||||
MyObj2& operator=(const MyObj2&) = delete;
|
||||
|
||||
int& i;
|
||||
};
|
||||
|
||||
static_assert(!eastl::is_trivially_destructible_v<MyObj>, "MyObj can't be trivially destructible");
|
||||
static_assert(!eastl::is_trivially_destructible_v<MyObj2>, "MyObj2 can't be trivially destructible");
|
||||
|
||||
{
|
||||
eastl::variant<MyObj, MyObj2> myVar;
|
||||
VERIFY(get<MyObj>(myVar).i == 1337);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::variant<MyObj, MyObj2> myVar = MyObj();
|
||||
VERIFY(get<MyObj>(myVar).i == 1337);
|
||||
}
|
||||
|
||||
{
|
||||
int i = 42;
|
||||
eastl::variant<MyObj, MyObj2> myVar = MyObj2(i);
|
||||
VERIFY(get<MyObj2>(myVar).i == 42);
|
||||
}
|
||||
|
||||
{
|
||||
auto m = MyObj();
|
||||
m.i = 2000;
|
||||
|
||||
eastl::variant<MyObj, MyObj2> myVar = m;
|
||||
VERIFY(get<MyObj>(myVar).i == 2000);
|
||||
}
|
||||
}
|
||||
|
||||
{ variant<int, int> v; EA_UNUSED(v); }
|
||||
{ variant<const short, volatile short, const volatile short> v; EA_UNUSED(v); }
|
||||
@@ -125,6 +173,17 @@ int TestVariantBasic()
|
||||
TestObject::Reset();
|
||||
}
|
||||
|
||||
{
|
||||
variant<string> v;
|
||||
VERIFY(*(get_if<string>(&v)) == "");
|
||||
VERIFY(get_if<string>(&v)->empty());
|
||||
VERIFY(get_if<string>(&v)->length() == 0);
|
||||
VERIFY(get_if<string>(&v)->size() == 0);
|
||||
|
||||
*(get_if<string>(&v)) += 'a';
|
||||
VERIFY(*(get_if<string>(&v)) == "a");
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
@@ -172,6 +231,17 @@ int TestVariantGet()
|
||||
VERIFY(!holds_alternative<int>(v));
|
||||
VERIFY( holds_alternative<string>(v));
|
||||
}
|
||||
{
|
||||
v_t v;
|
||||
v = strValue;
|
||||
VERIFY(v.index() == 1);
|
||||
VERIFY(*get_if<1>(&v) == strValue);
|
||||
VERIFY(get_if<0>(&v) == nullptr);
|
||||
}
|
||||
{
|
||||
VERIFY(get_if<0>((v_t*)nullptr) == nullptr);
|
||||
VERIFY(get_if<1>((v_t*)nullptr) == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
@@ -184,17 +254,27 @@ int TestVariantHoldsAlternative()
|
||||
|
||||
{
|
||||
{
|
||||
using v_t = variant<int, short>;
|
||||
using v_t = variant<int, short>; // default construct first type
|
||||
v_t v;
|
||||
|
||||
VERIFY(!holds_alternative<long>(v)); // Verify that a query for a T not in the variant typelist returns false.
|
||||
VERIFY(!holds_alternative<string>(v)); // Verify that a query for a T not in the variant typelist returns false.
|
||||
VERIFY(!holds_alternative<int>(v)); // variant does not hold an int
|
||||
VERIFY( holds_alternative<int>(v)); // variant does hold an int, because its a default constructible first parameter
|
||||
VERIFY(!holds_alternative<short>(v)); // variant does not hold a short
|
||||
}
|
||||
|
||||
{
|
||||
using v_t = variant<int>;
|
||||
using v_t = variant<monostate, int, short>; // default construct monostate
|
||||
v_t v;
|
||||
|
||||
VERIFY(!holds_alternative<long>(v)); // Verify that a query for a T not in the variant typelist returns false.
|
||||
VERIFY(!holds_alternative<string>(v)); // Verify that a query for a T not in the variant typelist returns false.
|
||||
VERIFY(!holds_alternative<int>(v)); // variant does not hold an int
|
||||
VERIFY(!holds_alternative<short>(v)); // variant does not hold a short
|
||||
}
|
||||
|
||||
{
|
||||
using v_t = variant<monostate, int>;
|
||||
|
||||
{
|
||||
v_t v;
|
||||
@@ -231,32 +311,80 @@ int TestVariantValuelessByException()
|
||||
{
|
||||
{
|
||||
using v_t = variant<int, short>;
|
||||
static_assert(eastl::is_default_constructible_v<v_t>, "valueless_by_exception error");
|
||||
|
||||
v_t v;
|
||||
VERIFY(v.valueless_by_exception());
|
||||
VERIFY(!v.valueless_by_exception());
|
||||
|
||||
v = 42;
|
||||
VERIFY(!v.valueless_by_exception());
|
||||
}
|
||||
|
||||
{
|
||||
using v_t = variant<int>;
|
||||
using v_t = variant<monostate, int>;
|
||||
static_assert(eastl::is_default_constructible_v<v_t>, "valueless_by_exception error");
|
||||
|
||||
v_t v1, v2;
|
||||
VERIFY(v1.valueless_by_exception());
|
||||
VERIFY(v2.valueless_by_exception());
|
||||
VERIFY(!v1.valueless_by_exception());
|
||||
VERIFY(!v2.valueless_by_exception());
|
||||
|
||||
v1 = 42;
|
||||
VERIFY(!v1.valueless_by_exception());
|
||||
VERIFY(v2.valueless_by_exception());
|
||||
VERIFY(!v2.valueless_by_exception());
|
||||
|
||||
eastl::swap(v1, v2);
|
||||
VERIFY( v1.valueless_by_exception());
|
||||
VERIFY(!v1.valueless_by_exception());
|
||||
VERIFY(!v2.valueless_by_exception());
|
||||
|
||||
v1 = v2;
|
||||
VERIFY(!v1.valueless_by_exception());
|
||||
VERIFY(!v2.valueless_by_exception());
|
||||
}
|
||||
|
||||
{
|
||||
struct NotDefaultConstructibleButHasConversionCtor
|
||||
{
|
||||
NotDefaultConstructibleButHasConversionCtor() = delete;
|
||||
NotDefaultConstructibleButHasConversionCtor(int) {}
|
||||
};
|
||||
static_assert(!eastl::is_default_constructible<NotDefaultConstructibleButHasConversionCtor>::value, "valueless_by_exception error");
|
||||
|
||||
using v_t = variant<NotDefaultConstructibleButHasConversionCtor>;
|
||||
v_t v(42);
|
||||
static_assert(!eastl::is_default_constructible_v<v_t>, "valueless_by_exception error");
|
||||
VERIFY(!v.valueless_by_exception());
|
||||
}
|
||||
|
||||
// TODO(rparolin): review exception safety for variant types
|
||||
//
|
||||
// {
|
||||
// #if EASTL_EXCEPTIONS_ENABLED
|
||||
// struct DefaultConstructibleButThrows
|
||||
// {
|
||||
// DefaultConstructibleButThrows() {}
|
||||
// ~DefaultConstructibleButThrows() {}
|
||||
//
|
||||
// DefaultConstructibleButThrows(DefaultConstructibleButThrows&&) { throw 42; }
|
||||
// DefaultConstructibleButThrows(const DefaultConstructibleButThrows&) { throw 42; }
|
||||
// DefaultConstructibleButThrows& operator=(const DefaultConstructibleButThrows&) { throw 42; }
|
||||
// DefaultConstructibleButThrows& operator=(DefaultConstructibleButThrows&&) { throw 42; }
|
||||
// };
|
||||
//
|
||||
// using v_t = variant<DefaultConstructibleButThrows>;
|
||||
//
|
||||
// v_t v1;
|
||||
// VERIFY(!v1.valueless_by_exception());
|
||||
//
|
||||
// try
|
||||
// {
|
||||
// v1 = DefaultConstructibleButThrows();
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// VERIFY(v1.valueless_by_exception());
|
||||
// }
|
||||
// #endif
|
||||
// }
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
|
||||
@@ -53,6 +53,7 @@ struct HasAddressOfOperator
|
||||
{
|
||||
// problematic 'addressof' operator that doesn't return a pointer type
|
||||
AddressOfOperatorResult operator&() const { return {}; }
|
||||
bool operator==(const HasAddressOfOperator&) const { return false; }
|
||||
};
|
||||
template class eastl::vector<HasAddressOfOperator>; // force compile all functions of vector
|
||||
|
||||
@@ -638,6 +639,10 @@ int TestVector()
|
||||
// iterator erase(iterator position);
|
||||
// iterator erase(iterator first, iterator last);
|
||||
// iterator erase_unsorted(iterator position);
|
||||
// iterator erase_first(const T& pos);
|
||||
// iterator erase_first_unsorted(const T& pos);
|
||||
// iterator erase_last(const T& pos);
|
||||
// iterator erase_last_unsorted(const T& pos);
|
||||
// void clear();
|
||||
|
||||
vector<int> intArray(20);
|
||||
@@ -724,6 +729,143 @@ int TestVector()
|
||||
EATEST_VERIFY(intArray[0] == 19);
|
||||
EATEST_VERIFY(intArray[10] == 18);
|
||||
EATEST_VERIFY(intArray[16] == 16);
|
||||
|
||||
// iterator erase_first(iterator position);
|
||||
intArray.resize(20);
|
||||
for (i = 0; i < 20; i++)
|
||||
intArray[i] = (int)i % 3; // (i.e. 0,1,2,0,1,2...)
|
||||
|
||||
intArray.erase_first(1);
|
||||
EATEST_VERIFY(intArray.validate());
|
||||
EATEST_VERIFY(intArray.size() == 19);
|
||||
EATEST_VERIFY(intArray[0] == 0);
|
||||
EATEST_VERIFY(intArray[1] == 2);
|
||||
EATEST_VERIFY(intArray[2] == 0);
|
||||
EATEST_VERIFY(intArray[3] == 1);
|
||||
EATEST_VERIFY(intArray[18] == 1);
|
||||
|
||||
intArray.erase_first(1);
|
||||
EATEST_VERIFY(intArray.validate());
|
||||
EATEST_VERIFY(intArray.size() == 18);
|
||||
EATEST_VERIFY(intArray[0] == 0);
|
||||
EATEST_VERIFY(intArray[1] == 2);
|
||||
EATEST_VERIFY(intArray[2] == 0);
|
||||
EATEST_VERIFY(intArray[3] == 2);
|
||||
EATEST_VERIFY(intArray[17] == 1);
|
||||
|
||||
intArray.erase_first(0);
|
||||
EATEST_VERIFY(intArray.validate());
|
||||
EATEST_VERIFY(intArray.size() == 17);
|
||||
EATEST_VERIFY(intArray[0] == 2);
|
||||
EATEST_VERIFY(intArray[1] == 0);
|
||||
EATEST_VERIFY(intArray[2] == 2);
|
||||
EATEST_VERIFY(intArray[3] == 0);
|
||||
EATEST_VERIFY(intArray[16] == 1);
|
||||
|
||||
// iterator erase_first_unsorted(const T& val);
|
||||
intArray.resize(20);
|
||||
for (i = 0; i < 20; i++)
|
||||
intArray[i] = (int) i/2; // every two values are the same (i.e. 0,0,1,1,2,2,3,3...)
|
||||
|
||||
intArray.erase_first_unsorted(1);
|
||||
EATEST_VERIFY(intArray.validate());
|
||||
EATEST_VERIFY(intArray.size() == 19);
|
||||
EATEST_VERIFY(intArray[0] == 0);
|
||||
EATEST_VERIFY(intArray[1] == 0);
|
||||
EATEST_VERIFY(intArray[2] == 9);
|
||||
EATEST_VERIFY(intArray[3] == 1);
|
||||
EATEST_VERIFY(intArray[18] == 9);
|
||||
|
||||
intArray.erase_first_unsorted(1);
|
||||
EATEST_VERIFY(intArray.validate());
|
||||
EATEST_VERIFY(intArray.size() == 18);
|
||||
EATEST_VERIFY(intArray[0] == 0);
|
||||
EATEST_VERIFY(intArray[1] == 0);
|
||||
EATEST_VERIFY(intArray[2] == 9);
|
||||
EATEST_VERIFY(intArray[3] == 9);
|
||||
EATEST_VERIFY(intArray[17] == 8);
|
||||
|
||||
intArray.erase_first_unsorted(0);
|
||||
EATEST_VERIFY(intArray.validate());
|
||||
EATEST_VERIFY(intArray.size() == 17);
|
||||
EATEST_VERIFY(intArray[0] == 8);
|
||||
EATEST_VERIFY(intArray[1] == 0);
|
||||
EATEST_VERIFY(intArray[2] == 9);
|
||||
EATEST_VERIFY(intArray[3] == 9);
|
||||
EATEST_VERIFY(intArray[16] == 8);
|
||||
|
||||
// iterator erase_last(const T& val);
|
||||
intArray.resize(20);
|
||||
for (i = 0; i < 20; i++)
|
||||
intArray[i] = (int)i % 3; // (i.e. 0,1,2,0,1,2...)
|
||||
|
||||
intArray.erase_last(1);
|
||||
EATEST_VERIFY(intArray.validate());
|
||||
EATEST_VERIFY(intArray.size() == 19);
|
||||
EATEST_VERIFY(intArray[0] == 0);
|
||||
EATEST_VERIFY(intArray[1] == 1);
|
||||
EATEST_VERIFY(intArray[2] == 2);
|
||||
EATEST_VERIFY(intArray[3] == 0);
|
||||
EATEST_VERIFY(intArray[15] == 0);
|
||||
EATEST_VERIFY(intArray[16] == 1);
|
||||
EATEST_VERIFY(intArray[17] == 2);
|
||||
EATEST_VERIFY(intArray[18] == 0);
|
||||
|
||||
intArray.erase_last(1);
|
||||
EATEST_VERIFY(intArray.validate());
|
||||
EATEST_VERIFY(intArray.size() == 18);
|
||||
EATEST_VERIFY(intArray[0] == 0);
|
||||
EATEST_VERIFY(intArray[1] == 1);
|
||||
EATEST_VERIFY(intArray[2] == 2);
|
||||
EATEST_VERIFY(intArray[3] == 0);
|
||||
EATEST_VERIFY(intArray[14] == 2);
|
||||
EATEST_VERIFY(intArray[15] == 0);
|
||||
EATEST_VERIFY(intArray[16] == 2);
|
||||
EATEST_VERIFY(intArray[17] == 0);
|
||||
|
||||
intArray.erase_last(0);
|
||||
EATEST_VERIFY(intArray.validate());
|
||||
EATEST_VERIFY(intArray.size() == 17);
|
||||
EATEST_VERIFY(intArray[0] == 0);
|
||||
EATEST_VERIFY(intArray[1] == 1);
|
||||
EATEST_VERIFY(intArray[2] == 2);
|
||||
EATEST_VERIFY(intArray[3] == 0);
|
||||
EATEST_VERIFY(intArray[13] == 1);
|
||||
EATEST_VERIFY(intArray[14] == 2);
|
||||
EATEST_VERIFY(intArray[15] == 0);
|
||||
EATEST_VERIFY(intArray[16] == 2);
|
||||
|
||||
// iterator erase_last_unsorted(const T& val);
|
||||
intArray.resize(20);
|
||||
for (i = 0; i < 20; i++)
|
||||
intArray[i] = (int)i / 2; // every two values are the same (i.e. 0,0,1,1,2,2,3,3...)
|
||||
|
||||
intArray.erase_last_unsorted(1);
|
||||
EATEST_VERIFY(intArray.validate());
|
||||
EATEST_VERIFY(intArray.size() == 19);
|
||||
EATEST_VERIFY(intArray[0] == 0);
|
||||
EATEST_VERIFY(intArray[1] == 0);
|
||||
EATEST_VERIFY(intArray[2] == 1);
|
||||
EATEST_VERIFY(intArray[3] == 9);
|
||||
EATEST_VERIFY(intArray[18] == 9);
|
||||
|
||||
intArray.erase_last_unsorted(1);
|
||||
EATEST_VERIFY(intArray.validate());
|
||||
EATEST_VERIFY(intArray.size() == 18);
|
||||
EATEST_VERIFY(intArray[0] == 0);
|
||||
EATEST_VERIFY(intArray[1] == 0);
|
||||
EATEST_VERIFY(intArray[2] == 9);
|
||||
EATEST_VERIFY(intArray[3] == 9);
|
||||
EATEST_VERIFY(intArray[17] == 8);
|
||||
|
||||
intArray.erase_last_unsorted(0);
|
||||
EATEST_VERIFY(intArray.validate());
|
||||
EATEST_VERIFY(intArray.size() == 17);
|
||||
EATEST_VERIFY(intArray[0] == 0);
|
||||
EATEST_VERIFY(intArray[1] == 8);
|
||||
EATEST_VERIFY(intArray[2] == 9);
|
||||
EATEST_VERIFY(intArray[3] == 9);
|
||||
EATEST_VERIFY(intArray[16] == 8);
|
||||
}
|
||||
|
||||
EATEST_VERIFY(TestObject::IsClear());
|
||||
|
||||
@@ -124,6 +124,7 @@ int EAMain(int argc, char* argv[])
|
||||
testSuite.AddTest("Set", TestSet);
|
||||
testSuite.AddTest("SmartPtr", TestSmartPtr);
|
||||
testSuite.AddTest("Sort", TestSort);
|
||||
testSuite.AddTest("Span", TestSpan);
|
||||
testSuite.AddTest("SparseMatrix", TestSparseMatrix);
|
||||
testSuite.AddTest("String", TestString);
|
||||
testSuite.AddTest("StringMap", TestStringMap);
|
||||
|
||||
Reference in New Issue
Block a user