mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-08-05 09:28:40 +02:00
Add ReaderWriterQueue and update ConcurrentQueue
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
EXT=.exe
|
||||
PLATFORM_OPTS=-static
|
||||
PLATFORM_LD_OPTS=-Wl,--no-as-needed
|
||||
else
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
EXT=
|
||||
PLATFORM_OPTS=
|
||||
PLATFORM_LD_OPTS=
|
||||
else
|
||||
EXT=
|
||||
PLATFORM_OPTS=
|
||||
PLATFORM_LD_OPTS=-lrt -Wl,--no-as-needed
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
default: unittests$(EXT)
|
||||
|
||||
unittests$(EXT): unittests.cpp ../../readerwriterqueue.h ../../atomicops.h ../common/simplethread.h ../common/simplethread.cpp minitest.h makefile
|
||||
g++ $(PLATFORM_OPTS) -std=c++11 -Wpedantic -Wall -DNDEBUG -O3 -g unittests.cpp ../common/simplethread.cpp -o unittests$(EXT) -pthread $(PLATFORM_LD_OPTS)
|
||||
|
||||
run: unittests$(EXT)
|
||||
./unittests$(EXT)
|
||||
@@ -0,0 +1,125 @@
|
||||
// ©2013-2014 Cameron Desrochers.
|
||||
// Distributed under the simplified BSD license (see the LICENSE file that
|
||||
// should have come with this header).
|
||||
|
||||
// Provides an extremely basic unit testing framework.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
|
||||
#ifdef __GNUG__
|
||||
#include <cxxabi.h>
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define REGISTER_TEST(testName) registerTest(#testName, &subclass_t::testName)
|
||||
|
||||
#define ASSERT_OR_FAIL(expr) { if (!(expr)) { notifyTestFailed(__LINE__, #expr); return false; } }
|
||||
#define SUCCEED() { return true; }
|
||||
|
||||
|
||||
|
||||
// Uses CRTP
|
||||
template<typename TSubclass>
|
||||
class TestClass
|
||||
{
|
||||
public:
|
||||
static void notifyTestFailed(int line, const char* expr)
|
||||
{
|
||||
std::printf(" FAILED!\n ******* Assertion failed (line %d): %s\n\n", line, expr);
|
||||
}
|
||||
|
||||
bool validateTestName(std::string const& which) const
|
||||
{
|
||||
return testMap.find(which) != testMap.end();
|
||||
}
|
||||
|
||||
void getAllTestNames(std::vector<std::string>& names) const
|
||||
{
|
||||
for (auto it = testMap.cbegin(); it != testMap.cend(); ++it) {
|
||||
names.push_back(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
bool run(unsigned int iterations = 1)
|
||||
{
|
||||
bool success = true;
|
||||
for (auto it = testVec.cbegin(); it != testVec.cend(); ++it) {
|
||||
if (!execTest(*it, iterations)) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool run(std::vector<std::string> const& which, unsigned int iterations = 1)
|
||||
{
|
||||
bool success = true;
|
||||
for (auto it = which.begin(); it != which.end(); ++it) {
|
||||
if (!execTest(*testMap.find(*it), iterations)) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
protected:
|
||||
typedef TSubclass subclass_t;
|
||||
|
||||
void registerTest(const char* name, bool (subclass_t::* method)())
|
||||
{
|
||||
testVec.push_back(std::make_pair(std::string(name), method));
|
||||
testMap[std::string(name)] = method;
|
||||
}
|
||||
|
||||
bool execTest(std::pair<std::string, bool (subclass_t::*)()> const& testRef, unsigned int iterations)
|
||||
{
|
||||
std::printf("%s::%s... \n", demangle_type_name(typeid(subclass_t).name()).c_str(), testRef.first.c_str());
|
||||
|
||||
bool result = true;
|
||||
for (unsigned int i = 0; i != iterations; ++i) {
|
||||
if (!(static_cast<subclass_t*>(this)->*testRef.second)()) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
std::printf(" passed\n\n");
|
||||
}
|
||||
else {
|
||||
std::printf(" FAILED!\n\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string demangle_type_name(const char* name)
|
||||
{
|
||||
#ifdef __GNUG__
|
||||
// Adapted from http://stackoverflow.com/a/4541470/21475
|
||||
int status = -4;
|
||||
char* res = abi::__cxa_demangle(name, nullptr, nullptr, &status);
|
||||
|
||||
const char* const demangled_name = (status == 0) ? res : name;
|
||||
std::string ret(demangled_name);
|
||||
|
||||
std::free(res);
|
||||
return ret;
|
||||
#else
|
||||
return name;
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<std::pair<std::string, bool (TSubclass::*)()> > testVec;
|
||||
std::map<std::string, bool (TSubclass::*)()> testMap;
|
||||
};
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittests", "unittests.vcxproj", "{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Debug|x64.Build.0 = Debug|x64
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Release|Win32.Build.0 = Release|Win32
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Release|x64.ActiveCfg = Release|x64
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>unittests</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IntDir>obj\$(Configuration)\$(Platform)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\$(Platform)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IntDir>obj\$(Configuration)\$(Platform)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\$(Platform)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IntDir>obj\$(Configuration)\$(Platform)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\$(Platform)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IntDir>obj\$(Configuration)\$(Platform)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\$(Platform)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\atomicops.h" />
|
||||
<ClInclude Include="..\..\..\readerwriterqueue.h" />
|
||||
<ClInclude Include="..\..\common\simplethread.h" />
|
||||
<ClInclude Include="..\minitest.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\common\simplethread.cpp" />
|
||||
<ClCompile Include="..\unittests.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\readerwriterqueue.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\atomicops.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\simplethread.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\minitest.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\common\simplethread.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\unittests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.30501.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittests", "unittests.vcxproj", "{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Debug|x64.Build.0 = Debug|x64
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Release|Win32.Build.0 = Release|Win32
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Release|x64.ActiveCfg = Release|x64
|
||||
{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{C209657D-56BF-4A61-8FD2-DBAEB1E51B3B}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>unittests</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IntDir>obj\$(Configuration)\$(Platform)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\$(Platform)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IntDir>obj\$(Configuration)\$(Platform)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\$(Platform)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IntDir>obj\$(Configuration)\$(Platform)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\$(Platform)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IntDir>obj\$(Configuration)\$(Platform)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\$(Platform)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\atomicops.h" />
|
||||
<ClInclude Include="..\..\..\readerwriterqueue.h" />
|
||||
<ClInclude Include="..\..\common\simplethread.h" />
|
||||
<ClInclude Include="..\minitest.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\common\simplethread.cpp" />
|
||||
<ClCompile Include="..\unittests.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\readerwriterqueue.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\atomicops.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\simplethread.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\minitest.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\common\simplethread.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\unittests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,778 @@
|
||||
// ©2013-2015 Cameron Desrochers
|
||||
// Unit tests for moodycamel::ReaderWriterQueue
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "minitest.h"
|
||||
#include "../common/simplethread.h"
|
||||
#include "../../readerwriterqueue.h"
|
||||
|
||||
using namespace moodycamel;
|
||||
|
||||
|
||||
// *NOT* thread-safe
|
||||
struct Foo
|
||||
{
|
||||
Foo() : copied(false) { id = _id()++; }
|
||||
Foo(Foo const& other) : id(other.id), copied(true) { }
|
||||
~Foo()
|
||||
{
|
||||
if (copied) return;
|
||||
if (id != _last_destroyed_id() + 1) {
|
||||
_destroyed_in_order() = false;
|
||||
}
|
||||
_last_destroyed_id() = id;
|
||||
++_destroy_count();
|
||||
}
|
||||
static void reset() { _destroy_count() = 0; _id() = 0; _destroyed_in_order() = true; _last_destroyed_id() = -1; }
|
||||
static int destroy_count() { return _destroy_count(); }
|
||||
static bool destroyed_in_order() { return _destroyed_in_order(); }
|
||||
|
||||
private:
|
||||
static int& _destroy_count() { static int c = 0; return c; }
|
||||
static int& _id() { static int i = 0; return i; }
|
||||
static bool& _destroyed_in_order() { static bool d = true; return d; }
|
||||
static int& _last_destroyed_id() { static int i = -1; return i; }
|
||||
|
||||
int id;
|
||||
bool copied;
|
||||
};
|
||||
|
||||
|
||||
#if MOODYCAMEL_HAS_EMPLACE
|
||||
class UniquePtrWrapper
|
||||
{
|
||||
public:
|
||||
UniquePtrWrapper() = default;
|
||||
UniquePtrWrapper(std::unique_ptr<int> p) : m_p(std::move(p)) {}
|
||||
int get_value() const { return *m_p; }
|
||||
std::unique_ptr<int>& get_ptr() { return m_p; }
|
||||
private:
|
||||
std::unique_ptr<int> m_p;
|
||||
};
|
||||
#endif
|
||||
|
||||
/// Extracted from private static method of ReaderWriterQueue
|
||||
static size_t ceilToPow2(size_t x)
|
||||
{
|
||||
// From http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||
--x;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
for (size_t i = 1; i < sizeof(size_t); i <<= 1) {
|
||||
x |= x >> (i << 3);
|
||||
}
|
||||
++x;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
class ReaderWriterQueueTests : public TestClass<ReaderWriterQueueTests>
|
||||
{
|
||||
public:
|
||||
ReaderWriterQueueTests()
|
||||
{
|
||||
REGISTER_TEST(create_empty_queue);
|
||||
REGISTER_TEST(enqueue_one);
|
||||
REGISTER_TEST(enqueue_many);
|
||||
REGISTER_TEST(nonempty_destroy);
|
||||
REGISTER_TEST(try_enqueue);
|
||||
REGISTER_TEST(try_dequeue);
|
||||
REGISTER_TEST(peek);
|
||||
REGISTER_TEST(pop);
|
||||
REGISTER_TEST(size_approx);
|
||||
REGISTER_TEST(max_capacity);
|
||||
REGISTER_TEST(threaded);
|
||||
REGISTER_TEST(blocking);
|
||||
REGISTER_TEST(vector);
|
||||
#if MOODYCAMEL_HAS_EMPLACE
|
||||
REGISTER_TEST(emplace);
|
||||
REGISTER_TEST(try_enqueue_fail_workaround);
|
||||
REGISTER_TEST(try_emplace_fail);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool create_empty_queue()
|
||||
{
|
||||
{
|
||||
ReaderWriterQueue<int> q;
|
||||
}
|
||||
|
||||
{
|
||||
ReaderWriterQueue<int> q(1234);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool enqueue_one()
|
||||
{
|
||||
int item;
|
||||
|
||||
{
|
||||
item = 0;
|
||||
ReaderWriterQueue<int> q(1);
|
||||
q.enqueue(12345);
|
||||
ASSERT_OR_FAIL(q.try_dequeue(item));
|
||||
ASSERT_OR_FAIL(item == 12345);
|
||||
}
|
||||
|
||||
{
|
||||
item = 0;
|
||||
ReaderWriterQueue<int> q(1);
|
||||
ASSERT_OR_FAIL(q.try_enqueue(12345));
|
||||
ASSERT_OR_FAIL(q.try_dequeue(item));
|
||||
ASSERT_OR_FAIL(item == 12345);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool enqueue_many()
|
||||
{
|
||||
int item = -1;
|
||||
|
||||
{
|
||||
ReaderWriterQueue<int> q(100);
|
||||
for (int i = 0; i != 100; ++i) {
|
||||
q.enqueue(i);
|
||||
}
|
||||
|
||||
for (int i = 0; i != 100; ++i) {
|
||||
ASSERT_OR_FAIL(q.try_dequeue(item));
|
||||
ASSERT_OR_FAIL(item == i);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ReaderWriterQueue<int> q(100);
|
||||
for (int i = 0; i != 1200; ++i) {
|
||||
q.enqueue(i);
|
||||
}
|
||||
|
||||
for (int i = 0; i != 1200; ++i) {
|
||||
ASSERT_OR_FAIL(q.try_dequeue(item));
|
||||
ASSERT_OR_FAIL(item == i);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nonempty_destroy()
|
||||
{
|
||||
Foo item;
|
||||
|
||||
// Some elements at beginning
|
||||
Foo::reset();
|
||||
{
|
||||
ReaderWriterQueue<Foo> q(31);
|
||||
for (int i = 0; i != 10; ++i) {
|
||||
q.enqueue(Foo());
|
||||
}
|
||||
}
|
||||
ASSERT_OR_FAIL(Foo::destroy_count() == 10);
|
||||
ASSERT_OR_FAIL(Foo::destroyed_in_order());
|
||||
|
||||
// Entire block
|
||||
Foo::reset();
|
||||
{
|
||||
ReaderWriterQueue<Foo> q(31);
|
||||
for (int i = 0; i != 31; ++i) {
|
||||
q.enqueue(Foo());
|
||||
}
|
||||
}
|
||||
ASSERT_OR_FAIL(Foo::destroy_count() == 31);
|
||||
ASSERT_OR_FAIL(Foo::destroyed_in_order());
|
||||
|
||||
// Multiple blocks
|
||||
Foo::reset();
|
||||
{
|
||||
ReaderWriterQueue<Foo> q(31);
|
||||
for (int i = 0; i != 94; ++i) {
|
||||
q.enqueue(Foo());
|
||||
}
|
||||
}
|
||||
ASSERT_OR_FAIL(Foo::destroy_count() == 94);
|
||||
ASSERT_OR_FAIL(Foo::destroyed_in_order());
|
||||
|
||||
// Some elements in another block
|
||||
Foo::reset();
|
||||
{
|
||||
ReaderWriterQueue<Foo> q(31);
|
||||
for (int i = 0; i != 42; ++i) {
|
||||
q.enqueue(Foo());
|
||||
}
|
||||
for (int i = 0; i != 31; ++i) {
|
||||
ASSERT_OR_FAIL(q.try_dequeue(item));
|
||||
}
|
||||
}
|
||||
ASSERT_OR_FAIL(Foo::destroy_count() == 42);
|
||||
ASSERT_OR_FAIL(Foo::destroyed_in_order());
|
||||
|
||||
// Some elements in multiple blocks
|
||||
Foo::reset();
|
||||
{
|
||||
ReaderWriterQueue<Foo> q(31);
|
||||
for (int i = 0; i != 123; ++i) {
|
||||
q.enqueue(Foo());
|
||||
}
|
||||
for (int i = 0; i != 25; ++i) {
|
||||
ASSERT_OR_FAIL(q.try_dequeue(item));
|
||||
}
|
||||
for (int i = 0; i != 47; ++i) {
|
||||
q.enqueue(Foo());
|
||||
}
|
||||
for (int i = 0; i != 140; ++i) {
|
||||
ASSERT_OR_FAIL(q.try_dequeue(item));
|
||||
}
|
||||
for (int i = 0; i != 230; ++i) {
|
||||
q.enqueue(Foo());
|
||||
}
|
||||
for (int i = 0; i != 130; ++i) {
|
||||
ASSERT_OR_FAIL(q.try_dequeue(item));
|
||||
}
|
||||
for (int i = 0; i != 100; ++i) {
|
||||
q.enqueue(Foo());
|
||||
}
|
||||
}
|
||||
ASSERT_OR_FAIL(Foo::destroy_count() == 500);
|
||||
ASSERT_OR_FAIL(Foo::destroyed_in_order());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_enqueue()
|
||||
{
|
||||
ReaderWriterQueue<int> q(31);
|
||||
int item;
|
||||
int size = 0;
|
||||
|
||||
for (int i = 0; i < 10000; ++i) {
|
||||
if ((rand() & 1) == 1) {
|
||||
bool result = q.try_enqueue(i);
|
||||
if (size == 31) {
|
||||
ASSERT_OR_FAIL(!result);
|
||||
}
|
||||
else {
|
||||
ASSERT_OR_FAIL(result);
|
||||
++size;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bool result = q.try_dequeue(item);
|
||||
if (size == 0) {
|
||||
ASSERT_OR_FAIL(!result);
|
||||
}
|
||||
else {
|
||||
ASSERT_OR_FAIL(result);
|
||||
--size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_dequeue()
|
||||
{
|
||||
int item;
|
||||
|
||||
{
|
||||
ReaderWriterQueue<int> q(1);
|
||||
ASSERT_OR_FAIL(!q.try_dequeue(item));
|
||||
}
|
||||
|
||||
{
|
||||
ReaderWriterQueue<int, 2> q(10);
|
||||
ASSERT_OR_FAIL(!q.try_dequeue(item));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool threaded()
|
||||
{
|
||||
weak_atomic<int> result;
|
||||
result = 1;
|
||||
|
||||
ReaderWriterQueue<int> q(100);
|
||||
SimpleThread reader([&]() {
|
||||
int item;
|
||||
int prevItem = -1;
|
||||
for (int i = 0; i != 1000000; ++i) {
|
||||
if (q.try_dequeue(item)) {
|
||||
if (item <= prevItem) {
|
||||
result = 0;
|
||||
}
|
||||
prevItem = item;
|
||||
}
|
||||
}
|
||||
});
|
||||
SimpleThread writer([&]() {
|
||||
for (int i = 0; i != 1000000; ++i) {
|
||||
if (((i >> 7) & 1) == 0) {
|
||||
q.enqueue(i);
|
||||
}
|
||||
else {
|
||||
q.try_enqueue(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
writer.join();
|
||||
reader.join();
|
||||
|
||||
return result.load() == 1 ? true : false;
|
||||
}
|
||||
|
||||
bool peek()
|
||||
{
|
||||
weak_atomic<int> result;
|
||||
result = 1;
|
||||
|
||||
ReaderWriterQueue<int> q(100);
|
||||
SimpleThread reader([&]() {
|
||||
int item;
|
||||
int prevItem = -1;
|
||||
int* peeked;
|
||||
for (int i = 0; i != 100000; ++i) {
|
||||
peeked = q.peek();
|
||||
if (peeked != nullptr) {
|
||||
if (q.try_dequeue(item)) {
|
||||
if (item <= prevItem || item != *peeked) {
|
||||
result = 0;
|
||||
}
|
||||
prevItem = item;
|
||||
}
|
||||
else {
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
SimpleThread writer([&]() {
|
||||
for (int i = 0; i != 100000; ++i) {
|
||||
if (((i >> 7) & 1) == 0) {
|
||||
q.enqueue(i);
|
||||
}
|
||||
else {
|
||||
q.try_enqueue(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
writer.join();
|
||||
reader.join();
|
||||
|
||||
return result.load() == 1 ? true : false;
|
||||
}
|
||||
|
||||
bool pop()
|
||||
{
|
||||
weak_atomic<int> result;
|
||||
result = 1;
|
||||
|
||||
ReaderWriterQueue<int> q(100);
|
||||
SimpleThread reader([&]() {
|
||||
int item;
|
||||
int prevItem = -1;
|
||||
int* peeked;
|
||||
for (int i = 0; i != 100000; ++i) {
|
||||
peeked = q.peek();
|
||||
if (peeked != nullptr) {
|
||||
item = *peeked;
|
||||
if (q.pop()) {
|
||||
if (item <= prevItem) {
|
||||
result = 0;
|
||||
}
|
||||
prevItem = item;
|
||||
}
|
||||
else {
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
SimpleThread writer([&]() {
|
||||
for (int i = 0; i != 100000; ++i) {
|
||||
if (((i >> 7) & 1) == 0) {
|
||||
q.enqueue(i);
|
||||
}
|
||||
else {
|
||||
q.try_enqueue(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
writer.join();
|
||||
reader.join();
|
||||
|
||||
return result.load() == 1 ? true : false;
|
||||
}
|
||||
|
||||
bool size_approx()
|
||||
{
|
||||
weak_atomic<int> result;
|
||||
weak_atomic<int> front;
|
||||
weak_atomic<int> tail;
|
||||
|
||||
result = 1;
|
||||
front = 0;
|
||||
tail = 0;
|
||||
|
||||
ReaderWriterQueue<int> q(10);
|
||||
SimpleThread reader([&]() {
|
||||
int item;
|
||||
for (int i = 0; i != 100000; ++i) {
|
||||
if (q.try_dequeue(item)) {
|
||||
fence(memory_order_release);
|
||||
front = front.load() + 1;
|
||||
}
|
||||
int size = (int)q.size_approx();
|
||||
fence(memory_order_acquire);
|
||||
int tail_ = tail.load();
|
||||
int front_ = front.load();
|
||||
if (size > tail_ - front_ || size < 0) {
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
SimpleThread writer([&]() {
|
||||
for (int i = 0; i != 100000; ++i) {
|
||||
tail = tail.load() + 1;
|
||||
fence(memory_order_release);
|
||||
q.enqueue(i);
|
||||
int tail_ = tail.load();
|
||||
int front_ = front.load();
|
||||
fence(memory_order_acquire);
|
||||
int size = (int)q.size_approx();
|
||||
if (size > tail_ - front_ || size < 0) {
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
writer.join();
|
||||
reader.join();
|
||||
|
||||
return result.load() == 1 ? true : false;
|
||||
}
|
||||
|
||||
bool max_capacity()
|
||||
{
|
||||
{
|
||||
// this math for queue size estimation is only valid for q_size <= 256
|
||||
for (size_t q_size = 2; q_size < 256; ++q_size) {
|
||||
ReaderWriterQueue<int> q(q_size);
|
||||
ASSERT_OR_FAIL(q.max_capacity() == ceilToPow2(q_size+1)-1);
|
||||
|
||||
const size_t start_cap = q.max_capacity();
|
||||
for (size_t i = 0; i < start_cap+1; ++i) // fill 1 past capacity to resize
|
||||
q.enqueue(i);
|
||||
ASSERT_OR_FAIL(q.max_capacity() == 3*start_cap+1);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool blocking()
|
||||
{
|
||||
{
|
||||
BlockingReaderWriterQueue<int> q;
|
||||
int item;
|
||||
|
||||
q.enqueue(123);
|
||||
ASSERT_OR_FAIL(q.try_dequeue(item));
|
||||
ASSERT_OR_FAIL(item == 123);
|
||||
ASSERT_OR_FAIL(q.size_approx() == 0);
|
||||
|
||||
q.enqueue(234);
|
||||
ASSERT_OR_FAIL(q.size_approx() == 1);
|
||||
ASSERT_OR_FAIL(*q.peek() == 234);
|
||||
ASSERT_OR_FAIL(*q.peek() == 234);
|
||||
ASSERT_OR_FAIL(q.pop());
|
||||
|
||||
ASSERT_OR_FAIL(q.try_enqueue(345));
|
||||
q.wait_dequeue(item);
|
||||
ASSERT_OR_FAIL(item == 345);
|
||||
ASSERT_OR_FAIL(!q.peek());
|
||||
ASSERT_OR_FAIL(q.size_approx() == 0);
|
||||
ASSERT_OR_FAIL(!q.try_dequeue(item));
|
||||
}
|
||||
|
||||
weak_atomic<int> result;
|
||||
result = 1;
|
||||
|
||||
{
|
||||
BlockingReaderWriterQueue<int> q(100);
|
||||
SimpleThread reader([&]() {
|
||||
int item = -1;
|
||||
int prevItem = -1;
|
||||
for (int i = 0; i != 1000000; ++i) {
|
||||
q.wait_dequeue(item);
|
||||
if (item <= prevItem) {
|
||||
result = 0;
|
||||
}
|
||||
prevItem = item;
|
||||
}
|
||||
});
|
||||
SimpleThread writer([&]() {
|
||||
for (int i = 0; i != 1000000; ++i) {
|
||||
q.enqueue(i);
|
||||
}
|
||||
});
|
||||
|
||||
writer.join();
|
||||
reader.join();
|
||||
|
||||
ASSERT_OR_FAIL(q.size_approx() == 0);
|
||||
ASSERT_OR_FAIL(result.load());
|
||||
}
|
||||
|
||||
{
|
||||
BlockingReaderWriterQueue<int> q(100);
|
||||
SimpleThread reader([&]() {
|
||||
int item = -1;
|
||||
int prevItem = -1;
|
||||
for (int i = 0; i != 1000000; ++i) {
|
||||
if (!q.wait_dequeue_timed(item, 1000)) {
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
if (item <= prevItem) {
|
||||
result = 0;
|
||||
}
|
||||
prevItem = item;
|
||||
}
|
||||
});
|
||||
SimpleThread writer([&]() {
|
||||
for (int i = 0; i != 1000000; ++i) {
|
||||
q.enqueue(i);
|
||||
for (volatile int x = 0; x != 100; ++x);
|
||||
}
|
||||
});
|
||||
|
||||
writer.join();
|
||||
reader.join();
|
||||
|
||||
int item;
|
||||
ASSERT_OR_FAIL(q.size_approx() == 0);
|
||||
ASSERT_OR_FAIL(!q.wait_dequeue_timed(item, 0));
|
||||
ASSERT_OR_FAIL(!q.wait_dequeue_timed(item, 1));
|
||||
ASSERT_OR_FAIL(result.load());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vector()
|
||||
{
|
||||
{
|
||||
std::vector<ReaderWriterQueue<int>> queues;
|
||||
queues.push_back(ReaderWriterQueue<int>());
|
||||
queues.emplace_back();
|
||||
|
||||
queues[0].enqueue(1);
|
||||
queues[1].enqueue(2);
|
||||
std::swap(queues[0], queues[1]);
|
||||
|
||||
int item;
|
||||
ASSERT_OR_FAIL(queues[0].try_dequeue(item));
|
||||
ASSERT_OR_FAIL(item == 2);
|
||||
|
||||
ASSERT_OR_FAIL(queues[1].try_dequeue(item));
|
||||
ASSERT_OR_FAIL(item == 1);
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<BlockingReaderWriterQueue<int>> queues;
|
||||
queues.push_back(BlockingReaderWriterQueue<int>());
|
||||
queues.emplace_back();
|
||||
|
||||
queues[0].enqueue(1);
|
||||
queues[1].enqueue(2);
|
||||
std::swap(queues[0], queues[1]);
|
||||
|
||||
int item;
|
||||
ASSERT_OR_FAIL(queues[0].try_dequeue(item));
|
||||
ASSERT_OR_FAIL(item == 2);
|
||||
|
||||
queues[1].wait_dequeue(item);
|
||||
ASSERT_OR_FAIL(item == 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if MOODYCAMEL_HAS_EMPLACE
|
||||
bool emplace()
|
||||
{
|
||||
ReaderWriterQueue<UniquePtrWrapper> q(100);
|
||||
std::unique_ptr<int> p { new int(123) };
|
||||
q.emplace(std::move(p));
|
||||
UniquePtrWrapper item;
|
||||
ASSERT_OR_FAIL(q.try_dequeue(item));
|
||||
ASSERT_OR_FAIL(item.get_value() == 123);
|
||||
ASSERT_OR_FAIL(q.size_approx() == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is what you have to do to try_enqueue() a movable type, and demonstrates why try_emplace() is useful
|
||||
bool try_enqueue_fail_workaround()
|
||||
{
|
||||
ReaderWriterQueue<UniquePtrWrapper> q(0);
|
||||
{
|
||||
// A failed try_enqueue() will still delete p
|
||||
std::unique_ptr<int> p { new int(123) };
|
||||
q.try_enqueue(std::move(p));
|
||||
ASSERT_OR_FAIL(q.size_approx() == 0);
|
||||
ASSERT_OR_FAIL(p == nullptr);
|
||||
}
|
||||
{
|
||||
// Workaround isn't pretty and potentially expensive - use try_emplace() instead
|
||||
std::unique_ptr<int> p { new int(123) };
|
||||
UniquePtrWrapper w(std::move(p));
|
||||
q.try_enqueue(std::move(w));
|
||||
p = std::move(w.get_ptr());
|
||||
ASSERT_OR_FAIL(q.size_approx() == 0);
|
||||
ASSERT_OR_FAIL(p != nullptr);
|
||||
ASSERT_OR_FAIL(*p == 123);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_emplace_fail()
|
||||
{
|
||||
ReaderWriterQueue<UniquePtrWrapper> q(0);
|
||||
std::unique_ptr<int> p { new int(123) };
|
||||
q.try_emplace(std::move(p));
|
||||
ASSERT_OR_FAIL(q.size_approx() == 0);
|
||||
ASSERT_OR_FAIL(p != nullptr);
|
||||
ASSERT_OR_FAIL(*p == 123);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
void printTests(ReaderWriterQueueTests const& tests)
|
||||
{
|
||||
std::printf(" Supported tests are:\n");
|
||||
|
||||
std::vector<std::string> names;
|
||||
tests.getAllTestNames(names);
|
||||
for (auto it = names.cbegin(); it != names.cend(); ++it) {
|
||||
std::printf(" %s\n", it->c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Basic test harness
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
bool disablePrompt = false;
|
||||
std::vector<std::string> selectedTests;
|
||||
|
||||
// Disable buffering (so that when run in, e.g., Sublime Text, the output appears as it is written)
|
||||
std::setvbuf(stdout, nullptr, _IONBF, 0);
|
||||
|
||||
// Isolate the executable name
|
||||
std::string progName = argv[0];
|
||||
auto slash = progName.find_last_of("/\\");
|
||||
if (slash != std::string::npos) {
|
||||
progName = progName.substr(slash + 1);
|
||||
}
|
||||
|
||||
ReaderWriterQueueTests tests;
|
||||
|
||||
// Parse command line options
|
||||
if (argc == 1) {
|
||||
std::printf("Running all unit tests for moodycamel::ReaderWriterQueue.\n(Run %s --help for other options.)\n\n", progName.c_str());
|
||||
}
|
||||
else {
|
||||
bool printHelp = false;
|
||||
bool printedTests = false;
|
||||
bool error = false;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (std::strcmp(argv[i], "--help") == 0) {
|
||||
printHelp = true;
|
||||
}
|
||||
else if (std::strcmp(argv[i], "--disable-prompt") == 0) {
|
||||
disablePrompt = true;
|
||||
}
|
||||
else if (std::strcmp(argv[i], "--run") == 0) {
|
||||
if (i + 1 == argc || argv[i + 1][0] == '-') {
|
||||
std::printf("Expected test name argument for --run option.\n");
|
||||
if (!printedTests) {
|
||||
printTests(tests);
|
||||
printedTests = true;
|
||||
}
|
||||
error = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!tests.validateTestName(argv[++i])) {
|
||||
std::printf("Unrecognized test '%s'.\n", argv[i]);
|
||||
if (!printedTests) {
|
||||
printTests(tests);
|
||||
printedTests = true;
|
||||
}
|
||||
error = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
selectedTests.push_back(argv[i]);
|
||||
}
|
||||
else {
|
||||
std::printf("Unrecognized option '%s'.\n", argv[i]);
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (error || printHelp) {
|
||||
if (error) {
|
||||
std::printf("\n");
|
||||
}
|
||||
std::printf("%s\n Description: Runs unit tests for moodycamel::ReaderWriterQueue\n", progName.c_str());
|
||||
std::printf(" --help Prints this help blurb\n");
|
||||
std::printf(" --run test Runs only the specified test(s)\n");
|
||||
std::printf(" --disable-prompt Disables prompt before exit when the tests finish\n");
|
||||
return error ? -1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int exitCode = 0;
|
||||
|
||||
bool result;
|
||||
if (selectedTests.size() > 0) {
|
||||
result = tests.run(selectedTests);
|
||||
}
|
||||
else {
|
||||
result = tests.run();
|
||||
}
|
||||
|
||||
if (result) {
|
||||
std::printf("All %stests passed.\n", (selectedTests.size() > 0 ? "selected " : ""));
|
||||
}
|
||||
else {
|
||||
std::printf("Test(s) failed!\n");
|
||||
exitCode = 2;
|
||||
}
|
||||
|
||||
if (!disablePrompt) {
|
||||
std::printf("Press ENTER to exit.\n");
|
||||
getchar();
|
||||
}
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user