Add ReaderWriterQueue and update ConcurrentQueue

This commit is contained in:
Paul Hollinsky
2020-03-09 13:38:14 -04:00
parent 9ac3fd56bd
commit 42780dc610
1629 changed files with 306008 additions and 868 deletions
@@ -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;
};
@@ -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
@@ -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>
@@ -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,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
@@ -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>
@@ -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;
}