Khara0 1 month ago
parent d04dfef198
commit 1239070d34

Binary file not shown.

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

@ -0,0 +1,253 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# Local build files
*c.cmd
*a.exe
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
[Xx]64/
[Xx]86/
[Bb]uild/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
# Visual Studio Code
.vscode/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Un-comment the next line if you do not want to checkin
# your web deploy settings because they may include unencrypted
# passwords
#*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Microsoft Azure ApplicationInsights config file
ApplicationInsights.config
# Windows Store app package directory
AppPackages/
BundleArtifacts/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# LightSwitch generated files
GeneratedArtifacts/
ModelManifest.xml
# Paket dependency manager
.paket/paket.exe
# FAKE - F# Make
.fake/

@ -0,0 +1,72 @@
language: cpp
# ubuntu 14.04 version
sudo: required
dist: trusty
matrix:
include:
- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5']
env:
- MATRIX_EVAL="CC=gcc-5 && CXX=g++-5"
- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6']
env:
- MATRIX_EVAL="CC=gcc-6 && CXX=g++-6"
- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-7']
env:
- MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
- os: osx
osx_image: xcode5
env:
- MATRIX_EVAL="CC=clang && CXX=clang++"
- os: osx
osx_image: xcode6
env:
- MATRIX_EVAL="CC=clang && CXX=clang++"
- os: osx
osx_image: xcode7
env:
- MATRIX_EVAL="CC=clang && CXX=clang++"
- os: osx
osx_image: xcode8
env:
- MATRIX_EVAL="CC=clang && CXX=clang++"
before_script:
- eval "${MATRIX_EVAL}"
- $CXX --version
script:
- mkdir build && cd ./build
- cmake ..
- make
- cd ../bin && ./stltest
branches:
only:
- master
notifications:
email: false

@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 2.8)
project(MyTinySTL)
# version
set(MyTinySTL_VERSION_MAJOR 2)
set(MyTinySTL_VERSION_MINOR 0)
set(MyTinySTL_VERSION_PATCH 0)
set(MyTinySTL_VERSION "${MyTinySTL_VERSION_MAJOR}.${MyTinySTL_VERSION_MINOR}.${MyTinySTL_VERSION_PATCH}")
message(STATUS "The version of this project is: ${MyTinySTL_VERSION}")
# build type
set(CMAKE_BUILD_TYPE release)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall -Wextra -Wno-sign-compare -Wno-unused-but-set-variable -Wno-array-bounds")
# set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wsign-conversion)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0.0")
message(FATAL_ERROR "required GCC 5.0 or later")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall -Wextra -Wno-sign-compare")
# set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wimplicit-fallthrough)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "3.5.0")
message(FATAL_ERROR "required Clang 3.5 or later")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
endif()
message(STATUS "The cmake_cxx_flags is: ${CMAKE_CXX_FLAGS}")
add_subdirectory(${PROJECT_SOURCE_DIR}/Test)

@ -0,0 +1,11 @@
Copyright (c) 2016-2017 Alinshans. All rights reserved.
First published on github, see https://github.com/Alinshans/MyTinySTL
The MyTinySTL source code is licensed under the MIT License.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -0,0 +1,28 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyTinySTL", "MyTinySTL_VS2015.vcxproj", "{E88807F6-B07C-4371-BD38-FB1569F894E4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E88807F6-B07C-4371-BD38-FB1569F894E4}.Debug|x64.ActiveCfg = Debug|x64
{E88807F6-B07C-4371-BD38-FB1569F894E4}.Debug|x64.Build.0 = Debug|x64
{E88807F6-B07C-4371-BD38-FB1569F894E4}.Debug|x86.ActiveCfg = Debug|Win32
{E88807F6-B07C-4371-BD38-FB1569F894E4}.Debug|x86.Build.0 = Debug|Win32
{E88807F6-B07C-4371-BD38-FB1569F894E4}.Release|x64.ActiveCfg = Release|x64
{E88807F6-B07C-4371-BD38-FB1569F894E4}.Release|x64.Build.0 = Release|x64
{E88807F6-B07C-4371-BD38-FB1569F894E4}.Release|x86.ActiveCfg = Release|Win32
{E88807F6-B07C-4371-BD38-FB1569F894E4}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

@ -0,0 +1,201 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.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="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{E88807F6-B07C-4371-BD38-FB1569F894E4}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>MyTinySTL</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<ProjectName>MyTinySTL</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</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 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 Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<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|x64'">
<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>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</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>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\Test\algorithm_performance_test.h" />
<ClInclude Include="..\Test\algorithm_test.h" />
<ClInclude Include="..\Test\deque_test.h" />
<ClInclude Include="..\Test\Lib\redbud\io\color.h" />
<ClInclude Include="..\Test\Lib\redbud\platform.h" />
<ClInclude Include="..\Test\list_test.h" />
<ClInclude Include="..\Test\map_test.h" />
<ClInclude Include="..\Test\queue_test.h" />
<ClInclude Include="..\Test\set_test.h" />
<ClInclude Include="..\Test\stack_test.h" />
<ClInclude Include="..\Test\string_test.h" />
<ClInclude Include="..\Test\test.h" />
<ClInclude Include="..\Test\unordered_map_test.h" />
<ClInclude Include="..\Test\unordered_set_test.h" />
<ClInclude Include="..\Test\vector_test.h" />
<ClInclude Include="..\MyTinySTL\algo.h" />
<ClInclude Include="..\MyTinySTL\algobase.h" />
<ClInclude Include="..\MyTinySTL\algorithm.h" />
<ClInclude Include="..\MyTinySTL\alloc.h" />
<ClInclude Include="..\MyTinySTL\allocator.h" />
<ClInclude Include="..\MyTinySTL\basic_string.h" />
<ClInclude Include="..\MyTinySTL\construct.h" />
<ClInclude Include="..\MyTinySTL\deque.h" />
<ClInclude Include="..\MyTinySTL\exceptdef.h" />
<ClInclude Include="..\MyTinySTL\functional.h" />
<ClInclude Include="..\MyTinySTL\hashtable.h" />
<ClInclude Include="..\MyTinySTL\unordered_map.h" />
<ClInclude Include="..\MyTinySTL\unordered_set.h" />
<ClInclude Include="..\MyTinySTL\heap_algo.h" />
<ClInclude Include="..\MyTinySTL\iterator.h" />
<ClInclude Include="..\MyTinySTL\list.h" />
<ClInclude Include="..\MyTinySTL\map.h" />
<ClInclude Include="..\MyTinySTL\memory.h" />
<ClInclude Include="..\MyTinySTL\numeric.h" />
<ClInclude Include="..\MyTinySTL\queue.h" />
<ClInclude Include="..\MyTinySTL\rb_tree.h" />
<ClInclude Include="..\MyTinySTL\set.h" />
<ClInclude Include="..\MyTinySTL\set_algo.h" />
<ClInclude Include="..\MyTinySTL\stack.h" />
<ClInclude Include="..\MyTinySTL\astring.h" />
<ClInclude Include="..\MyTinySTL\type_traits.h" />
<ClInclude Include="..\MyTinySTL\uninitialized.h" />
<ClInclude Include="..\MyTinySTL\util.h" />
<ClInclude Include="..\MyTinySTL\vector.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Test\test.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,162 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="资源文件">
<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>
<Filter Include="include">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="source">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="test">
<UniqueIdentifier>{ec314ff3-dcde-4cac-a63a-4f6827750d0a}</UniqueIdentifier>
</Filter>
<Filter Include="test\Lib">
<UniqueIdentifier>{c6f24d77-e6f0-439e-954a-c0ca577689d5}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\MyTinySTL\type_traits.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\construct.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\alloc.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\allocator.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\uninitialized.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\iterator.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\numeric.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\algobase.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\heap_algo.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\set_algo.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\algo.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\algorithm.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\vector.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\memory.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\list.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\deque.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\stack.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\queue.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\functional.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\rb_tree.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\set.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\map.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\hashtable.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\basic_string.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\unordered_set.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\unordered_map.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\Test\algorithm_performance_test.h">
<Filter>test</Filter>
</ClInclude>
<ClInclude Include="..\Test\algorithm_test.h">
<Filter>test</Filter>
</ClInclude>
<ClInclude Include="..\Test\deque_test.h">
<Filter>test</Filter>
</ClInclude>
<ClInclude Include="..\Test\list_test.h">
<Filter>test</Filter>
</ClInclude>
<ClInclude Include="..\Test\map_test.h">
<Filter>test</Filter>
</ClInclude>
<ClInclude Include="..\Test\queue_test.h">
<Filter>test</Filter>
</ClInclude>
<ClInclude Include="..\Test\set_test.h">
<Filter>test</Filter>
</ClInclude>
<ClInclude Include="..\Test\stack_test.h">
<Filter>test</Filter>
</ClInclude>
<ClInclude Include="..\Test\string_test.h">
<Filter>test</Filter>
</ClInclude>
<ClInclude Include="..\Test\test.h">
<Filter>test</Filter>
</ClInclude>
<ClInclude Include="..\Test\unordered_map_test.h">
<Filter>test</Filter>
</ClInclude>
<ClInclude Include="..\Test\unordered_set_test.h">
<Filter>test</Filter>
</ClInclude>
<ClInclude Include="..\Test\vector_test.h">
<Filter>test</Filter>
</ClInclude>
<ClInclude Include="..\Test\Lib\redbud\platform.h">
<Filter>test\Lib</Filter>
</ClInclude>
<ClInclude Include="..\Test\Lib\redbud\io\color.h">
<Filter>test\Lib</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\astring.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\util.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\MyTinySTL\exceptdef.h">
<Filter>include</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Test\test.cpp">
<Filter>test</Filter>
</ClCompile>
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,520 @@
#ifndef MYTINYSTL_ALGOBASE_H_
#define MYTINYSTL_ALGOBASE_H_
// 这个头文件包含了 mystl 的基本算法
#include <cstring>
#include "iterator.h"
#include "util.h"
namespace mystl
{
#ifdef max
#pragma message("#undefing marco max")
#undef max
#endif // max
#ifdef min
#pragma message("#undefing marco min")
#undef min
#endif // min
/*****************************************************************************************/
// max
// 取二者中的较大值,语义相等时保证返回第一个参数
/*****************************************************************************************/
template <class T>
const T& max(const T& lhs, const T& rhs)
{
return lhs < rhs ? rhs : lhs;
}
// 重载版本使用函数对象 comp 代替比较操作
template <class T, class Compare>
const T& max(const T& lhs, const T& rhs, Compare comp)
{
return comp(lhs, rhs) ? rhs : lhs;
}
/*****************************************************************************************/
// min
// 取二者中的较小值,语义相等时保证返回第一个参数
/*****************************************************************************************/
template <class T>
const T& min(const T& lhs, const T& rhs)
{
return rhs < lhs ? rhs : lhs;
}
// 重载版本使用函数对象 comp 代替比较操作
template <class T, class Compare>
const T& min(const T& lhs, const T& rhs, Compare comp)
{
return comp(rhs, lhs) ? rhs : lhs;
}
/*****************************************************************************************/
// iter_swap
// 将两个迭代器所指对象对调
/*****************************************************************************************/
template <class FIter1, class FIter2>
void iter_swap(FIter1 lhs, FIter2 rhs)
{
mystl::swap(*lhs, *rhs);
}
/*****************************************************************************************/
// copy
// 把 [first, last)区间内的元素拷贝到 [result, result + (last - first))内
/*****************************************************************************************/
// input_iterator_tag 版本
template <class InputIter, class OutputIter>
OutputIter
unchecked_copy_cat(InputIter first, InputIter last, OutputIter result,
mystl::input_iterator_tag)
{
for (; first != last; ++first, ++result)
{
*result = *first;
}
return result;
}
// ramdom_access_iterator_tag 版本
template <class RandomIter, class OutputIter>
OutputIter
unchecked_copy_cat(RandomIter first, RandomIter last, OutputIter result,
mystl::random_access_iterator_tag)
{
for (auto n = last - first; n > 0; --n, ++first, ++result)
{
*result = *first;
}
return result;
}
template <class InputIter, class OutputIter>
OutputIter
unchecked_copy(InputIter first, InputIter last, OutputIter result)
{
return unchecked_copy_cat(first, last, result, iterator_category(first));
}
// 为 trivially_copy_assignable 类型提供特化版本
template <class Tp, class Up>
typename std::enable_if<
std::is_same<typename std::remove_const<Tp>::type, Up>::value &&
std::is_trivially_copy_assignable<Up>::value,
Up*>::type
unchecked_copy(Tp* first, Tp* last, Up* result)
{
const auto n = static_cast<size_t>(last - first);
if (n != 0)
std::memmove(result, first, n * sizeof(Up));
return result + n;
}
template <class InputIter, class OutputIter>
OutputIter copy(InputIter first, InputIter last, OutputIter result)
{
return unchecked_copy(first, last, result);
}
/*****************************************************************************************/
// copy_backward
// 将 [first, last)区间内的元素拷贝到 [result - (last - first), result)内
/*****************************************************************************************/
// unchecked_copy_backward_cat 的 bidirectional_iterator_tag 版本
template <class BidirectionalIter1, class BidirectionalIter2>
BidirectionalIter2
unchecked_copy_backward_cat(BidirectionalIter1 first, BidirectionalIter1 last,
BidirectionalIter2 result, mystl::bidirectional_iterator_tag)
{
while (first != last)
*--result = *--last;
return result;
}
// unchecked_copy_backward_cat 的 random_access_iterator_tag 版本
template <class RandomIter1, class BidirectionalIter2>
BidirectionalIter2
unchecked_copy_backward_cat(RandomIter1 first, RandomIter1 last,
BidirectionalIter2 result, mystl::random_access_iterator_tag)
{
for (auto n = last - first; n > 0; --n)
*--result = *--last;
return result;
}
template <class BidirectionalIter1, class BidirectionalIter2>
BidirectionalIter2
unchecked_copy_backward(BidirectionalIter1 first, BidirectionalIter1 last,
BidirectionalIter2 result)
{
return unchecked_copy_backward_cat(first, last, result,
iterator_category(first));
}
// 为 trivially_copy_assignable 类型提供特化版本
template <class Tp, class Up>
typename std::enable_if<
std::is_same<typename std::remove_const<Tp>::type, Up>::value &&
std::is_trivially_copy_assignable<Up>::value,
Up*>::type
unchecked_copy_backward(Tp* first, Tp* last, Up* result)
{
const auto n = static_cast<size_t>(last - first);
if (n != 0)
{
result -= n;
std::memmove(result, first, n * sizeof(Up));
}
return result;
}
template <class BidirectionalIter1, class BidirectionalIter2>
BidirectionalIter2
copy_backward(BidirectionalIter1 first, BidirectionalIter1 last, BidirectionalIter2 result)
{
return unchecked_copy_backward(first, last, result);
}
/*****************************************************************************************/
// copy_if
// 把[first, last)内满足一元操作 unary_pred 的元素拷贝到以 result 为起始的位置上
/*****************************************************************************************/
template <class InputIter, class OutputIter, class UnaryPredicate>
OutputIter
copy_if(InputIter first, InputIter last, OutputIter result, UnaryPredicate unary_pred)
{
for (; first != last; ++first)
{
if (unary_pred(*first))
*result++ = *first;
}
return result;
}
/*****************************************************************************************/
// copy_n
// 把 [first, first + n)区间上的元素拷贝到 [result, result + n)上
// 返回一个 pair 分别指向拷贝结束的尾部
/*****************************************************************************************/
template <class InputIter, class Size, class OutputIter>
mystl::pair<InputIter, OutputIter>
unchecked_copy_n(InputIter first, Size n, OutputIter result, mystl::input_iterator_tag)
{
for (; n > 0; --n, ++first, ++result)
{
*result = *first;
}
return mystl::pair<InputIter, OutputIter>(first, result);
}
template <class RandomIter, class Size, class OutputIter>
mystl::pair<RandomIter, OutputIter>
unchecked_copy_n(RandomIter first, Size n, OutputIter result,
mystl::random_access_iterator_tag)
{
auto last = first + n;
return mystl::pair<RandomIter, OutputIter>(last, mystl::copy(first, last, result));
}
template <class InputIter, class Size, class OutputIter>
mystl::pair<InputIter, OutputIter>
copy_n(InputIter first, Size n, OutputIter result)
{
return unchecked_copy_n(first, n, result, iterator_category(first));
}
/*****************************************************************************************/
// move
// 把 [first, last)区间内的元素移动到 [result, result + (last - first))内
/*****************************************************************************************/
// input_iterator_tag 版本
template <class InputIter, class OutputIter>
OutputIter
unchecked_move_cat(InputIter first, InputIter last, OutputIter result,
mystl::input_iterator_tag)
{
for (; first != last; ++first, ++result)
{
*result = mystl::move(*first);
}
return result;
}
// ramdom_access_iterator_tag 版本
template <class RandomIter, class OutputIter>
OutputIter
unchecked_move_cat(RandomIter first, RandomIter last, OutputIter result,
mystl::random_access_iterator_tag)
{
for (auto n = last - first; n > 0; --n, ++first, ++result)
{
*result = mystl::move(*first);
}
return result;
}
template <class InputIter, class OutputIter>
OutputIter
unchecked_move(InputIter first, InputIter last, OutputIter result)
{
return unchecked_move_cat(first, last, result, iterator_category(first));
}
// 为 trivially_copy_assignable 类型提供特化版本
template <class Tp, class Up>
typename std::enable_if<
std::is_same<typename std::remove_const<Tp>::type, Up>::value &&
std::is_trivially_move_assignable<Up>::value,
Up*>::type
unchecked_move(Tp* first, Tp* last, Up* result)
{
const size_t n = static_cast<size_t>(last - first);
if (n != 0)
std::memmove(result, first, n * sizeof(Up));
return result + n;
}
template <class InputIter, class OutputIter>
OutputIter move(InputIter first, InputIter last, OutputIter result)
{
return unchecked_move(first, last, result);
}
/*****************************************************************************************/
// move_backward
// 将 [first, last)区间内的元素移动到 [result - (last - first), result)内
/*****************************************************************************************/
// bidirectional_iterator_tag 版本
template <class BidirectionalIter1, class BidirectionalIter2>
BidirectionalIter2
unchecked_move_backward_cat(BidirectionalIter1 first, BidirectionalIter1 last,
BidirectionalIter2 result, mystl::bidirectional_iterator_tag)
{
while (first != last)
*--result = mystl::move(*--last);
return result;
}
// random_access_iterator_tag 版本
template <class RandomIter1, class RandomIter2>
RandomIter2
unchecked_move_backward_cat(RandomIter1 first, RandomIter1 last,
RandomIter2 result, mystl::random_access_iterator_tag)
{
for (auto n = last - first; n > 0; --n)
*--result = mystl::move(*--last);
return result;
}
template <class BidirectionalIter1, class BidirectionalIter2>
BidirectionalIter2
unchecked_move_backward(BidirectionalIter1 first, BidirectionalIter1 last,
BidirectionalIter2 result)
{
return unchecked_move_backward_cat(first, last, result,
iterator_category(first));
}
// 为 trivially_copy_assignable 类型提供特化版本
template <class Tp, class Up>
typename std::enable_if<
std::is_same<typename std::remove_const<Tp>::type, Up>::value &&
std::is_trivially_move_assignable<Up>::value,
Up*>::type
unchecked_move_backward(Tp* first, Tp* last, Up* result)
{
const size_t n = static_cast<size_t>(last - first);
if (n != 0)
{
result -= n;
std::memmove(result, first, n * sizeof(Up));
}
return result;
}
template <class BidirectionalIter1, class BidirectionalIter2>
BidirectionalIter2
move_backward(BidirectionalIter1 first, BidirectionalIter1 last, BidirectionalIter2 result)
{
return unchecked_move_backward(first, last, result);
}
/*****************************************************************************************/
// equal
// 比较第一序列在 [first, last)区间上的元素值是否和第二序列相等
/*****************************************************************************************/
template <class InputIter1, class InputIter2>
bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2)
{
for (; first1 != last1; ++first1, ++first2)
{
if (*first1 != *first2)
return false;
}
return true;
}
// 重载版本使用函数对象 comp 代替比较操作
template <class InputIter1, class InputIter2, class Compared>
bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2, Compared comp)
{
for (; first1 != last1; ++first1, ++first2)
{
if (!comp(*first1, *first2))
return false;
}
return true;
}
/*****************************************************************************************/
// fill_n
// 从 first 位置开始填充 n 个值
/*****************************************************************************************/
template <class OutputIter, class Size, class T>
OutputIter unchecked_fill_n(OutputIter first, Size n, const T& value)
{
for (; n > 0; --n, ++first)
{
*first = value;
}
return first;
}
// 为 one-byte 类型提供特化版本
template <class Tp, class Size, class Up>
typename std::enable_if<
std::is_integral<Tp>::value && sizeof(Tp) == 1 &&
!std::is_same<Tp, bool>::value &&
std::is_integral<Up>::value && sizeof(Up) == 1,
Tp*>::type
unchecked_fill_n(Tp* first, Size n, Up value)
{
if (n > 0)
{
std::memset(first, (unsigned char)value, (size_t)(n));
}
return first + n;
}
template <class OutputIter, class Size, class T>
OutputIter fill_n(OutputIter first, Size n, const T& value)
{
return unchecked_fill_n(first, n, value);
}
/*****************************************************************************************/
// fill
// 为 [first, last)区间内的所有元素填充新值
/*****************************************************************************************/
template <class ForwardIter, class T>
void fill_cat(ForwardIter first, ForwardIter last, const T& value,
mystl::forward_iterator_tag)
{
for (; first != last; ++first)
{
*first = value;
}
}
template <class RandomIter, class T>
void fill_cat(RandomIter first, RandomIter last, const T& value,
mystl::random_access_iterator_tag)
{
fill_n(first, last - first, value);
}
template <class ForwardIter, class T>
void fill(ForwardIter first, ForwardIter last, const T& value)
{
fill_cat(first, last, value, iterator_category(first));
}
/*****************************************************************************************/
// lexicographical_compare
// 以字典序排列对两个序列进行比较,当在某个位置发现第一组不相等元素时,有下列几种情况:
// (1)如果第一序列的元素较小,返回 true ,否则返回 false
// (2)如果到达 last1 而尚未到达 last2 返回 true
// (3)如果到达 last2 而尚未到达 last1 返回 false
// (4)如果同时到达 last1 和 last2 返回 false
/*****************************************************************************************/
template <class InputIter1, class InputIter2>
bool lexicographical_compare(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2)
{
for (; first1 != last1 && first2 != last2; ++first1, ++first2)
{
if (*first1 < *first2)
return true;
if (*first2 < *first1)
return false;
}
return first1 == last1 && first2 != last2;
}
// 重载版本使用函数对象 comp 代替比较操作
template <class InputIter1, class InputIter2, class Compred>
bool lexicographical_compare(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2, Compred comp)
{
for (; first1 != last1 && first2 != last2; ++first1, ++first2)
{
if (comp(*first1, *first2))
return true;
if (comp(*first2, *first1))
return false;
}
return first1 == last1 && first2 != last2;
}
// 针对 const unsigned char* 的特化版本
bool lexicographical_compare(const unsigned char* first1,
const unsigned char* last1,
const unsigned char* first2,
const unsigned char* last2)
{
const auto len1 = last1 - first1;
const auto len2 = last2 - first2;
// 先比较相同长度的部分
const auto result = std::memcmp(first1, first2, mystl::min(len1, len2));
// 若相等,长度较长的比较大
return result != 0 ? result < 0 : len1 < len2;
}
/*****************************************************************************************/
// mismatch
// 平行比较两个序列,找到第一处失配的元素,返回一对迭代器,分别指向两个序列中失配的元素
/*****************************************************************************************/
template <class InputIter1, class InputIter2>
mystl::pair<InputIter1, InputIter2>
mismatch(InputIter1 first1, InputIter1 last1, InputIter2 first2)
{
while (first1 != last1 && *first1 == *first2)
{
++first1;
++first2;
}
return mystl::pair<InputIter1, InputIter2>(first1, first2);
}
// 重载版本使用函数对象 comp 代替比较操作
template <class InputIter1, class InputIter2, class Compred>
mystl::pair<InputIter1, InputIter2>
mismatch(InputIter1 first1, InputIter1 last1, InputIter2 first2, Compred comp)
{
while (first1 != last1 && comp(*first1, *first2))
{
++first1;
++first2;
}
return mystl::pair<InputIter1, InputIter2>(first1, first2);
}
} // namespace mystl
#endif // !MYTINYSTL_ALGOBASE_H_

@ -0,0 +1,18 @@
#ifndef MYTINYSTL_ALGORITHM_H_
#define MYTINYSTL_ALGORITHM_H_
// 这个头文件包含了 mystl 的所有算法包括基本算法数值算法heap 算法set 算法和其他算法
#include "algobase.h"
#include "algo.h"
#include "set_algo.h"
#include "heap_algo.h"
#include "numeric.h"
namespace mystl
{
} // namespace mystl
#endif // !MYTINYSTL_ALGORITHM_H_

@ -0,0 +1,264 @@
#ifndef MYTINYSTL_ALLOC_H_
#define MYTINYSTL_ALLOC_H_
// 这个头文件包含一个类 alloc用于分配和回收内存以内存池的方式实现
//
// 从 v2.0.0 版本开始,将不再使用内存池,这个文件将被弃用,但暂时保留
//
// 注意!!!
// 我知道这个文件里很多实现是错的,这是很久很久前写的了,后面已经不用这个东西了,
// 所以我也没再维护有诸多问题已经有人在issue中都提了free_list的修改
// 指针作为参数时没实际修改到原指针,等等。相信会看这么仔细的,大部分都是
// 初学C++的朋友,大佬都不会看这些玩具了,所以其中的错误,就留给对内存池实现
// 感兴趣的朋友去修改啦!
#include <new>
#include <cstddef>
#include <cstdio>
namespace mystl
{
// 共用体: FreeList
// 采用链表的方式管理内存碎片,分配与回收小内存(<=4K区块
union FreeList
{
union FreeList* next; // 指向下一个区块
char data[1]; // 储存本块内存的首地址
};
// 不同内存范围的上调大小
enum
{
EAlign128 = 8,
EAlign256 = 16,
EAlign512 = 32,
EAlign1024 = 64,
EAlign2048 = 128,
EAlign4096 = 256
};
// 小对象的内存大小
enum { ESmallObjectBytes = 4096 };
// free lists 个数
enum { EFreeListsNumber = 56 };
// 空间配置类 alloc
// 如果内存较大,超过 4096 bytes直接调用 std::malloc, std::free
// 当内存较小时,以内存池管理,每次配置一大块内存,并维护对应的自由链表
class alloc
{
private:
static char* start_free; // 内存池起始位置
static char* end_free; // 内存池结束位置
static size_t heap_size; // 申请 heap 空间附加值大小
static FreeList* free_list[EFreeListsNumber]; // 自由链表
public:
static void* allocate(size_t n);
static void deallocate(void* p, size_t n);
static void* reallocate(void* p, size_t old_size, size_t new_size);
private:
static size_t M_align(size_t bytes);
static size_t M_round_up(size_t bytes);
static size_t M_freelist_index(size_t bytes);
static void* M_refill(size_t n);
static char* M_chunk_alloc(size_t size, size_t &nobj);
};
// 静态成员变量初始化
char* alloc::start_free = nullptr;
char* alloc::end_free = nullptr;
size_t alloc::heap_size = 0;
FreeList* alloc::free_list[EFreeListsNumber] = {
nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,
nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,
nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,
nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,
nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,
nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,
nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr
};
// 分配大小为 n 的空间, n > 0
inline void* alloc::allocate(size_t n)
{
FreeList* my_free_list;
FreeList* result;
if (n > static_cast<size_t>(ESmallObjectBytes))
return std::malloc(n);
my_free_list = free_list[M_freelist_index(n)];
result = my_free_list;
if (result == nullptr)
{
void* r = M_refill(M_round_up(n));
return r;
}
my_free_list = result->next;
return result;
}
// 释放 p 指向的大小为 n 的空间, p 不能为 0
inline void alloc::deallocate(void* p, size_t n)
{
if (n > static_cast<size_t>(ESmallObjectBytes))
{
std::free(p);
return;
}
FreeList* q = reinterpret_cast<FreeList*>(p);
FreeList* my_free_list;
my_free_list = free_list[M_freelist_index(n)];
q->next = my_free_list;
my_free_list = q;
}
// 重新分配空间,接受三个参数,参数一为指向新空间的指针,参数二为原来空间的大小,参数三为申请空间的大小
inline void* alloc::reallocate(void* p, size_t old_size, size_t new_size)
{
deallocate(p, old_size);
p = allocate(new_size);
return p;
}
// bytes 对应上调大小
inline size_t alloc::M_align(size_t bytes)
{
if (bytes <= 512)
{
return bytes <= 256
? bytes <= 128 ? EAlign128 : EAlign256
: EAlign512;
}
return bytes <= 2048
? bytes <= 1024 ? EAlign1024 : EAlign2048
: EAlign4096;
}
// 将 bytes 上调至对应区间大小
inline size_t alloc::M_round_up(size_t bytes)
{
return ((bytes + M_align(bytes) - 1) & ~(M_align(bytes) - 1));
}
// 根据区块大小,选择第 n 个 free lists
inline size_t alloc::M_freelist_index(size_t bytes)
{
if (bytes <= 512)
{
return bytes <= 256
? bytes <= 128
? ((bytes + EAlign128 - 1) / EAlign128 - 1)
: (15 + (bytes + EAlign256 - 129) / EAlign256)
: (23 + (bytes + EAlign512 - 257) / EAlign512);
}
return bytes <= 2048
? bytes <= 1024
? (31 + (bytes + EAlign1024 - 513) / EAlign1024)
: (39 + (bytes + EAlign2048 - 1025) / EAlign2048)
: (47 + (bytes + EAlign4096 - 2049) / EAlign4096);
}
// 重新填充 free list
void* alloc::M_refill(size_t n)
{
size_t nblock = 10;
char* c = M_chunk_alloc(n, nblock);
FreeList* my_free_list;
FreeList* result, *cur, *next;
// 如果只有一个区块就把这个区块返回给调用者free list 没有增加新节点
if (nblock == 1)
return c;
// 否则把一个区块给调用者,剩下的纳入 free list 作为新节点
my_free_list = free_list[M_freelist_index(n)];
result = (FreeList*)c;
my_free_list = next = (FreeList*)(c + n);
for (size_t i = 1; ; ++i)
{
cur = next;
next = (FreeList*)((char*)next + n);
if (nblock - 1 == i)
{
cur->next = nullptr;
break;
}
else
{
cur->next = next;
}
}
return result;
}
// 从内存池中取空间给 free list 使用,条件不允许时,会调整 nblock
char* alloc::M_chunk_alloc(size_t size, size_t& nblock)
{
char* result;
size_t need_bytes = size * nblock;
size_t pool_bytes = end_free - start_free;
// 如果内存池剩余大小完全满足需求量,返回它
if (pool_bytes >= need_bytes)
{
result = start_free;
start_free += need_bytes;
return result;
}
// 如果内存池剩余大小不能完全满足需求量,但至少可以分配一个或一个以上的区块,就返回它
else if (pool_bytes >= size)
{
nblock = pool_bytes / size;
need_bytes = size * nblock;
result = start_free;
start_free += need_bytes;
return result;
}
// 如果内存池剩余大小连一个区块都无法满足
else
{
if (pool_bytes > 0)
{ // 如果内存池还有剩余,把剩余的空间加入到 free list 中
FreeList* my_free_list = free_list[M_freelist_index(pool_bytes)];
((FreeList*)start_free)->next = my_free_list;
my_free_list = (FreeList*)start_free;
}
// 申请 heap 空间
size_t bytes_to_get = (need_bytes << 1) + M_round_up(heap_size >> 4);
start_free = (char*)std::malloc(bytes_to_get);
if (!start_free)
{ // heap 空间也不够
FreeList* my_free_list, *p;
// 试着查找有无未用区块,且区块足够大的 free list
for (size_t i = size; i <= ESmallObjectBytes; i += M_align(i))
{
my_free_list = free_list[M_freelist_index(i)];
p = my_free_list;
if (p)
{
my_free_list = p->next;
start_free = (char*)p;
end_free = start_free + i;
return M_chunk_alloc(size, nblock);
}
}
std::printf("out of memory");
end_free = nullptr;
throw std::bad_alloc();
}
end_free = start_free + bytes_to_get;
heap_size += bytes_to_get;
return M_chunk_alloc(size, nblock);
}
}
} // namespace mystl
#endif // !MYTINYSTL_ALLOC_H_

@ -0,0 +1,113 @@
#ifndef MYTINYSTL_ALLOCATOR_H_
#define MYTINYSTL_ALLOCATOR_H_
// 这个头文件包含一个模板类 allocator用于管理内存的分配、释放对象的构造、析构
#include "construct.h"
#include "util.h"
namespace mystl
{
// 模板类allocator
// 模板函数代表数据类型
template <class T>
class allocator
{
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
public:
static T* allocate();
static T* allocate(size_type n);
static void deallocate(T* ptr);
static void deallocate(T* ptr, size_type n);
static void construct(T* ptr);
static void construct(T* ptr, const T& value);
static void construct(T* ptr, T&& value);
template <class... Args>
static void construct(T* ptr, Args&& ...args);
static void destroy(T* ptr);
static void destroy(T* first, T* last);
};
template <class T>
T* allocator<T>::allocate()
{
return static_cast<T*>(::operator new(sizeof(T)));
}
template <class T>
T* allocator<T>::allocate(size_type n)
{
if (n == 0)
return nullptr;
return static_cast<T*>(::operator new(n * sizeof(T)));
}
template <class T>
void allocator<T>::deallocate(T* ptr)
{
if (ptr == nullptr)
return;
::operator delete(ptr);
}
template <class T>
void allocator<T>::deallocate(T* ptr, size_type /*size*/)
{
if (ptr == nullptr)
return;
::operator delete(ptr);
}
template <class T>
void allocator<T>::construct(T* ptr)
{
mystl::construct(ptr);
}
template <class T>
void allocator<T>::construct(T* ptr, const T& value)
{
mystl::construct(ptr, value);
}
template <class T>
void allocator<T>::construct(T* ptr, T&& value)
{
mystl::construct(ptr, mystl::move(value));
}
template <class T>
template <class ...Args>
void allocator<T>::construct(T* ptr, Args&& ...args)
{
mystl::construct(ptr, mystl::forward<Args>(args)...);
}
template <class T>
void allocator<T>::destroy(T* ptr)
{
mystl::destroy(ptr);
}
template <class T>
void allocator<T>::destroy(T* first, T* last)
{
mystl::destroy(first, last);
}
} // namespace mystl
#endif // !MYTINYSTL_ALLOCATOR_H_

@ -0,0 +1,18 @@
#ifndef MYTINYSTL_ASTRING_H_
#define MYTINYSTL_ASTRING_H_
// 定义了 string, wstring, u16string, u32string 类型
#include "basic_string.h"
namespace mystl
{
using string = mystl::basic_string<char>;
using wstring = mystl::basic_string<wchar_t>;
using u16string = mystl::basic_string<char16_t>;
using u32string = mystl::basic_string<char32_t>;
}
#endif // !MYTINYSTL_ASTRING_H_

@ -0,0 +1,85 @@
#ifndef MYTINYSTL_CONSTRUCT_H_
#define MYTINYSTL_CONSTRUCT_H_
// 这个头文件包含两个函数 constructdestroy
// construct : 负责对象的构造
// destroy : 负责对象的析构
#include <new>
#include "type_traits.h"
#include "iterator.h"
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4100) // unused parameter
#endif // _MSC_VER
namespace mystl
{
// construct 构造对象
template <class Ty>
void construct(Ty* ptr)
{
::new ((void*)ptr) Ty();
}
template <class Ty1, class Ty2>
void construct(Ty1* ptr, const Ty2& value)
{
::new ((void*)ptr) Ty1(value);
}
template <class Ty, class... Args>
void construct(Ty* ptr, Args&&... args)
{
::new ((void*)ptr) Ty(mystl::forward<Args>(args)...);
}
// destroy 将对象析构
template <class Ty>
void destroy_one(Ty*, std::true_type) {}
template <class Ty>
void destroy_one(Ty* pointer, std::false_type)
{
if (pointer != nullptr)
{
pointer->~Ty();
}
}
template <class ForwardIter>
void destroy_cat(ForwardIter , ForwardIter , std::true_type) {}
template <class ForwardIter>
void destroy_cat(ForwardIter first, ForwardIter last, std::false_type)
{
for (; first != last; ++first)
destroy(&*first);
}
template <class Ty>
void destroy(Ty* pointer)
{
destroy_one(pointer, std::is_trivially_destructible<Ty>{});
}
template <class ForwardIter>
void destroy(ForwardIter first, ForwardIter last)
{
destroy_cat(first, last, std::is_trivially_destructible<
typename iterator_traits<ForwardIter>::value_type>{});
}
} // namespace mystl
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
#endif // !MYTINYSTL_CONSTRUCT_H_

File diff suppressed because it is too large Load Diff

@ -0,0 +1,26 @@
#ifndef MYTINYSTL_EXCEPTDEF_H_
#define MYTINYSTL_EXCEPTDEF_H_
#include <stdexcept>
#include <cassert>
namespace mystl
{
#define MYSTL_DEBUG(expr) \
assert(expr)
#define THROW_LENGTH_ERROR_IF(expr, what) \
if ((expr)) throw std::length_error(what)
#define THROW_OUT_OF_RANGE_IF(expr, what) \
if ((expr)) throw std::out_of_range(what)
#define THROW_RUNTIME_ERROR_IF(expr, what) \
if ((expr)) throw std::runtime_error(what)
} // namepsace mystl
#endif // !MYTINYSTL_EXCEPTDEF_H_

@ -0,0 +1,285 @@
#ifndef MYTINYSTL_FUNCTIONAL_H_
#define MYTINYSTL_FUNCTIONAL_H_
// 这个头文件包含了 mystl 的函数对象与哈希函数
#include <cstddef>
namespace mystl
{
// 定义一元函数的参数型别和返回值型别
template <class Arg, class Result>
struct unarg_function
{
typedef Arg argument_type;
typedef Result result_type;
};
// 定义二元函数的参数型别的返回值型别
template <class Arg1, class Arg2, class Result>
struct binary_function
{
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
// 函数对象:加法
template <class T>
struct plus :public binary_function<T, T, T>
{
T operator()(const T& x, const T& y) const { return x + y; }
};
// 函数对象:减法
template <class T>
struct minus :public binary_function<T, T, T>
{
T operator()(const T& x, const T& y) const { return x - y; }
};
// 函数对象:乘法
template <class T>
struct multiplies :public binary_function<T, T, T>
{
T operator()(const T& x, const T& y) const { return x * y; }
};
// 函数对象:除法
template <class T>
struct divides :public binary_function<T, T, T>
{
T operator()(const T& x, const T& y) const { return x / y; }
};
// 函数对象:模取
template <class T>
struct modulus :public binary_function<T, T, T>
{
T operator()(const T& x, const T& y) const { return x % y; }
};
// 函数对象:否定
template <class T>
struct negate :public unarg_function<T, T>
{
T operator()(const T& x) const { return -x; }
};
// 加法的证同元素
template <class T>
T identity_element(plus<T>) { return T(0); }
// 乘法的证同元素
template <class T>
T identity_element(multiplies<T>) { return T(1); }
// 函数对象:等于
template <class T>
struct equal_to :public binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const { return x == y; }
};
// 函数对象:不等于
template <class T>
struct not_equal_to :public binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const { return x != y; }
};
// 函数对象:大于
template <class T>
struct greater :public binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const { return x > y; }
};
// 函数对象:小于
template <class T>
struct less :public binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const { return x < y; }
};
// 函数对象:大于等于
template <class T>
struct greater_equal :public binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const { return x >= y; }
};
// 函数对象:小于等于
template <class T>
struct less_equal :public binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const { return x <= y; }
};
// 函数对象:逻辑与
template <class T>
struct logical_and :public binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const { return x && y; }
};
// 函数对象:逻辑或
template <class T>
struct logical_or :public binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const { return x || y; }
};
// 函数对象:逻辑非
template <class T>
struct logical_not :public unarg_function<T, bool>
{
bool operator()(const T& x) const { return !x; }
};
// 证同函数:不会改变元素,返回本身
template <class T>
struct identity :public unarg_function<T, bool>
{
const T& operator()(const T& x) const { return x; }
};
// 选择函数:接受一个 pair返回第一个元素
template <class Pair>
struct selectfirst :public unarg_function<Pair, typename Pair::first_type>
{
const typename Pair::first_type& operator()(const Pair& x) const
{
return x.first;
}
};
// 选择函数:接受一个 pair返回第二个元素
template <class Pair>
struct selectsecond :public unarg_function<Pair, typename Pair::second_type>
{
const typename Pair::second_type& operator()(const Pair& x) const
{
return x.second;
}
};
// 投射函数:返回第一参数
template <class Arg1, class Arg2>
struct projectfirst :public binary_function<Arg1, Arg2, Arg1>
{
Arg1 operator()(const Arg1& x, const Arg2&) const { return x; }
};
// 投射函数:返回第二参数
template <class Arg1, class Arg2>
struct projectsecond :public binary_function<Arg1, Arg2, Arg1>
{
Arg2 operator()(const Arg1&, const Arg2& y) const { return y; }
};
/*****************************************************************************************/
// 哈希函数对象
// 对于大部分类型hash function 什么都不做
template <class Key>
struct hash {};
// 针对指针的偏特化版本
template <class T>
struct hash<T*>
{
size_t operator()(T* p) const noexcept
{ return reinterpret_cast<size_t>(p); }
};
// 对于整型类型,只是返回原值
#define MYSTL_TRIVIAL_HASH_FCN(Type) \
template <> struct hash<Type> \
{ \
size_t operator()(Type val) const noexcept \
{ return static_cast<size_t>(val); } \
};
MYSTL_TRIVIAL_HASH_FCN(bool)
MYSTL_TRIVIAL_HASH_FCN(char)
MYSTL_TRIVIAL_HASH_FCN(signed char)
MYSTL_TRIVIAL_HASH_FCN(unsigned char)
MYSTL_TRIVIAL_HASH_FCN(wchar_t)
MYSTL_TRIVIAL_HASH_FCN(char16_t)
MYSTL_TRIVIAL_HASH_FCN(char32_t)
MYSTL_TRIVIAL_HASH_FCN(short)
MYSTL_TRIVIAL_HASH_FCN(unsigned short)
MYSTL_TRIVIAL_HASH_FCN(int)
MYSTL_TRIVIAL_HASH_FCN(unsigned int)
MYSTL_TRIVIAL_HASH_FCN(long)
MYSTL_TRIVIAL_HASH_FCN(unsigned long)
MYSTL_TRIVIAL_HASH_FCN(long long)
MYSTL_TRIVIAL_HASH_FCN(unsigned long long)
#undef MYSTL_TRIVIAL_HASH_FCN
// 对于浮点数,逐位哈希
inline size_t bitwise_hash(const unsigned char* first, size_t count)
{
#if (_MSC_VER && _WIN64) || ((__GNUC__ || __clang__) &&__SIZEOF_POINTER__ == 8)
const size_t fnv_offset = 14695981039346656037ull;
const size_t fnv_prime = 1099511628211ull;
#else
const size_t fnv_offset = 2166136261u;
const size_t fnv_prime = 16777619u;
#endif
size_t result = fnv_offset;
for (size_t i = 0; i < count; ++i)
{
result ^= (size_t)first[i];
result *= fnv_prime;
}
return result;
}
template <>
struct hash<float>
{
size_t operator()(const float& val)
{
return val == 0.0f ? 0 : bitwise_hash((const unsigned char*)&val, sizeof(float));
}
};
template <>
struct hash<double>
{
size_t operator()(const double& val)
{
return val == 0.0f ? 0 : bitwise_hash((const unsigned char*)&val, sizeof(double));
}
};
template <>
struct hash<long double>
{
size_t operator()(const long double& val)
{
return val == 0.0f ? 0 : bitwise_hash((const unsigned char*)&val, sizeof(long double));
}
};
} // namespace mystl
#endif // !MYTINYSTL_FUNCTIONAL_H_

File diff suppressed because it is too large Load Diff

@ -0,0 +1,227 @@
#ifndef MYTINYSTL_HEAP_ALGO_H_
#define MYTINYSTL_HEAP_ALGO_H_
// 这个头文件包含 heap 的四个算法 : push_heap, pop_heap, sort_heap, make_heap
#include "iterator.h"
namespace mystl
{
/*****************************************************************************************/
// push_heap
// 该函数接受两个迭代器,表示一个 heap 容器的首尾,并且新元素已经插入到底部容器的最尾端,调整 heap
/*****************************************************************************************/
template <class RandomIter, class Distance, class T>
void push_heap_aux(RandomIter first, Distance holeIndex, Distance topIndex, T value)
{
auto parent = (holeIndex - 1) / 2;
while (holeIndex > topIndex && *(first + parent) < value)
{
// 使用 operator<,所以 heap 为 max-heap
*(first + holeIndex) = *(first + parent);
holeIndex = parent;
parent = (holeIndex - 1) / 2;
}
*(first + holeIndex) = value;
}
template <class RandomIter, class Distance>
void push_heap_d(RandomIter first, RandomIter last, Distance*)
{
mystl::push_heap_aux(first, (last - first) - 1, static_cast<Distance>(0), *(last - 1));
}
template <class RandomIter>
void push_heap(RandomIter first, RandomIter last)
{ // 新元素应该已置于底部容器的最尾端
mystl::push_heap_d(first, last, distance_type(first));
}
// 重载版本使用函数对象 comp 代替比较操作
template <class RandomIter, class Distance, class T, class Compared>
void push_heap_aux(RandomIter first, Distance holeIndex, Distance topIndex, T value,
Compared comp)
{
auto parent = (holeIndex - 1) / 2;
while (holeIndex > topIndex && comp(*(first + parent), value))
{
*(first + holeIndex) = *(first + parent);
holeIndex = parent;
parent = (holeIndex - 1) / 2;
}
*(first + holeIndex) = value;
}
template <class RandomIter, class Compared, class Distance>
void push_heap_d(RandomIter first, RandomIter last, Distance*, Compared comp)
{
mystl::push_heap_aux(first, (last - first) - 1, static_cast<Distance>(0),
*(last - 1), comp);
}
template <class RandomIter, class Compared>
void push_heap(RandomIter first, RandomIter last, Compared comp)
{
mystl::push_heap_d(first, last, distance_type(first), comp);
}
/*****************************************************************************************/
// pop_heap
// 该函数接受两个迭代器,表示 heap 容器的首尾,将 heap 的根节点取出放到容器尾部,调整 heap
/*****************************************************************************************/
template <class RandomIter, class T, class Distance>
void adjust_heap(RandomIter first, Distance holeIndex, Distance len, T value)
{
// 先进行下溯(percolate down)过程
auto topIndex = holeIndex;
auto rchild = 2 * holeIndex + 2;
while (rchild < len)
{
if (*(first + rchild) < *(first + rchild - 1))
--rchild;
*(first + holeIndex) = *(first + rchild);
holeIndex = rchild;
rchild = 2 * (rchild + 1);
}
if (rchild == len)
{ // 如果没有右子节点
*(first + holeIndex) = *(first + (rchild - 1));
holeIndex = rchild - 1;
}
// 再执行一次上溯(percolate up)过程
mystl::push_heap_aux(first, holeIndex, topIndex, value);
}
template <class RandomIter, class T, class Distance>
void pop_heap_aux(RandomIter first, RandomIter last, RandomIter result, T value,
Distance*)
{
// 先将首值调至尾节点,然后调整[first, last - 1)使之重新成为一个 max-heap
*result = *first;
mystl::adjust_heap(first, static_cast<Distance>(0), last - first, value);
}
template <class RandomIter>
void pop_heap(RandomIter first, RandomIter last)
{
mystl::pop_heap_aux(first, last - 1, last - 1, *(last - 1), distance_type(first));
}
// 重载版本使用函数对象 comp 代替比较操作
template <class RandomIter, class T, class Distance, class Compared>
void adjust_heap(RandomIter first, Distance holeIndex, Distance len, T value,
Compared comp)
{
// 先进行下溯(percolate down)过程
auto topIndex = holeIndex;
auto rchild = 2 * holeIndex + 2;
while (rchild < len)
{
if (comp(*(first + rchild), *(first + rchild - 1))) --rchild;
*(first + holeIndex) = *(first + rchild);
holeIndex = rchild;
rchild = 2 * (rchild + 1);
}
if (rchild == len)
{
*(first + holeIndex) = *(first + (rchild - 1));
holeIndex = rchild - 1;
}
// 再执行一次上溯(percolate up)过程
mystl::push_heap_aux(first, holeIndex, topIndex, value, comp);
}
template <class RandomIter, class T, class Distance, class Compared>
void pop_heap_aux(RandomIter first, RandomIter last, RandomIter result,
T value, Distance*, Compared comp)
{
*result = *first; // 先将尾指设置成首值,即尾指为欲求结果
mystl::adjust_heap(first, static_cast<Distance>(0), last - first, value, comp);
}
template <class RandomIter, class Compared>
void pop_heap(RandomIter first, RandomIter last, Compared comp)
{
mystl::pop_heap_aux(first, last - 1, last - 1, *(last - 1),
distance_type(first), comp);
}
/*****************************************************************************************/
// sort_heap
// 该函数接受两个迭代器,表示 heap 容器的首尾,不断执行 pop_heap 操作直到首尾最多相差1
/*****************************************************************************************/
template <class RandomIter>
void sort_heap(RandomIter first, RandomIter last)
{
// 每执行一次 pop_heap最大的元素都被放到尾部直到容器最多只有一个元素完成排序
while (last - first > 1)
{
mystl::pop_heap(first, last--);
}
}
// 重载版本使用函数对象 comp 代替比较操作
template <class RandomIter, class Compared>
void sort_heap(RandomIter first, RandomIter last, Compared comp)
{
while (last - first > 1)
{
mystl::pop_heap(first, last--, comp);
}
}
/*****************************************************************************************/
// make_heap
// 该函数接受两个迭代器,表示 heap 容器的首尾,把容器内的数据变为一个 heap
/*****************************************************************************************/
template <class RandomIter, class Distance>
void make_heap_aux(RandomIter first, RandomIter last, Distance*)
{
if (last - first < 2)
return;
auto len = last - first;
auto holeIndex = (len - 2) / 2;
while (true)
{
// 重排以 holeIndex 为首的子树
mystl::adjust_heap(first, holeIndex, len, *(first + holeIndex));
if (holeIndex == 0)
return;
holeIndex--;
}
}
template <class RandomIter>
void make_heap(RandomIter first, RandomIter last)
{
mystl::make_heap_aux(first, last, distance_type(first));;
}
// 重载版本使用函数对象 comp 代替比较操作
template <class RandomIter, class Distance, class Compared>
void make_heap_aux(RandomIter first, RandomIter last, Distance*, Compared comp)
{
if (last - first < 2)
return;
auto len = last - first;
auto holeIndex = (len - 2) / 2;
while (true)
{
// 重排以 holeIndex 为首的子树
mystl::adjust_heap(first, holeIndex, len, *(first + holeIndex), comp);
if (holeIndex == 0)
return;
holeIndex--;
}
}
template <class RandomIter, class Compared>
void make_heap(RandomIter first, RandomIter last, Compared comp)
{
mystl::make_heap_aux(first, last, distance_type(first), comp);
}
} // namespace mystl
#endif // !MYTINYSTL_HEAP_ALGO_H_

@ -0,0 +1,366 @@
#ifndef MYTINYSTL_ITERATOR_H_
#define MYTINYSTL_ITERATOR_H_
// 这个头文件用于迭代器设计,包含了一些模板结构体与全局函数,
#include <cstddef>
#include "type_traits.h"
namespace mystl
{
// 五种迭代器类型
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
// iterator 模板
template <class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&>
struct iterator
{
typedef Category iterator_category;
typedef T value_type;
typedef Pointer pointer;
typedef Reference reference;
typedef Distance difference_type;
};
// iterator traits
template <class T>
struct has_iterator_cat
{
private:
struct two { char a; char b; };
template <class U> static two test(...);
template <class U> static char test(typename U::iterator_category* = 0);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
};
template <class Iterator, bool>
struct iterator_traits_impl {};
template <class Iterator>
struct iterator_traits_impl<Iterator, true>
{
typedef typename Iterator::iterator_category iterator_category;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
typedef typename Iterator::difference_type difference_type;
};
template <class Iterator, bool>
struct iterator_traits_helper {};
template <class Iterator>
struct iterator_traits_helper<Iterator, true>
: public iterator_traits_impl<Iterator,
std::is_convertible<typename Iterator::iterator_category, input_iterator_tag>::value ||
std::is_convertible<typename Iterator::iterator_category, output_iterator_tag>::value>
{
};
// 萃取迭代器的特性
template <class Iterator>
struct iterator_traits
: public iterator_traits_helper<Iterator, has_iterator_cat<Iterator>::value> {};
// 针对原生指针的偏特化版本
template <class T>
struct iterator_traits<T*>
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef ptrdiff_t difference_type;
};
template <class T>
struct iterator_traits<const T*>
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef const T* pointer;
typedef const T& reference;
typedef ptrdiff_t difference_type;
};
template <class T, class U, bool = has_iterator_cat<iterator_traits<T>>::value>
struct has_iterator_cat_of
: public m_bool_constant<std::is_convertible<
typename iterator_traits<T>::iterator_category, U>::value>
{
};
// 萃取某种迭代器
template <class T, class U>
struct has_iterator_cat_of<T, U, false> : public m_false_type {};
template <class Iter>
struct is_input_iterator : public has_iterator_cat_of<Iter, input_iterator_tag> {};
template <class Iter>
struct is_output_iterator : public has_iterator_cat_of<Iter, output_iterator_tag> {};
template <class Iter>
struct is_forward_iterator : public has_iterator_cat_of<Iter, forward_iterator_tag> {};
template <class Iter>
struct is_bidirectional_iterator : public has_iterator_cat_of<Iter, bidirectional_iterator_tag> {};
template <class Iter>
struct is_random_access_iterator : public has_iterator_cat_of<Iter, random_access_iterator_tag> {};
template <class Iterator>
struct is_iterator :
public m_bool_constant<is_input_iterator<Iterator>::value ||
is_output_iterator<Iterator>::value>
{
};
// 萃取某个迭代器的 category
template <class Iterator>
typename iterator_traits<Iterator>::iterator_category
iterator_category(const Iterator&)
{
typedef typename iterator_traits<Iterator>::iterator_category Category;
return Category();
}
// 萃取某个迭代器的 distance_type
template <class Iterator>
typename iterator_traits<Iterator>::difference_type*
distance_type(const Iterator&)
{
return static_cast<typename iterator_traits<Iterator>::difference_type*>(0);
}
// 萃取某个迭代器的 value_type
template <class Iterator>
typename iterator_traits<Iterator>::value_type*
value_type(const Iterator&)
{
return static_cast<typename iterator_traits<Iterator>::value_type*>(0);
}
// 以下函数用于计算迭代器间的距离
// distance 的 input_iterator_tag 的版本
template <class InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance_dispatch(InputIterator first, InputIterator last, input_iterator_tag)
{
typename iterator_traits<InputIterator>::difference_type n = 0;
while (first != last)
{
++first;
++n;
}
return n;
}
// distance 的 random_access_iterator_tag 的版本
template <class RandomIter>
typename iterator_traits<RandomIter>::difference_type
distance_dispatch(RandomIter first, RandomIter last,
random_access_iterator_tag)
{
return last - first;
}
template <class InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance(InputIterator first, InputIterator last)
{
return distance_dispatch(first, last, iterator_category(first));
}
// 以下函数用于让迭代器前进 n 个距离
// advance 的 input_iterator_tag 的版本
template <class InputIterator, class Distance>
void advance_dispatch(InputIterator& i, Distance n, input_iterator_tag)
{
while (n--)
++i;
}
// advance 的 bidirectional_iterator_tag 的版本
template <class BidirectionalIterator, class Distance>
void advance_dispatch(BidirectionalIterator& i, Distance n, bidirectional_iterator_tag)
{
if (n >= 0)
while (n--) ++i;
else
while (n++) --i;
}
// advance 的 random_access_iterator_tag 的版本
template <class RandomIter, class Distance>
void advance_dispatch(RandomIter& i, Distance n, random_access_iterator_tag)
{
i += n;
}
template <class InputIterator, class Distance>
void advance(InputIterator& i, Distance n)
{
advance_dispatch(i, n, iterator_category(i));
}
/*****************************************************************************************/
// 模板类 : reverse_iterator
// 代表反向迭代器,使前进为后退,后退为前进
template <class Iterator>
class reverse_iterator
{
private:
Iterator current; // 记录对应的正向迭代器
public:
// 反向迭代器的五种相应型别
typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
typedef typename iterator_traits<Iterator>::value_type value_type;
typedef typename iterator_traits<Iterator>::difference_type difference_type;
typedef typename iterator_traits<Iterator>::pointer pointer;
typedef typename iterator_traits<Iterator>::reference reference;
typedef Iterator iterator_type;
typedef reverse_iterator<Iterator> self;
public:
// 构造函数
reverse_iterator() {}
explicit reverse_iterator(iterator_type i) :current(i) {}
reverse_iterator(const self& rhs) :current(rhs.current) {}
public:
// 取出对应的正向迭代器
iterator_type base() const
{ return current; }
// 重载操作符
reference operator*() const
{ // 实际对应正向迭代器的前一个位置
auto tmp = current;
return *--tmp;
}
pointer operator->() const
{
return &(operator*());
}
// 前进(++)变为后退(--)
self& operator++()
{
--current;
return *this;
}
self operator++(int)
{
self tmp = *this;
--current;
return tmp;
}
// 后退(--)变为前进(++)
self& operator--()
{
++current;
return *this;
}
self operator--(int)
{
self tmp = *this;
++current;
return tmp;
}
self& operator+=(difference_type n)
{
current -= n;
return *this;
}
self operator+(difference_type n) const
{
return self(current - n);
}
self& operator-=(difference_type n)
{
current += n;
return *this;
}
self operator-(difference_type n) const
{
return self(current + n);
}
reference operator[](difference_type n) const
{
return *(*this + n);
}
};
// 重载 operator-
template <class Iterator>
typename reverse_iterator<Iterator>::difference_type
operator-(const reverse_iterator<Iterator>& lhs,
const reverse_iterator<Iterator>& rhs)
{
return rhs.base() - lhs.base();
}
// 重载比较操作符
template <class Iterator>
bool operator==(const reverse_iterator<Iterator>& lhs,
const reverse_iterator<Iterator>& rhs)
{
return lhs.base() == rhs.base();
}
template <class Iterator>
bool operator<(const reverse_iterator<Iterator>& lhs,
const reverse_iterator<Iterator>& rhs)
{
return rhs.base() < lhs.base();
}
template <class Iterator>
bool operator!=(const reverse_iterator<Iterator>& lhs,
const reverse_iterator<Iterator>& rhs)
{
return !(lhs == rhs);
}
template <class Iterator>
bool operator>(const reverse_iterator<Iterator>& lhs,
const reverse_iterator<Iterator>& rhs)
{
return rhs < lhs;
}
template <class Iterator>
bool operator<=(const reverse_iterator<Iterator>& lhs,
const reverse_iterator<Iterator>& rhs)
{
return !(rhs < lhs);
}
template <class Iterator>
bool operator>=(const reverse_iterator<Iterator>& lhs,
const reverse_iterator<Iterator>& rhs)
{
return !(lhs < rhs);
}
} // namespace mystl
#endif // !MYTINYSTL_ITERATOR_H_

File diff suppressed because it is too large Load Diff

@ -0,0 +1,549 @@
#ifndef MYTINYSTL_MAP_H_
#define MYTINYSTL_MAP_H_
// 这个头文件包含了两个模板类 map 和 multimap
// map : 映射,元素具有键值和实值,会根据键值大小自动排序,键值不允许重复
// multimap : 映射,元素具有键值和实值,会根据键值大小自动排序,键值允许重复
// notes:
//
// 异常保证:
// mystl::map<Key, T> / mystl::multimap<Key, T> 满足基本异常保证,对以下等函数做强异常安全保证:
// * emplace
// * emplace_hint
// * insert
#include "rb_tree.h"
namespace mystl
{
// 模板类 map键值不允许重复
// 参数一代表键值类型,参数二代表实值类型,参数三代表键值的比较方式,缺省使用 mystl::less
template <class Key, class T, class Compare = mystl::less<Key>>
class map
{
public:
// map 的嵌套型别定义
typedef Key key_type;
typedef T mapped_type;
typedef mystl::pair<const Key, T> value_type;
typedef Compare key_compare;
// 定义一个 functor用来进行元素比较
class value_compare : public binary_function <value_type, value_type, bool>
{
friend class map<Key, T, Compare>;
private:
Compare comp;
value_compare(Compare c) : comp(c) {}
public:
bool operator()(const value_type& lhs, const value_type& rhs) const
{
return comp(lhs.first, rhs.first); // 比较键值的大小
}
};
private:
// 以 mystl::rb_tree 作为底层机制
typedef mystl::rb_tree<value_type, key_compare> base_type;
base_type tree_;
public:
// 使用 rb_tree 的型别
typedef typename base_type::node_type node_type;
typedef typename base_type::pointer pointer;
typedef typename base_type::const_pointer const_pointer;
typedef typename base_type::reference reference;
typedef typename base_type::const_reference const_reference;
typedef typename base_type::iterator iterator;
typedef typename base_type::const_iterator const_iterator;
typedef typename base_type::reverse_iterator reverse_iterator;
typedef typename base_type::const_reverse_iterator const_reverse_iterator;
typedef typename base_type::size_type size_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::allocator_type allocator_type;
public:
// 构造、复制、移动、赋值函数
map() = default;
template <class InputIterator>
map(InputIterator first, InputIterator last)
:tree_()
{ tree_.insert_unique(first, last); }
map(std::initializer_list<value_type> ilist)
:tree_()
{ tree_.insert_unique(ilist.begin(), ilist.end()); }
map(const map& rhs)
:tree_(rhs.tree_)
{
}
map(map&& rhs) noexcept
:tree_(mystl::move(rhs.tree_))
{
}
map& operator=(const map& rhs)
{
tree_ = rhs.tree_;
return *this;
}
map& operator=(map&& rhs)
{
tree_ = mystl::move(rhs.tree_);
return *this;
}
map& operator=(std::initializer_list<value_type> ilist)
{
tree_.clear();
tree_.insert_unique(ilist.begin(), ilist.end());
return *this;
}
// 相关接口
key_compare key_comp() const { return tree_.key_comp(); }
value_compare value_comp() const { return value_compare(tree_.key_comp()); }
allocator_type get_allocator() const { return tree_.get_allocator(); }
// 迭代器相关
iterator begin() noexcept
{ return tree_.begin(); }
const_iterator begin() const noexcept
{ return tree_.begin(); }
iterator end() noexcept
{ return tree_.end(); }
const_iterator end() const noexcept
{ return tree_.end(); }
reverse_iterator rbegin() noexcept
{ return reverse_iterator(end()); }
const_reverse_iterator rbegin() const noexcept
{ return const_reverse_iterator(end()); }
reverse_iterator rend() noexcept
{ return reverse_iterator(begin()); }
const_reverse_iterator rend() const noexcept
{ return const_reverse_iterator(begin()); }
const_iterator cbegin() const noexcept
{ return begin(); }
const_iterator cend() const noexcept
{ return end(); }
const_reverse_iterator crbegin() const noexcept
{ return rbegin(); }
const_reverse_iterator crend() const noexcept
{ return rend(); }
// 容量相关
bool empty() const noexcept { return tree_.empty(); }
size_type size() const noexcept { return tree_.size(); }
size_type max_size() const noexcept { return tree_.max_size(); }
// 访问元素相关
// 若键值不存在at 会抛出一个异常
mapped_type& at(const key_type& key)
{
iterator it = lower_bound(key);
// it->first >= key
THROW_OUT_OF_RANGE_IF(it == end() || key_comp()(it->first, key),
"map<Key, T> no such element exists");
return it->second;
}
const mapped_type& at(const key_type& key) const
{
const_iterator it = lower_bound(key);
// it->first >= key
THROW_OUT_OF_RANGE_IF(it == end() || key_comp()(it->first, key),
"map<Key, T> no such element exists");
return it->second;
}
mapped_type& operator[](const key_type& key)
{
iterator it = lower_bound(key);
// it->first >= key
if (it == end() || key_comp()(key, it->first))
it = emplace_hint(it, key, T{});
return it->second;
}
mapped_type& operator[](key_type&& key)
{
iterator it = lower_bound(key);
// it->first >= key
if (it == end() || key_comp()(key, it->first))
it = emplace_hint(it, mystl::move(key), T{});
return it->second;
}
// 插入删除相关
template <class ...Args>
pair<iterator, bool> emplace(Args&& ...args)
{
return tree_.emplace_unique(mystl::forward<Args>(args)...);
}
template <class ...Args>
iterator emplace_hint(iterator hint, Args&& ...args)
{
return tree_.emplace_unique_use_hint(hint, mystl::forward<Args>(args)...);
}
pair<iterator, bool> insert(const value_type& value)
{
return tree_.insert_unique(value);
}
pair<iterator, bool> insert(value_type&& value)
{
return tree_.insert_unique(mystl::move(value));
}
iterator insert(iterator hint, const value_type& value)
{
return tree_.insert_unique(hint, value);
}
iterator insert(iterator hint, value_type&& value)
{
return tree_.insert_unique(hint, mystl::move(value));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{
tree_.insert_unique(first, last);
}
void erase(iterator position) { tree_.erase(position); }
size_type erase(const key_type& key) { return tree_.erase_unique(key); }
void erase(iterator first, iterator last) { tree_.erase(first, last); }
void clear() { tree_.clear(); }
// map 相关操作
iterator find(const key_type& key) { return tree_.find(key); }
const_iterator find(const key_type& key) const { return tree_.find(key); }
size_type count(const key_type& key) const { return tree_.count_unique(key); }
iterator lower_bound(const key_type& key) { return tree_.lower_bound(key); }
const_iterator lower_bound(const key_type& key) const { return tree_.lower_bound(key); }
iterator upper_bound(const key_type& key) { return tree_.upper_bound(key); }
const_iterator upper_bound(const key_type& key) const { return tree_.upper_bound(key); }
pair<iterator, iterator>
equal_range(const key_type& key)
{ return tree_.equal_range_unique(key); }
pair<const_iterator, const_iterator>
equal_range(const key_type& key) const
{ return tree_.equal_range_unique(key); }
void swap(map& rhs) noexcept
{ tree_.swap(rhs.tree_); }
public:
friend bool operator==(const map& lhs, const map& rhs) { return lhs.tree_ == rhs.tree_; }
friend bool operator< (const map& lhs, const map& rhs) { return lhs.tree_ < rhs.tree_; }
};
// 重载比较操作符
template <class Key, class T, class Compare>
bool operator==(const map<Key, T, Compare>& lhs, const map<Key, T, Compare>& rhs)
{
return lhs == rhs;
}
template <class Key, class T, class Compare>
bool operator<(const map<Key, T, Compare>& lhs, const map<Key, T, Compare>& rhs)
{
return lhs < rhs;
}
template <class Key, class T, class Compare>
bool operator!=(const map<Key, T, Compare>& lhs, const map<Key, T, Compare>& rhs)
{
return !(lhs == rhs);
}
template <class Key, class T, class Compare>
bool operator>(const map<Key, T, Compare>& lhs, const map<Key, T, Compare>& rhs)
{
return rhs < lhs;
}
template <class Key, class T, class Compare>
bool operator<=(const map<Key, T, Compare>& lhs, const map<Key, T, Compare>& rhs)
{
return !(rhs < lhs);
}
template <class Key, class T, class Compare>
bool operator>=(const map<Key, T, Compare>& lhs, const map<Key, T, Compare>& rhs)
{
return !(lhs < rhs);
}
// 重载 mystl 的 swap
template <class Key, class T, class Compare>
void swap(map<Key, T, Compare>& lhs, map<Key, T, Compare>& rhs) noexcept
{
lhs.swap(rhs);
}
/*****************************************************************************************/
// 模板类 multimap键值允许重复
// 参数一代表键值类型,参数二代表实值类型,参数三代表键值的比较方式,缺省使用 mystl::less
template <class Key, class T, class Compare = mystl::less<Key>>
class multimap
{
public:
// multimap 的型别定义
typedef Key key_type;
typedef T mapped_type;
typedef mystl::pair<const Key, T> value_type;
typedef Compare key_compare;
// 定义一个 functor用来进行元素比较
class value_compare : public binary_function <value_type, value_type, bool>
{
friend class multimap<Key, T, Compare>;
private:
Compare comp;
value_compare(Compare c) : comp(c) {}
public:
bool operator()(const value_type& lhs, const value_type& rhs) const
{
return comp(lhs.first, rhs.first);
}
};
private:
// 用 mystl::rb_tree 作为底层机制
typedef mystl::rb_tree<value_type, key_compare> base_type;
base_type tree_;
public:
// 使用 rb_tree 的型别
typedef typename base_type::node_type node_type;
typedef typename base_type::pointer pointer;
typedef typename base_type::const_pointer const_pointer;
typedef typename base_type::reference reference;
typedef typename base_type::const_reference const_reference;
typedef typename base_type::iterator iterator;
typedef typename base_type::const_iterator const_iterator;
typedef typename base_type::reverse_iterator reverse_iterator;
typedef typename base_type::const_reverse_iterator const_reverse_iterator;
typedef typename base_type::size_type size_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::allocator_type allocator_type;
public:
// 构造、复制、移动函数
multimap() = default;
template <class InputIterator>
multimap(InputIterator first, InputIterator last)
:tree_()
{ tree_.insert_multi(first, last); }
multimap(std::initializer_list<value_type> ilist)
:tree_()
{ tree_.insert_multi(ilist.begin(), ilist.end()); }
multimap(const multimap& rhs)
:tree_(rhs.tree_)
{
}
multimap(multimap&& rhs) noexcept
:tree_(mystl::move(rhs.tree_))
{
}
multimap& operator=(const multimap& rhs)
{
tree_ = rhs.tree_;
return *this;
}
multimap& operator=(multimap&& rhs)
{
tree_ = mystl::move(rhs.tree_);
return *this;
}
multimap& operator=(std::initializer_list<value_type> ilist)
{
tree_.clear();
tree_.insert_multi(ilist.begin(), ilist.end());
return *this;
}
// 相关接口
key_compare key_comp() const { return tree_.key_comp(); }
value_compare value_comp() const { return value_compare(tree_.key_comp()); }
allocator_type get_allocator() const { return tree_.get_allocator(); }
// 迭代器相关
iterator begin() noexcept
{ return tree_.begin(); }
const_iterator begin() const noexcept
{ return tree_.begin(); }
iterator end() noexcept
{ return tree_.end(); }
const_iterator end() const noexcept
{ return tree_.end(); }
reverse_iterator rbegin() noexcept
{ return reverse_iterator(end()); }
const_reverse_iterator rbegin() const noexcept
{ return const_reverse_iterator(end()); }
reverse_iterator rend() noexcept
{ return reverse_iterator(begin()); }
const_reverse_iterator rend() const noexcept
{ return const_reverse_iterator(begin()); }
const_iterator cbegin() const noexcept
{ return begin(); }
const_iterator cend() const noexcept
{ return end(); }
const_reverse_iterator crbegin() const noexcept
{ return rbegin(); }
const_reverse_iterator crend() const noexcept
{ return rend(); }
// 容量相关
bool empty() const noexcept { return tree_.empty(); }
size_type size() const noexcept { return tree_.size(); }
size_type max_size() const noexcept { return tree_.max_size(); }
// 插入删除操作
template <class ...Args>
iterator emplace(Args&& ...args)
{
return tree_.emplace_multi(mystl::forward<Args>(args)...);
}
template <class ...Args>
iterator emplace_hint(iterator hint, Args&& ...args)
{
return tree_.emplace_multi_use_hint(hint, mystl::forward<Args>(args)...);
}
iterator insert(const value_type& value)
{
return tree_.insert_multi(value);
}
iterator insert(value_type&& value)
{
return tree_.insert_multi(mystl::move(value));
}
iterator insert(iterator hint, const value_type& value)
{
return tree_.insert_multi(hint, value);
}
iterator insert(iterator hint, value_type&& value)
{
return tree_.insert_multi(hint, mystl::move(value));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{
tree_.insert_multi(first, last);
}
void erase(iterator position) { tree_.erase(position); }
size_type erase(const key_type& key) { return tree_.erase_multi(key); }
void erase(iterator first, iterator last) { tree_.erase(first, last); }
void clear() { tree_.clear(); }
// multimap 相关操作
iterator find(const key_type& key) { return tree_.find(key); }
const_iterator find(const key_type& key) const { return tree_.find(key); }
size_type count(const key_type& key) const { return tree_.count_multi(key); }
iterator lower_bound(const key_type& key) { return tree_.lower_bound(key); }
const_iterator lower_bound(const key_type& key) const { return tree_.lower_bound(key); }
iterator upper_bound(const key_type& key) { return tree_.upper_bound(key); }
const_iterator upper_bound(const key_type& key) const { return tree_.upper_bound(key); }
pair<iterator, iterator>
equal_range(const key_type& key)
{ return tree_.equal_range_multi(key); }
pair<const_iterator, const_iterator>
equal_range(const key_type& key) const
{ return tree_.equal_range_multi(key); }
void swap(multimap& rhs) noexcept
{ tree_.swap(rhs.tree_); }
public:
friend bool operator==(const multimap& lhs, const multimap& rhs) { return lhs.tree_ == rhs.tree_; }
friend bool operator< (const multimap& lhs, const multimap& rhs) { return lhs.tree_ < rhs.tree_; }
};
// 重载比较操作符
template <class Key, class T, class Compare>
bool operator==(const multimap<Key, T, Compare>& lhs, const multimap<Key, T, Compare>& rhs)
{
return lhs == rhs;
}
template <class Key, class T, class Compare>
bool operator<(const multimap<Key, T, Compare>& lhs, const multimap<Key, T, Compare>& rhs)
{
return lhs < rhs;
}
template <class Key, class T, class Compare>
bool operator!=(const multimap<Key, T, Compare>& lhs, const multimap<Key, T, Compare>& rhs)
{
return !(lhs == rhs);
}
template <class Key, class T, class Compare>
bool operator>(const multimap<Key, T, Compare>& lhs, const multimap<Key, T, Compare>& rhs)
{
return rhs < lhs;
}
template <class Key, class T, class Compare>
bool operator<=(const multimap<Key, T, Compare>& lhs, const multimap<Key, T, Compare>& rhs)
{
return !(rhs < lhs);
}
template <class Key, class T, class Compare>
bool operator>=(const multimap<Key, T, Compare>& lhs, const multimap<Key, T, Compare>& rhs)
{
return !(lhs < rhs);
}
// 重载 mystl 的 swap
template <class Key, class T, class Compare>
void swap(multimap<Key, T, Compare>& lhs, multimap<Key, T, Compare>& rhs) noexcept
{
lhs.swap(rhs);
}
} // namespace mystl
#endif // !MYTINYSTL_MAP_H_

@ -0,0 +1,208 @@
#ifndef MYTINYSTL_MEMORY_H_
#define MYTINYSTL_MEMORY_H_
// 这个头文件负责更高级的动态内存管理
// 包含一些基本函数、空间配置器、未初始化的储存空间管理,以及一个模板类 auto_ptr
#include <cstddef>
#include <cstdlib>
#include <climits>
#include "algobase.h"
#include "allocator.h"
#include "construct.h"
#include "uninitialized.h"
namespace mystl
{
// 获取对象地址
template <class Tp>
constexpr Tp* address_of(Tp& value) noexcept
{
return &value;
}
// 获取 / 释放 临时缓冲区
template <class T>
pair<T*, ptrdiff_t> get_buffer_helper(ptrdiff_t len, T*)
{
if (len > static_cast<ptrdiff_t>(INT_MAX / sizeof(T)))
len = INT_MAX / sizeof(T);
while (len > 0)
{
T* tmp = static_cast<T*>(malloc(static_cast<size_t>(len) * sizeof(T)));
if (tmp)
return pair<T*, ptrdiff_t>(tmp, len);
len /= 2; // 申请失败时减少 len 的大小
}
return pair<T*, ptrdiff_t>(nullptr, 0);
}
template <class T>
pair<T*, ptrdiff_t> get_temporary_buffer(ptrdiff_t len)
{
return get_buffer_helper(len, static_cast<T*>(0));
}
template <class T>
pair<T*, ptrdiff_t> get_temporary_buffer(ptrdiff_t len, T*)
{
return get_buffer_helper(len, static_cast<T*>(0));
}
template <class T>
void release_temporary_buffer(T* ptr)
{
free(ptr);
}
// --------------------------------------------------------------------------------------
// 类模板 : temporary_buffer
// 进行临时缓冲区的申请与释放
template <class ForwardIterator, class T>
class temporary_buffer
{
private:
ptrdiff_t original_len; // 缓冲区申请的大小
ptrdiff_t len; // 缓冲区实际的大小
T* buffer; // 指向缓冲区的指针
public:
// 构造、析构函数
temporary_buffer(ForwardIterator first, ForwardIterator last);
~temporary_buffer()
{
mystl::destroy(buffer, buffer + len);
free(buffer);
}
public:
ptrdiff_t size() const noexcept { return len; }
ptrdiff_t requested_size() const noexcept { return original_len; }
T* begin() noexcept { return buffer; }
T* end() noexcept { return buffer + len; }
private:
void allocate_buffer();
void initialize_buffer(const T&, std::true_type) {}
void initialize_buffer(const T& value, std::false_type)
{ mystl::uninitialized_fill_n(buffer, len, value); }
private:
temporary_buffer(const temporary_buffer&);
void operator=(const temporary_buffer&);
};
// 构造函数
template <class ForwardIterator, class T>
temporary_buffer<ForwardIterator, T>::
temporary_buffer(ForwardIterator first, ForwardIterator last)
{
try
{
len = mystl::distance(first, last);
allocate_buffer();
if (len > 0)
{
initialize_buffer(*first, std::is_trivially_default_constructible<T>());
}
}
catch (...)
{
free(buffer);
buffer = nullptr;
len = 0;
}
}
// allocate_buffer 函数
template <class ForwardIterator, class T>
void temporary_buffer<ForwardIterator, T>::allocate_buffer()
{
original_len = len;
if (len > static_cast<ptrdiff_t>(INT_MAX / sizeof(T)))
len = INT_MAX / sizeof(T);
while (len > 0)
{
buffer = static_cast<T*>(malloc(len * sizeof(T)));
if (buffer)
break;
len /= 2; // 申请失败时减少申请空间大小
}
}
// --------------------------------------------------------------------------------------
// 模板类: auto_ptr
// 一个具有严格对象所有权的小型智能指针
template <class T>
class auto_ptr
{
public:
typedef T elem_type;
private:
T* m_ptr; // 实际指针
public:
// 构造、复制、析构函数
explicit auto_ptr(T* p = nullptr) :m_ptr(p) {}
auto_ptr(auto_ptr& rhs) :m_ptr(rhs.release()) {}
template <class U>
auto_ptr(auto_ptr<U>& rhs) : m_ptr(rhs.release()) {}
auto_ptr& operator=(auto_ptr& rhs)
{
if (this != &rhs)
{
delete m_ptr;
m_ptr = rhs.release();
}
return *this;
}
template <class U>
auto_ptr& operator=(auto_ptr<U>& rhs)
{
if (this->get() != rhs.get())
{
delete m_ptr;
m_ptr = rhs.release();
}
return *this;
}
~auto_ptr() { delete m_ptr; }
public:
// 重载 operator* 和 operator->
T& operator*() const { return *m_ptr; }
T* operator->() const { return m_ptr; }
// 获得指针
T* get() const { return m_ptr; }
// 释放指针
T* release()
{
T* tmp = m_ptr;
m_ptr = nullptr;
return tmp;
}
// 重置指针
void reset(T* p = nullptr)
{
if (m_ptr != p)
{
delete m_ptr;
m_ptr = p;
}
}
};
} // namespace mystl
#endif // !MYTINYSTL_MEMORY_H_

@ -0,0 +1,155 @@
#ifndef MYTINYSTL_NUMERIC_H_
#define MYTINYSTL_NUMERIC_H_
// 这个头文件包含了 mystl 的数值算法
#include "iterator.h"
namespace mystl
{
/*****************************************************************************************/
// accumulate
// 版本1以初值 init 对每个元素进行累加
// 版本2以初值 init 对每个元素进行二元操作
/*****************************************************************************************/
// 版本1
template <class InputIter, class T>
T accumulate(InputIter first, InputIter last, T init)
{
for (; first != last; ++first)
{
init += *first;
}
return init;
}
// 版本2
template <class InputIter, class T, class BinaryOp>
T accumulate(InputIter first, InputIter last, T init, BinaryOp binary_op)
{
for (; first != last; ++first)
{
init = binary_op(init, *first);
}
return init;
}
/*****************************************************************************************/
// adjacent_difference
// 版本1计算相邻元素的差值结果保存到以 result 为起始的区间上
// 版本2自定义相邻元素的二元操作
/*****************************************************************************************/
// 版本1
template <class InputIter, class OutputIter>
OutputIter adjacent_difference(InputIter first, InputIter last, OutputIter result)
{
if (first == last) return result;
*result = *first; // 记录第一个元素
auto value = *first;
while (++first != last)
{
auto tmp = *first;
*++result = tmp - value;
value = tmp;
}
return ++result;
}
// 版本2
template <class InputIter, class OutputIter, class BinaryOp>
OutputIter adjacent_difference(InputIter first, InputIter last, OutputIter result,
BinaryOp binary_op)
{
if (first == last) return result;
*result = *first; // 记录第一个元素
auto value = *first;
while (++first != last)
{
auto tmp = *first;
*++result = binary_op(tmp, value);
value = tmp;
}
return ++result;
}
/*****************************************************************************************/
// inner_product
// 版本1以 init 为初值,计算两个区间的内积
// 版本2自定义 operator+ 和 operator*
/*****************************************************************************************/
// 版本1
template <class InputIter1, class InputIter2, class T>
T inner_product(InputIter1 first1, InputIter1 last1, InputIter2 first2, T init)
{
for (; first1 != last1; ++first1, ++first2)
{
init = init + (*first1 * *first2);
}
return init;
}
// 版本2
template <class InputIter1, class InputIter2, class T, class BinaryOp1, class BinaryOp2>
T inner_product(InputIter1 first1, InputIter1 last1, InputIter2 first2, T init,
BinaryOp1 binary_op1, BinaryOp2 binary_op2)
{
for (; first1 != last1; ++first1, ++first2)
{
init = binary_op1(init, binary_op2(*first1, *first2));
}
return init;
}
/*****************************************************************************************/
// iota
// 填充[first, last),以 value 为初值开始递增
/*****************************************************************************************/
template <class ForwardIter, class T>
void iota(ForwardIter first, ForwardIter last, T value)
{
while (first != last)
{
*first++ = value;
++value;
}
}
/*****************************************************************************************/
// partial_sum
// 版本1计算局部累计求和结果保存到以 result 为起始的区间上
// 版本2进行局部进行自定义二元操作
/*****************************************************************************************/
template <class InputIter, class OutputIter>
OutputIter partial_sum(InputIter first, InputIter last, OutputIter result)
{
if (first == last) return result;
*result = *first; // 记录第一个元素
auto value = *first;
while (++first != last)
{
value = value + *first;
*++result = value;
}
return ++result;
}
// 版本2
template <class InputIter, class OutputIter, class BinaryOp>
OutputIter partial_sum(InputIter first, InputIter last, OutputIter result,
BinaryOp binary_op)
{
if (first == last) return result;
*result = *first; //记录第一个元素
auto value = *first;
while (++first != last)
{
value = binary_op(value, *first);
*++result = value;
}
return ++result;
}
} // namespace mystl
#endif // !MYTINYSTL_NUMERIC_H_

@ -0,0 +1,364 @@
#ifndef MYTINYSTL_QUEUE_H_
#define MYTINYSTL_QUEUE_H_
// 这个头文件包含了两个模板类 queue 和 priority_queue
// queue : 队列
// priority_queue : 优先队列
#include "deque.h"
#include "vector.h"
#include "functional.h"
#include "heap_algo.h"
namespace mystl
{
// 模板类 queue
// 参数一代表数据类型,参数二代表底层容器类型,缺省使用 mystl::deque 作为底层容器
template <class T, class Container = mystl::deque<T>>
class queue
{
public:
typedef Container container_type;
// 使用底层容器的型别
typedef typename Container::value_type value_type;
typedef typename Container::size_type size_type;
typedef typename Container::reference reference;
typedef typename Container::const_reference const_reference;
static_assert(std::is_same<T, value_type>::value,
"the value_type of Container should be same with T");
private:
container_type c_; // 用底层容器表现 queue
public:
// 构造、复制、移动函数
queue() = default;
explicit queue(size_type n)
:c_(n)
{
}
queue(size_type n, const value_type& value)
:c_(n, value)
{
}
template <class IIter>
queue(IIter first, IIter last)
:c_(first, last)
{
}
queue(std::initializer_list<T> ilist)
:c_(ilist.begin(), ilist.end())
{
}
queue(const Container& c)
:c_(c)
{
}
queue(Container&& c) noexcept(std::is_nothrow_move_constructible<Container>::value)
:c_(mystl::move(c))
{
}
queue(const queue& rhs)
:c_(rhs.c_)
{
}
queue(queue&& rhs) noexcept(std::is_nothrow_move_constructible<Container>::value)
:c_(mystl::move(rhs.c_))
{
}
queue& operator=(const queue& rhs)
{
c_ = rhs.c_;
return *this;
}
queue& operator=(queue&& rhs) noexcept(std::is_nothrow_move_assignable<Container>::value)
{
c_ = mystl::move(rhs.c_);
return *this;
}
queue& operator=(std::initializer_list<T> ilist)
{
c_ = ilist;
return *this;
}
~queue() = default;
// 访问元素相关操作
reference front() { return c_.front(); }
const_reference front() const { return c_.front(); }
reference back() { return c_.back(); }
const_reference back() const { return c_.back(); }
// 容量相关操作
bool empty() const noexcept { return c_.empty(); }
size_type size() const noexcept { return c_.size(); }
// 修改容器相关操作
template <class ...Args>
void emplace(Args&& ...args)
{ c_.emplace_back(mystl::forward<Args>(args)...); }
void push(const value_type& value)
{ c_.push_back(value); }
void push(value_type&& value)
{ c_.emplace_back(mystl::move(value)); }
void pop()
{ c_.pop_front(); }
void clear()
{
while (!empty())
pop();
}
void swap(queue& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_)))
{ mystl::swap(c_, rhs.c_); }
public:
friend bool operator==(const queue& lhs, const queue& rhs) { return lhs.c_ == rhs.c_; }
friend bool operator< (const queue& lhs, const queue& rhs) { return lhs.c_ < rhs.c_; }
};
// 重载比较操作符
template <class T, class Container>
bool operator==(const queue<T, Container>& lhs, const queue<T, Container>& rhs)
{
return lhs == rhs;
}
template <class T, class Container>
bool operator!=(const queue<T, Container>& lhs, const queue<T, Container>& rhs)
{
return !(lhs == rhs);
}
template <class T, class Container>
bool operator<(const queue<T, Container>& lhs, const queue<T, Container>& rhs)
{
return lhs < rhs;
}
template <class T, class Container>
bool operator>(const queue<T, Container>& lhs, const queue<T, Container>& rhs)
{
return rhs < lhs;
}
template <class T, class Container>
bool operator<=(const queue<T, Container>& lhs, const queue<T, Container>& rhs)
{
return !(rhs < lhs);
}
template <class T, class Container>
bool operator>=(const queue<T, Container>& lhs, const queue<T, Container>& rhs)
{
return !(lhs < rhs);
}
// 重载 mystl 的 swap
template <class T, class Container>
void swap(queue<T, Container>& lhs, queue<T, Container>& rhs) noexcept(noexcept(lhs.swap(rhs)))
{
lhs.swap(rhs);
}
/*****************************************************************************************/
// 模板类 priority_queue
// 参数一代表数据类型,参数二代表容器类型,缺省使用 mystl::vector 作为底层容器
// 参数三代表比较权值的方式,缺省使用 mystl::less 作为比较方式
template <class T, class Container = mystl::vector<T>,
class Compare = mystl::less<typename Container::value_type>>
class priority_queue
{
public:
typedef Container container_type;
typedef Compare value_compare;
// 使用底层容器的型别
typedef typename Container::value_type value_type;
typedef typename Container::size_type size_type;
typedef typename Container::reference reference;
typedef typename Container::const_reference const_reference;
static_assert(std::is_same<T, value_type>::value,
"the value_type of Container should be same with T");
private:
container_type c_; // 用底层容器来表现 priority_queue
value_compare comp_; // 权值比较的标准
public:
// 构造、复制、移动函数
priority_queue() = default;
priority_queue(const Compare& c)
:c_(), comp_(c)
{
}
explicit priority_queue(size_type n)
:c_(n)
{
mystl::make_heap(c_.begin(), c_.end(), comp_);
}
priority_queue(size_type n, const value_type& value)
:c_(n, value)
{
mystl::make_heap(c_.begin(), c_.end(), comp_);
}
template <class IIter>
priority_queue(IIter first, IIter last)
:c_(first, last)
{
mystl::make_heap(c_.begin(), c_.end(), comp_);
}
priority_queue(std::initializer_list<T> ilist)
:c_(ilist)
{
mystl::make_heap(c_.begin(), c_.end(), comp_);
}
priority_queue(const Container& s)
:c_(s)
{
mystl::make_heap(c_.begin(), c_.end(), comp_);
}
priority_queue(Container&& s)
:c_(mystl::move(s))
{
mystl::make_heap(c_.begin(), c_.end(), comp_);
}
priority_queue(const priority_queue& rhs)
:c_(rhs.c_), comp_(rhs.comp_)
{
mystl::make_heap(c_.begin(), c_.end(), comp_);
}
priority_queue(priority_queue&& rhs)
:c_(mystl::move(rhs.c_)), comp_(rhs.comp_)
{
mystl::make_heap(c_.begin(), c_.end(), comp_);
}
priority_queue& operator=(const priority_queue& rhs)
{
c_ = rhs.c_;
comp_ = rhs.comp_;
mystl::make_heap(c_.begin(), c_.end(), comp_);
return *this;
}
priority_queue& operator=(priority_queue&& rhs)
{
c_ = mystl::move(rhs.c_);
comp_ = rhs.comp_;
mystl::make_heap(c_.begin(), c_.end(), comp_);
return *this;
}
priority_queue& operator=(std::initializer_list<T> ilist)
{
c_ = ilist;
comp_ = value_compare();
mystl::make_heap(c_.begin(), c_.end(), comp_);
return *this;
}
~priority_queue() = default;
public:
// 访问元素相关操作
const_reference top() const { return c_.front(); }
// 容量相关操作
bool empty() const noexcept { return c_.empty(); }
size_type size() const noexcept { return c_.size(); }
// 修改容器相关操作
template <class... Args>
void emplace(Args&& ...args)
{
c_.emplace_back(mystl::forward<Args>(args)...);
mystl::push_heap(c_.begin(), c_.end(), comp_);
}
void push(const value_type& value)
{
c_.push_back(value);
mystl::push_heap(c_.begin(), c_.end(), comp_);
}
void push(value_type&& value)
{
c_.push_back(mystl::move(value));
mystl::push_heap(c_.begin(), c_.end(), comp_);
}
void pop()
{
mystl::pop_heap(c_.begin(), c_.end(), comp_);
c_.pop_back();
}
void clear()
{
while (!empty())
pop();
}
void swap(priority_queue& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_)) &&
noexcept(mystl::swap(comp_, rhs.comp_)))
{
mystl::swap(c_, rhs.c_);
mystl::swap(comp_, rhs.comp_);
}
public:
friend bool operator==(const priority_queue& lhs, const priority_queue& rhs)
{
return lhs.c_ == rhs.c_;
}
friend bool operator!=(const priority_queue& lhs, const priority_queue& rhs)
{
return lhs.c_ != rhs.c_;
}
};
// 重载比较操作符
template <class T, class Container, class Compare>
bool operator==(priority_queue<T, Container, Compare>& lhs,
priority_queue<T, Container, Compare>& rhs)
{
return lhs == rhs;
}
template <class T, class Container, class Compare>
bool operator!=(priority_queue<T, Container, Compare>& lhs,
priority_queue<T, Container, Compare>& rhs)
{
return lhs != rhs;
}
// 重载 mystl 的 swap
template <class T, class Container, class Compare>
void swap(priority_queue<T, Container, Compare>& lhs,
priority_queue<T, Container, Compare>& rhs) noexcept(noexcept(lhs.swap(rhs)))
{
lhs.swap(rhs);
}
} // namespace mystl
#endif // !MYTINYSTL_QUEUE_H_

File diff suppressed because it is too large Load Diff

@ -0,0 +1,477 @@
#ifndef MYTINYSTL_SET_H_
#define MYTINYSTL_SET_H_
// 这个头文件包含两个模板类 set 和 multiset
// set : 集合,键值即实值,集合内元素会自动排序,键值不允许重复
// multiset : 集合,键值即实值,集合内元素会自动排序,键值允许重复
// notes:
//
// 异常保证:
// mystl::set<Key> / mystl::multiset<Key> 满足基本异常保证,对以下等函数做强异常安全保证:
// * emplace
// * emplace_hint
// * insert
#include "rb_tree.h"
namespace mystl
{
// 模板类 set键值不允许重复
// 参数一代表键值类型,参数二代表键值比较方式,缺省使用 mystl::less
template <class Key, class Compare = mystl::less<Key>>
class set
{
public:
typedef Key key_type;
typedef Key value_type;
typedef Compare key_compare;
typedef Compare value_compare;
private:
// 以 mystl::rb_tree 作为底层机制
typedef mystl::rb_tree<value_type, key_compare> base_type;
base_type tree_;
public:
// 使用 rb_tree 定义的型别
typedef typename base_type::node_type node_type;
typedef typename base_type::const_pointer pointer;
typedef typename base_type::const_pointer const_pointer;
typedef typename base_type::const_reference reference;
typedef typename base_type::const_reference const_reference;
typedef typename base_type::const_iterator iterator;
typedef typename base_type::const_iterator const_iterator;
typedef typename base_type::const_reverse_iterator reverse_iterator;
typedef typename base_type::const_reverse_iterator const_reverse_iterator;
typedef typename base_type::size_type size_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::allocator_type allocator_type;
public:
// 构造、复制、移动函数
set() = default;
template <class InputIterator>
set(InputIterator first, InputIterator last)
:tree_()
{ tree_.insert_unique(first, last); }
set(std::initializer_list<value_type> ilist)
:tree_()
{ tree_.insert_unique(ilist.begin(), ilist.end()); }
set(const set& rhs)
:tree_(rhs.tree_)
{
}
set(set&& rhs) noexcept
:tree_(mystl::move(rhs.tree_))
{
}
set& operator=(const set& rhs)
{
tree_ = rhs.tree_;
return *this;
}
set& operator=(set&& rhs)
{
tree_ = mystl::move(rhs.tree_);
return *this;
}
set& operator=(std::initializer_list<value_type> ilist)
{
tree_.clear();
tree_.insert_unique(ilist.begin(), ilist.end());
return *this;
}
// 相关接口
key_compare key_comp() const { return tree_.key_comp(); }
value_compare value_comp() const { return tree_.key_comp(); }
allocator_type get_allocator() const { return tree_.get_allocator(); }
// 迭代器相关
iterator begin() noexcept
{ return tree_.begin(); }
const_iterator begin() const noexcept
{ return tree_.begin(); }
iterator end() noexcept
{ return tree_.end(); }
const_iterator end() const noexcept
{ return tree_.end(); }
reverse_iterator rbegin() noexcept
{ return reverse_iterator(end()); }
const_reverse_iterator rbegin() const noexcept
{ return const_reverse_iterator(end()); }
reverse_iterator rend() noexcept
{ return reverse_iterator(begin()); }
const_reverse_iterator rend() const noexcept
{ return const_reverse_iterator(begin()); }
const_iterator cbegin() const noexcept
{ return begin(); }
const_iterator cend() const noexcept
{ return end(); }
const_reverse_iterator crbegin() const noexcept
{ return rbegin(); }
const_reverse_iterator crend() const noexcept
{ return rend(); }
// 容量相关
bool empty() const noexcept { return tree_.empty(); }
size_type size() const noexcept { return tree_.size(); }
size_type max_size() const noexcept { return tree_.max_size(); }
// 插入删除操作
template <class ...Args>
pair<iterator, bool> emplace(Args&& ...args)
{
return tree_.emplace_unique(mystl::forward<Args>(args)...);
}
template <class ...Args>
iterator emplace_hint(iterator hint, Args&& ...args)
{
return tree_.emplace_unique_use_hint(hint, mystl::forward<Args>(args)...);
}
pair<iterator, bool> insert(const value_type& value)
{
return tree_.insert_unique(value);
}
pair<iterator, bool> insert(value_type&& value)
{
return tree_.insert_unique(mystl::move(value));
}
iterator insert(iterator hint, const value_type& value)
{
return tree_.insert_unique(hint, value);
}
iterator insert(iterator hint, value_type&& value)
{
return tree_.insert_unique(hint, mystl::move(value));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{
tree_.insert_unique(first, last);
}
void erase(iterator position) { tree_.erase(position); }
size_type erase(const key_type& key) { return tree_.erase_unique(key); }
void erase(iterator first, iterator last) { tree_.erase(first, last); }
void clear() { tree_.clear(); }
// set 相关操作
iterator find(const key_type& key) { return tree_.find(key); }
const_iterator find(const key_type& key) const { return tree_.find(key); }
size_type count(const key_type& key) const { return tree_.count_unique(key); }
iterator lower_bound(const key_type& key) { return tree_.lower_bound(key); }
const_iterator lower_bound(const key_type& key) const { return tree_.lower_bound(key); }
iterator upper_bound(const key_type& key) { return tree_.upper_bound(key); }
const_iterator upper_bound(const key_type& key) const { return tree_.upper_bound(key); }
pair<iterator, iterator>
equal_range(const key_type& key)
{ return tree_.equal_range_unique(key); }
pair<const_iterator, const_iterator>
equal_range(const key_type& key) const
{ return tree_.equal_range_unique(key); }
void swap(set& rhs) noexcept
{ tree_.swap(rhs.tree_); }
public:
friend bool operator==(const set& lhs, const set& rhs) { return lhs.tree_ == rhs.tree_; }
friend bool operator< (const set& lhs, const set& rhs) { return lhs.tree_ < rhs.tree_; }
};
// 重载比较操作符
template <class Key, class Compare>
bool operator==(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
{
return lhs == rhs;
}
template <class Key, class Compare>
bool operator<(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
{
return lhs < rhs;
}
template <class Key, class Compare>
bool operator!=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
{
return !(lhs == rhs);
}
template <class Key, class Compare>
bool operator>(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
{
return rhs < lhs;
}
template <class Key, class Compare>
bool operator<=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
{
return !(rhs < lhs);
}
template <class Key, class Compare>
bool operator>=(const set<Key, Compare>& lhs, const set<Key, Compare>& rhs)
{
return !(lhs < rhs);
}
// 重载 mystl 的 swap
template <class Key, class Compare>
void swap(set<Key, Compare>& lhs, set<Key, Compare>& rhs) noexcept
{
lhs.swap(rhs);
}
/*****************************************************************************************/
// 模板类 multiset键值允许重复
// 参数一代表键值类型,参数二代表键值比较方式,缺省使用 mystl::less
template <class Key, class Compare = mystl::less<Key>>
class multiset
{
public:
typedef Key key_type;
typedef Key value_type;
typedef Compare key_compare;
typedef Compare value_compare;
private:
// 以 mystl::rb_tree 作为底层机制
typedef mystl::rb_tree<value_type, key_compare> base_type;
base_type tree_; // 以 rb_tree 表现 multiset
public:
// 使用 rb_tree 定义的型别
typedef typename base_type::node_type node_type;
typedef typename base_type::const_pointer pointer;
typedef typename base_type::const_pointer const_pointer;
typedef typename base_type::const_reference reference;
typedef typename base_type::const_reference const_reference;
typedef typename base_type::const_iterator iterator;
typedef typename base_type::const_iterator const_iterator;
typedef typename base_type::const_reverse_iterator reverse_iterator;
typedef typename base_type::const_reverse_iterator const_reverse_iterator;
typedef typename base_type::size_type size_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::allocator_type allocator_type;
public:
// 构造、复制、移动函数
multiset() = default;
template <class InputIterator>
multiset(InputIterator first, InputIterator last)
:tree_()
{ tree_.insert_multi(first, last); }
multiset(std::initializer_list<value_type> ilist)
:tree_()
{ tree_.insert_multi(ilist.begin(), ilist.end()); }
multiset(const multiset& rhs)
:tree_(rhs.tree_)
{
}
multiset(multiset&& rhs) noexcept
:tree_(mystl::move(rhs.tree_))
{
}
multiset& operator=(const multiset& rhs)
{
tree_ = rhs.tree_;
return *this;
}
multiset& operator=(multiset&& rhs)
{
tree_ = mystl::move(rhs.tree_);
return *this;
}
multiset& operator=(std::initializer_list<value_type> ilist)
{
tree_.clear();
tree_.insert_multi(ilist.begin(), ilist.end());
return *this;
}
// 相关接口
key_compare key_comp() const { return tree_.key_comp(); }
value_compare value_comp() const { return tree_.key_comp(); }
allocator_type get_allocator() const { return tree_.get_allocator(); }
// 迭代器相关
iterator begin() noexcept
{ return tree_.begin(); }
const_iterator begin() const noexcept
{ return tree_.begin(); }
iterator end() noexcept
{ return tree_.end(); }
const_iterator end() const noexcept
{ return tree_.end(); }
reverse_iterator rbegin() noexcept
{ return reverse_iterator(end()); }
const_reverse_iterator rbegin() const noexcept
{ return const_reverse_iterator(end()); }
reverse_iterator rend() noexcept
{ return reverse_iterator(begin()); }
const_reverse_iterator rend() const noexcept
{ return const_reverse_iterator(begin()); }
const_iterator cbegin() const noexcept
{ return begin(); }
const_iterator cend() const noexcept
{ return end(); }
const_reverse_iterator crbegin() const noexcept
{ return rbegin(); }
const_reverse_iterator crend() const noexcept
{ return rend(); }
// 容量相关
bool empty() const noexcept { return tree_.empty(); }
size_type size() const noexcept { return tree_.size(); }
size_type max_size() const noexcept { return tree_.max_size(); }
// 插入删除操作
template <class ...Args>
iterator emplace(Args&& ...args)
{
return tree_.emplace_multi(mystl::forward<Args>(args)...);
}
template <class ...Args>
iterator emplace_hint(iterator hint, Args&& ...args)
{
return tree_.emplace_multi_use_hint(hint, mystl::forward<Args>(args)...);
}
iterator insert(const value_type& value)
{
return tree_.insert_multi(value);
}
iterator insert(value_type&& value)
{
return tree_.insert_multi(mystl::move(value));
}
iterator insert(iterator hint, const value_type& value)
{
return tree_.insert_multi(hint, value);
}
iterator insert(iterator hint, value_type&& value)
{
return tree_.insert_multi(hint, mystl::move(value));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{
tree_.insert_multi(first, last);
}
void erase(iterator position) { tree_.erase(position); }
size_type erase(const key_type& key) { return tree_.erase_multi(key); }
void erase(iterator first, iterator last) { tree_.erase(first, last); }
void clear() { tree_.clear(); }
// multiset 相关操作
iterator find(const key_type& key) { return tree_.find(key); }
const_iterator find(const key_type& key) const { return tree_.find(key); }
size_type count(const key_type& key) const { return tree_.count_multi(key); }
iterator lower_bound(const key_type& key) { return tree_.lower_bound(key); }
const_iterator lower_bound(const key_type& key) const { return tree_.lower_bound(key); }
iterator upper_bound(const key_type& key) { return tree_.upper_bound(key); }
const_iterator upper_bound(const key_type& key) const { return tree_.upper_bound(key); }
pair<iterator, iterator>
equal_range(const key_type& key)
{ return tree_.equal_range_multi(key); }
pair<const_iterator, const_iterator>
equal_range(const key_type& key) const
{ return tree_.equal_range_multi(key); }
void swap(multiset& rhs) noexcept
{ tree_.swap(rhs.tree_); }
public:
friend bool operator==(const multiset& lhs, const multiset& rhs) { return lhs.tree_ == rhs.tree_; }
friend bool operator< (const multiset& lhs, const multiset& rhs) { return lhs.tree_ < rhs.tree_; }
};
// 重载比较操作符
template <class Key, class Compare>
bool operator==(const multiset<Key, Compare>& lhs, const multiset<Key, Compare>& rhs)
{
return lhs == rhs;
}
template <class Key, class Compare>
bool operator<(const multiset<Key, Compare>& lhs, const multiset<Key, Compare>& rhs)
{
return lhs < rhs;
}
template <class Key, class Compare>
bool operator!=(const multiset<Key, Compare>& lhs, const multiset<Key, Compare>& rhs)
{
return !(lhs == rhs);
}
template <class Key, class Compare>
bool operator>(const multiset<Key, Compare>& lhs, const multiset<Key, Compare>& rhs)
{
return rhs < lhs;
}
template <class Key, class Compare>
bool operator<=(const multiset<Key, Compare>& lhs, const multiset<Key, Compare>& rhs)
{
return !(rhs < lhs);
}
template <class Key, class Compare>
bool operator>=(const multiset<Key, Compare>& lhs, const multiset<Key, Compare>& rhs)
{
return !(lhs < rhs);
}
// 重载 mystl 的 swap
template <class Key, class Compare>
void swap(multiset<Key, Compare>& lhs, multiset<Key, Compare>& rhs) noexcept
{
lhs.swap(rhs);
}
} // namespace mystl
#endif // !MYTINYSTL_SET_H_

@ -0,0 +1,253 @@
#ifndef MYTINYSTL_SET_ALGO_H_
#define MYTINYSTL_SET_ALGO_H_
// 这个头文件包含 set 的四种算法: union, intersection, difference, symmetric_difference
// 所有函数都要求序列有序
#include "algobase.h"
#include "iterator.h"
namespace mystl
{
/*****************************************************************************************/
// set_union
// 计算 S1S2 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部
/*****************************************************************************************/
template <class InputIter1, class InputIter2, class OutputIter>
OutputIter set_union(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result)
{
while (first1 != last1 && first2 != last2)
{
if (*first1 < *first2)
{
*result = *first1;
++first1;
}
else if (*first2 < *first1)
{
*result = *first2;
++first2;
}
else
{
*result = *first1;
++first1;
++first2;
}
++result;
}
// 将剩余元素拷贝到 result
return mystl::copy(first2, last2, mystl::copy(first1, last1, result));
}
// 重载版本使用函数对象 comp 代替比较操作
template <class InputIter1, class InputIter2, class OutputIter, class Compared>
OutputIter set_union(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result, Compared comp)
{
while (first1 != last1 && first2 != last2)
{
if (comp(*first1, *first2))
{
*result = *first1;
++first1;
}
else if (comp(*first2, *first1))
{
*result = *first2;
++first2;
}
else
{
*result = *first1;
++first1;
++first2;
}
++result;
}
// 将剩余元素拷贝到 result
return mystl::copy(first2, last2, mystl::copy(first1, last1, result));
}
/*****************************************************************************************/
// set_intersection
// 计算 S1∩S2 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部
/*****************************************************************************************/
template <class InputIter1, class InputIter2, class OutputIter>
OutputIter set_intersection(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result)
{
while (first1 != last1 && first2 != last2)
{
if (*first1 < *first2)
{
++first1;
}
else if (*first2 < *first1)
{
++first2;
}
else
{
*result = *first1;
++first1;
++first2;
++result;
}
}
return result;
}
// 重载版本使用函数对象 comp 代替比较操作
template <class InputIter1, class InputIter2, class OutputIter, class Compared>
OutputIter set_intersection(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result, Compared comp)
{
while (first1 != last1 && first2 != last2)
{
if (comp(*first1, *first2))
{
++first1;
}
else if (comp(*first2, *first1))
{
++first2;
}
else
{
*result = *first1;
++first1;
++first2;
++result;
}
}
return result;
}
/*****************************************************************************************/
// set_difference
// 计算 S1-S2 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部
/*****************************************************************************************/
template <class InputIter1, class InputIter2, class OutputIter>
OutputIter set_difference(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result)
{
while (first1 != last1 && first2 != last2)
{
if (*first1 < *first2)
{
*result = *first1;
++first1;
++result;
}
else if (*first2 < *first1)
{
++first2;
}
else
{
++first1;
++first2;
}
}
return mystl::copy(first1, last1, result);
}
// 重载版本使用函数对象 comp 代替比较操作
template <class InputIter1, class InputIter2, class OutputIter, class Compared>
OutputIter set_difference(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result, Compared comp)
{
while (first1 != last1 && first2 != last2)
{
if (comp(*first1, *first2))
{
*result = *first1;
++first1;
++result;
}
else if (comp(*first2, *first1))
{
++first2;
}
else
{
++first1;
++first2;
}
}
return mystl::copy(first1, last1, result);
}
/*****************************************************************************************/
// set_symmetric_difference
// 计算 (S1-S2)(S2-S1) 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部
/*****************************************************************************************/
template <class InputIter1, class InputIter2, class OutputIter>
OutputIter set_symmetric_difference(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result)
{
while (first1 != last1 && first2 != last2)
{
if (*first1 < *first2)
{
*result = *first1;
++first1;
++result;
}
else if (*first2 < *first1)
{
*result = *first2;
++first2;
++result;
}
else
{
++first1;
++first2;
}
}
return mystl::copy(first2, last2, mystl::copy(first1, last1, result));
}
// 重载版本使用函数对象 comp 代替比较操作
template <class InputIter1, class InputIter2, class OutputIter, class Compared>
OutputIter set_symmetric_difference(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result, Compared comp)
{
while (first1 != last1 && first2 != last2)
{
if (comp(*first1, *first2))
{
*result = *first1;
++first1;
++result;
}
else if (comp(*first2, *first1))
{
*result = *first2;
++first2;
++result;
}
else
{
++first1;
++first2;
}
}
return mystl::copy(first2, last2, mystl::copy(first1, last1, result));
}
} // namespace mystl
#endif // !MYTINYSTL_SET_ALGO_H_

@ -0,0 +1,173 @@
#ifndef MYTINYSTL_STACK_H_
#define MYTINYSTL_STACK_H_
// 这个头文件包含了一个模板类 stack
// stack : 栈
#include "deque.h"
namespace mystl
{
// 模板类 stack
// 参数一代表数据类型,参数二代表底层容器类型,缺省使用 mystl::deque 作为底层容器
template <class T, class Container = mystl::deque<T>>
class stack
{
public:
typedef Container container_type;
// 使用底层容器的型别
typedef typename Container::value_type value_type;
typedef typename Container::size_type size_type;
typedef typename Container::reference reference;
typedef typename Container::const_reference const_reference;
static_assert(std::is_same<T, value_type>::value,
"the value_type of Container should be same with T");
private:
container_type c_; // 用底层容器表现 stack
public:
// 构造、复制、移动函数
stack() = default;
explicit stack(size_type n)
:c_(n)
{
}
stack(size_type n, const value_type& value)
:c_(n, value)
{
}
template <class IIter>
stack(IIter first, IIter last)
: c_(first, last)
{
}
stack(std::initializer_list<T> ilist)
:c_(ilist.begin(), ilist.end())
{
}
stack(const Container& c)
:c_(c)
{
}
stack(Container&& c) noexcept(std::is_nothrow_move_constructible<Container>::value)
:c_(mystl::move(c))
{
}
stack(const stack& rhs)
:c_(rhs.c_)
{
}
stack(stack&& rhs) noexcept(std::is_nothrow_move_constructible<Container>::value)
:c_(mystl::move(rhs.c_))
{
}
stack& operator=(const stack& rhs)
{
c_ = rhs.c_;
return *this;
}
stack& operator=(stack&& rhs) noexcept(std::is_nothrow_move_assignable<Container>::value)
{
c_ = mystl::move(rhs.c_);
return *this;
}
stack& operator=(std::initializer_list<T> ilist)
{
c_ = ilist;
return *this;
}
~stack() = default;
// 访问元素相关操作
reference top() { return c_.back(); }
const_reference top() const { return c_.back(); }
// 容量相关操作
bool empty() const noexcept { return c_.empty(); }
size_type size() const noexcept { return c_.size(); }
// 修改容器相关操作
template <class... Args>
void emplace(Args&& ...args)
{ c_.emplace_back(mystl::forward<Args>(args)...); }
void push(const value_type& value)
{ c_.push_back(value); }
void push(value_type&& value)
{ c_.push_back(mystl::move(value)); }
void pop()
{ c_.pop_back(); }
void clear()
{
while (!empty())
pop();
}
void swap(stack& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_)))
{ mystl::swap(c_, rhs.c_); }
public:
friend bool operator==(const stack& lhs, const stack& rhs) { return lhs.c_ == rhs.c_; }
friend bool operator< (const stack& lhs, const stack& rhs) { return lhs.c_ < rhs.c_; }
};
// 重载比较操作符
template <class T, class Container>
bool operator==(const stack<T, Container>& lhs, const stack<T, Container>& rhs)
{
return lhs == rhs;
}
template <class T, class Container>
bool operator<(const stack<T, Container>& lhs, const stack<T, Container>& rhs)
{
return lhs < rhs;
}
template <class T, class Container>
bool operator!=(const stack<T, Container>& lhs, const stack<T, Container>& rhs)
{
return !(lhs == rhs);
}
template <class T, class Container>
bool operator>(const stack<T, Container>& lhs, const stack<T, Container>& rhs)
{
return rhs < lhs;
}
template <class T, class Container>
bool operator<=(const stack<T, Container>& lhs, const stack<T, Container>& rhs)
{
return !(rhs < lhs);
}
template <class T, class Container>
bool operator>=(const stack<T, Container>& lhs, const stack<T, Container>& rhs)
{
return !(lhs < rhs);
}
// 重载 mystl 的 swap
template <class T, class Container>
void swap(stack<T, Container>& lhs, stack<T, Container>& rhs) noexcept(noexcept(lhs.swap(rhs)))
{
lhs.swap(rhs);
}
} // namespace mystl
#endif // !MYTINYSTL_STACK_H_

@ -0,0 +1,45 @@
#ifndef MYTINYSTL_TYPE_TRAITS_H_
#define MYTINYSTL_TYPE_TRAITS_H_
// 这个头文件用于提取类型信息
// use standard header for type_traits
#include <type_traits>
namespace mystl
{
// helper struct
template <class T, T v>
struct m_integral_constant
{
static constexpr T value = v;
};
template <bool b>
using m_bool_constant = m_integral_constant<bool, b>;
typedef m_bool_constant<true> m_true_type;
typedef m_bool_constant<false> m_false_type;
/*****************************************************************************************/
// type traits
// is_pair
// --- forward declaration begin
template <class T1, class T2>
struct pair;
// --- forward declaration end
template <class T>
struct is_pair : mystl::m_false_type {};
template <class T1, class T2>
struct is_pair<mystl::pair<T1, T2>> : mystl::m_true_type {};
} // namespace mystl
#endif // !MYTINYSTL_TYPE_TRAITS_H_

@ -0,0 +1,256 @@
#ifndef MYTINYSTL_UNINITIALIZED_H_
#define MYTINYSTL_UNINITIALIZED_H_
// 这个头文件用于对未初始化空间构造元素
#include "algobase.h"
#include "construct.h"
#include "iterator.h"
#include "type_traits.h"
#include "util.h"
namespace mystl
{
/*****************************************************************************************/
// uninitialized_copy
// 把 [first, last) 上的内容复制到以 result 为起始处的空间,返回复制结束的位置
/*****************************************************************************************/
template <class InputIter, class ForwardIter>
ForwardIter
unchecked_uninit_copy(InputIter first, InputIter last, ForwardIter result, std::true_type)
{
return mystl::copy(first, last, result);
}
template <class InputIter, class ForwardIter>
ForwardIter
unchecked_uninit_copy(InputIter first, InputIter last, ForwardIter result, std::false_type)
{
auto cur = result;
try
{
for (; first != last; ++first, ++cur)
{
mystl::construct(&*cur, *first);
}
}
catch (...)
{
for (; result != cur; --cur)
mystl::destroy(&*cur);
}
return cur;
}
template <class InputIter, class ForwardIter>
ForwardIter uninitialized_copy(InputIter first, InputIter last, ForwardIter result)
{
return mystl::unchecked_uninit_copy(first, last, result,
std::is_trivially_copy_assignable<
typename iterator_traits<ForwardIter>::
value_type>{});
}
/*****************************************************************************************/
// uninitialized_copy_n
// 把 [first, first + n) 上的内容复制到以 result 为起始处的空间,返回复制结束的位置
/*****************************************************************************************/
template <class InputIter, class Size, class ForwardIter>
ForwardIter
unchecked_uninit_copy_n(InputIter first, Size n, ForwardIter result, std::true_type)
{
return mystl::copy_n(first, n, result).second;
}
template <class InputIter, class Size, class ForwardIter>
ForwardIter
unchecked_uninit_copy_n(InputIter first, Size n, ForwardIter result, std::false_type)
{
auto cur = result;
try
{
for (; n > 0; --n, ++cur, ++first)
{
mystl::construct(&*cur, *first);
}
}
catch (...)
{
for (; result != cur; --cur)
mystl::destroy(&*cur);
}
return cur;
}
template <class InputIter, class Size, class ForwardIter>
ForwardIter uninitialized_copy_n(InputIter first, Size n, ForwardIter result)
{
return mystl::unchecked_uninit_copy_n(first, n, result,
std::is_trivially_copy_assignable<
typename iterator_traits<InputIter>::
value_type>{});
}
/*****************************************************************************************/
// uninitialized_fill
// 在 [first, last) 区间内填充元素值
/*****************************************************************************************/
template <class ForwardIter, class T>
void
unchecked_uninit_fill(ForwardIter first, ForwardIter last, const T& value, std::true_type)
{
mystl::fill(first, last, value);
}
template <class ForwardIter, class T>
void
unchecked_uninit_fill(ForwardIter first, ForwardIter last, const T& value, std::false_type)
{
auto cur = first;
try
{
for (; cur != last; ++cur)
{
mystl::construct(&*cur, value);
}
}
catch (...)
{
for (;first != cur; ++first)
mystl::destroy(&*first);
}
}
template <class ForwardIter, class T>
void uninitialized_fill(ForwardIter first, ForwardIter last, const T& value)
{
mystl::unchecked_uninit_fill(first, last, value,
std::is_trivially_copy_assignable<
typename iterator_traits<ForwardIter>::
value_type>{});
}
/*****************************************************************************************/
// uninitialized_fill_n
// 从 first 位置开始,填充 n 个元素值,返回填充结束的位置
/*****************************************************************************************/
template <class ForwardIter, class Size, class T>
ForwardIter
unchecked_uninit_fill_n(ForwardIter first, Size n, const T& value, std::true_type)
{
return mystl::fill_n(first, n, value);
}
template <class ForwardIter, class Size, class T>
ForwardIter
unchecked_uninit_fill_n(ForwardIter first, Size n, const T& value, std::false_type)
{
auto cur = first;
try
{
for (; n > 0; --n, ++cur)
{
mystl::construct(&*cur, value);
}
}
catch (...)
{
for (; first != cur; ++first)
mystl::destroy(&*first);
}
return cur;
}
template <class ForwardIter, class Size, class T>
ForwardIter uninitialized_fill_n(ForwardIter first, Size n, const T& value)
{
return mystl::unchecked_uninit_fill_n(first, n, value,
std::is_trivially_copy_assignable<
typename iterator_traits<ForwardIter>::
value_type>{});
}
/*****************************************************************************************/
// uninitialized_move
// 把[first, last)上的内容移动到以 result 为起始处的空间,返回移动结束的位置
/*****************************************************************************************/
template <class InputIter, class ForwardIter>
ForwardIter
unchecked_uninit_move(InputIter first, InputIter last, ForwardIter result, std::true_type)
{
return mystl::move(first, last, result);
}
template <class InputIter, class ForwardIter>
ForwardIter
unchecked_uninit_move(InputIter first, InputIter last, ForwardIter result, std::false_type)
{
ForwardIter cur = result;
try
{
for (; first != last; ++first, ++cur)
{
mystl::construct(&*cur, mystl::move(*first));
}
}
catch (...)
{
mystl::destroy(result, cur);
}
return cur;
}
template <class InputIter, class ForwardIter>
ForwardIter uninitialized_move(InputIter first, InputIter last, ForwardIter result)
{
return mystl::unchecked_uninit_move(first, last, result,
std::is_trivially_move_assignable<
typename iterator_traits<InputIter>::
value_type>{});
}
/*****************************************************************************************/
// uninitialized_move_n
// 把[first, first + n)上的内容移动到以 result 为起始处的空间,返回移动结束的位置
/*****************************************************************************************/
template <class InputIter, class Size, class ForwardIter>
ForwardIter
unchecked_uninit_move_n(InputIter first, Size n, ForwardIter result, std::true_type)
{
return mystl::move(first, first + n, result);
}
template <class InputIter, class Size, class ForwardIter>
ForwardIter
unchecked_uninit_move_n(InputIter first, Size n, ForwardIter result, std::false_type)
{
auto cur = result;
try
{
for (; n > 0; --n, ++first, ++cur)
{
mystl::construct(&*cur, mystl::move(*first));
}
}
catch (...)
{
for (; result != cur; ++result)
mystl::destroy(&*result);
throw;
}
return cur;
}
template <class InputIter, class Size, class ForwardIter>
ForwardIter uninitialized_move_n(InputIter first, Size n, ForwardIter result)
{
return mystl::unchecked_uninit_move_n(first, n, result,
std::is_trivially_move_assignable<
typename iterator_traits<InputIter>::
value_type>{});
}
} // namespace mystl
#endif // !MYTINYSTL_UNINITIALIZED_H_

@ -0,0 +1,563 @@
#ifndef MYTINYSTL_UNORDERED_MAP_H_
#define MYTINYSTL_UNORDERED_MAP_H_
// 这个头文件包含两个模板类 unordered_map 和 unordered_multimap
// 功能与用法与 map 和 multimap 类似,不同的是使用 hashtable 作为底层实现机制,容器内的元素不会自动排序
// notes:
//
// 异常保证:
// mystl::unordered_map<Key, T> / mystl::unordered_multimap<Key, T> 满足基本异常保证,对以下等函数做强异常安全保证:
// * emplace
// * emplace_hint
// * insert
#include "hashtable.h"
namespace mystl
{
// 模板类 unordered_map键值不允许重复
// 参数一代表键值类型,参数二代表实值类型,参数三代表哈希函数,缺省使用 mystl::hash
// 参数四代表键值比较方式,缺省使用 mystl::equal_to
template <class Key, class T, class Hash = mystl::hash<Key>, class KeyEqual = mystl::equal_to<Key>>
class unordered_map
{
private:
// 使用 hashtable 作为底层机制
typedef hashtable<mystl::pair<const Key, T>, Hash, KeyEqual> base_type;
base_type ht_;
public:
// 使用 hashtable 的型别
typedef typename base_type::allocator_type allocator_type;
typedef typename base_type::key_type key_type;
typedef typename base_type::mapped_type mapped_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::hasher hasher;
typedef typename base_type::key_equal key_equal;
typedef typename base_type::size_type size_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::pointer pointer;
typedef typename base_type::const_pointer const_pointer;
typedef typename base_type::reference reference;
typedef typename base_type::const_reference const_reference;
typedef typename base_type::iterator iterator;
typedef typename base_type::const_iterator const_iterator;
typedef typename base_type::local_iterator local_iterator;
typedef typename base_type::const_local_iterator const_local_iterator;
allocator_type get_allocator() const { return ht_.get_allocator(); }
public:
// 构造、复制、移动、析构函数
unordered_map()
:ht_(100, Hash(), KeyEqual())
{
}
explicit unordered_map(size_type bucket_count,
const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual())
:ht_(bucket_count, hash, equal)
{
}
template <class InputIterator>
unordered_map(InputIterator first, InputIterator last,
const size_type bucket_count = 100,
const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual())
: ht_(mystl::max(bucket_count, static_cast<size_type>(mystl::distance(first, last))), hash, equal)
{
for (; first != last; ++first)
ht_.insert_unique_noresize(*first);
}
unordered_map(std::initializer_list<value_type> ilist,
const size_type bucket_count = 100,
const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual())
:ht_(mystl::max(bucket_count, static_cast<size_type>(ilist.size())), hash, equal)
{
for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)
ht_.insert_unique_noresize(*first);
}
unordered_map(const unordered_map& rhs)
:ht_(rhs.ht_)
{
}
unordered_map(unordered_map&& rhs) noexcept
:ht_(mystl::move(rhs.ht_))
{
}
unordered_map& operator=(const unordered_map& rhs)
{
ht_ = rhs.ht_;
return *this;
}
unordered_map& operator=(unordered_map&& rhs)
{
ht_ = mystl::move(rhs.ht_);
return *this;
}
unordered_map& operator=(std::initializer_list<value_type> ilist)
{
ht_.clear();
ht_.reserve(ilist.size());
for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)
ht_.insert_unique_noresize(*first);
return *this;
}
~unordered_map() = default;
// 迭代器相关
iterator begin() noexcept
{ return ht_.begin(); }
const_iterator begin() const noexcept
{ return ht_.begin(); }
iterator end() noexcept
{ return ht_.end(); }
const_iterator end() const noexcept
{ return ht_.end(); }
const_iterator cbegin() const noexcept
{ return ht_.cbegin(); }
const_iterator cend() const noexcept
{ return ht_.cend(); }
// 容量相关
bool empty() const noexcept { return ht_.empty(); }
size_type size() const noexcept { return ht_.size(); }
size_type max_size() const noexcept { return ht_.max_size(); }
// 修改容器操作
// empalce / empalce_hint
template <class ...Args>
pair<iterator, bool> emplace(Args&& ...args)
{ return ht_.emplace_unique(mystl::forward<Args>(args)...); }
template <class ...Args>
iterator emplace_hint(const_iterator hint, Args&& ...args)
{ return ht_.emplace_unique_use_hint(hint, mystl::forward<Args>(args)...); }
// insert
pair<iterator, bool> insert(const value_type& value)
{ return ht_.insert_unique(value); }
pair<iterator, bool> insert(value_type&& value)
{ return ht_.emplace_unique(mystl::move(value)); }
iterator insert(const_iterator hint, const value_type& value)
{ return ht_.insert_unique_use_hint(hint, value); }
iterator insert(const_iterator hint, value_type&& value)
{ return ht_.emplace_unique_use_hint(hint, mystl::move(value)); }
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{ ht_.insert_unique(first, last); }
// erase / clear
void erase(iterator it)
{ ht_.erase(it); }
void erase(iterator first, iterator last)
{ ht_.erase(first, last); }
size_type erase(const key_type& key)
{ return ht_.erase_unique(key); }
void clear()
{ ht_.clear(); }
void swap(unordered_map& other) noexcept
{ ht_.swap(other.ht_); }
// 查找相关
mapped_type& at(const key_type& key)
{
iterator it = ht_.find(key);
THROW_OUT_OF_RANGE_IF(it.node == nullptr, "unordered_map<Key, T> no such element exists");
return it->second;
}
const mapped_type& at(const key_type& key) const
{
iterator it = ht_.find(key);
THROW_OUT_OF_RANGE_IF(it.node == nullptr, "unordered_map<Key, T> no such element exists");
return it->second;
}
mapped_type& operator[](const key_type& key)
{
iterator it = ht_.find(key);
if (it.node == nullptr)
it = ht_.emplace_unique(key, T{}).first;
return it->second;
}
mapped_type& operator[](key_type&& key)
{
iterator it = ht_.find(key);
if (it.node == nullptr)
it = ht_.emplace_unique(mystl::move(key), T{}).first;
return it->second;
}
size_type count(const key_type& key) const
{ return ht_.count(key); }
iterator find(const key_type& key)
{ return ht_.find(key); }
const_iterator find(const key_type& key) const
{ return ht_.find(key); }
pair<iterator, iterator> equal_range(const key_type& key)
{ return ht_.equal_range_unique(key); }
pair<const_iterator, const_iterator> equal_range(const key_type& key) const
{ return ht_.equal_range_unique(key); }
// bucket interface
local_iterator begin(size_type n) noexcept
{ return ht_.begin(n); }
const_local_iterator begin(size_type n) const noexcept
{ return ht_.begin(n); }
const_local_iterator cbegin(size_type n) const noexcept
{ return ht_.cbegin(n); }
local_iterator end(size_type n) noexcept
{ return ht_.end(n); }
const_local_iterator end(size_type n) const noexcept
{ return ht_.end(n); }
const_local_iterator cend(size_type n) const noexcept
{ return ht_.cend(n); }
size_type bucket_count() const noexcept
{ return ht_.bucket_count(); }
size_type max_bucket_count() const noexcept
{ return ht_.max_bucket_count(); }
size_type bucket_size(size_type n) const noexcept
{ return ht_.bucket_size(n); }
size_type bucket(const key_type& key) const
{ return ht_.bucket(key); }
// hash policy
float load_factor() const noexcept { return ht_.load_factor(); }
float max_load_factor() const noexcept { return ht_.max_load_factor(); }
void max_load_factor(float ml) { ht_.max_load_factor(ml); }
void rehash(size_type count) { ht_.rehash(count); }
void reserve(size_type count) { ht_.reserve(count); }
hasher hash_fcn() const { return ht_.hash_fcn(); }
key_equal key_eq() const { return ht_.key_eq(); }
public:
friend bool operator==(const unordered_map& lhs, const unordered_map& rhs)
{
return lhs.ht_.equal_range_unique(rhs.ht_);
}
friend bool operator!=(const unordered_map& lhs, const unordered_map& rhs)
{
return !lhs.ht_.equal_range_unique(rhs.ht_);
}
};
// 重载比较操作符
template <class Key, class T, class Hash, class KeyEqual>
bool operator==(const unordered_map<Key, T, Hash, KeyEqual>& lhs,
const unordered_map<Key, T, Hash, KeyEqual>& rhs)
{
return lhs == rhs;
}
template <class Key, class T, class Hash, class KeyEqual>
bool operator!=(const unordered_map<Key, T, Hash, KeyEqual>& lhs,
const unordered_map<Key, T, Hash, KeyEqual>& rhs)
{
return lhs != rhs;
}
// 重载 mystl 的 swap
template <class Key, class T, class Hash, class KeyEqual>
void swap(unordered_map<Key, T, Hash, KeyEqual>& lhs,
unordered_map<Key, T, Hash, KeyEqual>& rhs)
{
lhs.swap(rhs);
}
/*****************************************************************************************/
// 模板类 unordered_multimap键值允许重复
// 参数一代表键值类型,参数二代表实值类型,参数三代表哈希函数,缺省使用 mystl::hash
// 参数四代表键值比较方式,缺省使用 mystl::equal_to
template <class Key, class T, class Hash = mystl::hash<Key>, class KeyEqual = mystl::equal_to<Key>>
class unordered_multimap
{
private:
// 使用 hashtable 作为底层机制
typedef hashtable<pair<const Key, T>, Hash, KeyEqual> base_type;
base_type ht_;
public:
// 使用 hashtable 的型别
typedef typename base_type::allocator_type allocator_type;
typedef typename base_type::key_type key_type;
typedef typename base_type::mapped_type mapped_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::hasher hasher;
typedef typename base_type::key_equal key_equal;
typedef typename base_type::size_type size_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::pointer pointer;
typedef typename base_type::const_pointer const_pointer;
typedef typename base_type::reference reference;
typedef typename base_type::const_reference const_reference;
typedef typename base_type::iterator iterator;
typedef typename base_type::const_iterator const_iterator;
typedef typename base_type::local_iterator local_iterator;
typedef typename base_type::const_local_iterator const_local_iterator;
allocator_type get_allocator() const { return ht_.get_allocator(); }
public:
// 构造、复制、移动函数
unordered_multimap()
:ht_(100, Hash(), KeyEqual())
{
}
explicit unordered_multimap(size_type bucket_count,
const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual())
:ht_(bucket_count, hash, equal)
{
}
template <class InputIterator>
unordered_multimap(InputIterator first, InputIterator last,
const size_type bucket_count = 100,
const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual())
:ht_(mystl::max(bucket_count, static_cast<size_type>(mystl::distance(first, last))), hash, equal)
{
for (; first != last; ++first)
ht_.insert_multi_noresize(*first);
}
unordered_multimap(std::initializer_list<value_type> ilist,
const size_type bucket_count = 100,
const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual())
:ht_(mystl::max(bucket_count, static_cast<size_type>(ilist.size())), hash, equal)
{
for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)
ht_.insert_multi_noresize(*first);
}
unordered_multimap(const unordered_multimap& rhs)
:ht_(rhs.ht_)
{
}
unordered_multimap(unordered_multimap&& rhs) noexcept
:ht_(mystl::move(rhs.ht_))
{
}
unordered_multimap& operator=(const unordered_multimap& rhs)
{
ht_ = rhs.ht_;
return *this;
}
unordered_multimap& operator=(unordered_multimap&& rhs)
{
ht_ = mystl::move(rhs.ht_);
return *this;
}
unordered_multimap& operator=(std::initializer_list<value_type> ilist)
{
ht_.clear();
ht_.reserve(ilist.size());
for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)
ht_.insert_multi_noresize(*first);
return *this;
}
~unordered_multimap() = default;
// 迭代器相关
iterator begin() noexcept
{ return ht_.begin(); }
const_iterator begin() const noexcept
{ return ht_.begin(); }
iterator end() noexcept
{ return ht_.end(); }
const_iterator end() const noexcept
{ return ht_.end(); }
const_iterator cbegin() const noexcept
{ return ht_.cbegin(); }
const_iterator cend() const noexcept
{ return ht_.cend(); }
// 容量相关
bool empty() const noexcept { return ht_.empty(); }
size_type size() const noexcept { return ht_.size(); }
size_type max_size() const noexcept { return ht_.max_size(); }
// 修改容器相关
// emplace / emplace_hint
template <class ...Args>
iterator emplace(Args&& ...args)
{ return ht_.emplace_multi(mystl::forward<Args>(args)...); }
template <class ...Args>
iterator emplace_hint(const_iterator hint, Args&& ...args)
{ return ht_.emplace_multi_use_hint(hint, mystl::forward<Args>(args)...); }
// insert
iterator insert(const value_type& value)
{ return ht_.insert_multi(value); }
iterator insert(value_type&& value)
{ return ht_.emplace_multi(mystl::move(value)); }
iterator insert(const_iterator hint, const value_type& value)
{ return ht_.insert_multi_use_hint(hint, value); }
iterator insert(const_iterator hint, value_type&& value)
{ return ht_.emplace_multi_use_hint(hint, mystl::move(value)); }
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{ ht_.insert_multi(first, last); }
// erase / clear
void erase(iterator it)
{ ht_.erase(it); }
void erase(iterator first, iterator last)
{ ht_.erase(first, last); }
size_type erase(const key_type& key)
{ return ht_.erase_multi(key); }
void clear()
{ ht_.clear(); }
void swap(unordered_multimap& other) noexcept
{ ht_.swap(other.ht_); }
// 查找相关
size_type count(const key_type& key) const
{ return ht_.count(key); }
iterator find(const key_type& key)
{ return ht_.find(key); }
const_iterator find(const key_type& key) const
{ return ht_.find(key); }
pair<iterator, iterator> equal_range(const key_type& key)
{ return ht_.equal_range_multi(key); }
pair<const_iterator, const_iterator> equal_range(const key_type& key) const
{ return ht_.equal_range_multi(key); }
// bucket interface
local_iterator begin(size_type n) noexcept
{ return ht_.begin(n); }
const_local_iterator begin(size_type n) const noexcept
{ return ht_.begin(n); }
const_local_iterator cbegin(size_type n) const noexcept
{ return ht_.cbegin(n); }
local_iterator end(size_type n) noexcept
{ return ht_.end(n); }
const_local_iterator end(size_type n) const noexcept
{ return ht_.end(n); }
const_local_iterator cend(size_type n) const noexcept
{ return ht_.cend(n); }
size_type bucket_count() const noexcept
{ return ht_.bucket_count(); }
size_type max_bucket_count() const noexcept
{ return ht_.max_bucket_count(); }
size_type bucket_size(size_type n) const noexcept
{ return ht_.bucket_size(n); }
size_type bucket(const key_type& key) const
{ return ht_.bucket(key); }
// hash policy
float load_factor() const noexcept { return ht_.load_factor(); }
float max_load_factor() const noexcept { return ht_.max_load_factor(); }
void max_load_factor(float ml) { ht_.max_load_factor(ml); }
void rehash(size_type count) { ht_.rehash(count); }
void reserve(size_type count) { ht_.reserve(count); }
hasher hash_fcn() const { return ht_.hash_fcn(); }
key_equal key_eq() const { return ht_.key_eq(); }
public:
friend bool operator==(const unordered_multimap& lhs, const unordered_multimap& rhs)
{
return lhs.ht_.equal_range_multi(rhs.ht_);
}
friend bool operator!=(const unordered_multimap& lhs, const unordered_multimap& rhs)
{
return !lhs.ht_.equal_range_multi(rhs.ht_);
}
};
// 重载比较操作符
template <class Key, class T, class Hash, class KeyEqual>
bool operator==(const unordered_multimap<Key, T, Hash, KeyEqual>& lhs,
const unordered_multimap<Key, T, Hash, KeyEqual>& rhs)
{
return lhs == rhs;
}
template <class Key, class T, class Hash, class KeyEqual>
bool operator!=(const unordered_multimap<Key, T, Hash, KeyEqual>& lhs,
const unordered_multimap<Key, T, Hash, KeyEqual>& rhs)
{
return lhs != rhs;
}
// 重载 mystl 的 swap
template <class Key, class T, class Hash, class KeyEqual>
void swap(unordered_multimap<Key, T, Hash, KeyEqual>& lhs,
unordered_multimap<Key, T, Hash, KeyEqual>& rhs)
{
lhs.swap(rhs);
}
} // namespace mystl
#endif // !MYTINYSTL_UNORDERED_MAP_H_

@ -0,0 +1,534 @@
#ifndef MYTINYSTL_UNORDERED_SET_H_
#define MYTINYSTL_UNORDERED_SET_H_
// 这个头文件包含两个模板类 unordered_set 和 unordered_multiset
// 功能与用法与 set 和 multiset 类似,不同的是使用 hashtable 作为底层实现机制,容器中的元素不会自动排序
// notes:
//
// 异常保证:
// mystl::unordered_set<Key> / mystl::unordered_multiset<Key> 满足基本异常保证,对以下等函数做强异常安全保证:
// * emplace
// * emplace_hint
// * insert
#include "hashtable.h"
namespace mystl
{
// 模板类 unordered_set键值不允许重复
// 参数一代表键值类型,参数二代表哈希函数,缺省使用 mystl::hash
// 参数三代表键值比较方式,缺省使用 mystl::equal_to
template <class Key, class Hash = mystl::hash<Key>, class KeyEqual = mystl::equal_to<Key>>
class unordered_set
{
private:
// 使用 hashtable 作为底层机制
typedef hashtable<Key, Hash, KeyEqual> base_type;
base_type ht_;
public:
// 使用 hashtable 的型别
typedef typename base_type::allocator_type allocator_type;
typedef typename base_type::key_type key_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::hasher hasher;
typedef typename base_type::key_equal key_equal;
typedef typename base_type::size_type size_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::pointer pointer;
typedef typename base_type::const_pointer const_pointer;
typedef typename base_type::reference reference;
typedef typename base_type::const_reference const_reference;
typedef typename base_type::const_iterator iterator;
typedef typename base_type::const_iterator const_iterator;
typedef typename base_type::const_local_iterator local_iterator;
typedef typename base_type::const_local_iterator const_local_iterator;
allocator_type get_allocator() const { return ht_.get_allocator(); }
public:
// 构造、复制、移动函数
unordered_set()
:ht_(100, Hash(), KeyEqual())
{
}
explicit unordered_set(size_type bucket_count,
const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual())
:ht_(bucket_count, hash, equal)
{
}
template <class InputIterator>
unordered_set(InputIterator first, InputIterator last,
const size_type bucket_count = 100,
const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual())
: ht_(mystl::max(bucket_count, static_cast<size_type>(mystl::distance(first, last))), hash, equal)
{
for (; first != last; ++first)
ht_.insert_unique_noresize(*first);
}
unordered_set(std::initializer_list<value_type> ilist,
const size_type bucket_count = 100,
const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual())
:ht_(mystl::max(bucket_count, static_cast<size_type>(ilist.size())), hash, equal)
{
for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)
ht_.insert_unique_noresize(*first);
}
unordered_set(const unordered_set& rhs)
:ht_(rhs.ht_)
{
}
unordered_set(unordered_set&& rhs) noexcept
: ht_(mystl::move(rhs.ht_))
{
}
unordered_set& operator=(const unordered_set& rhs)
{
ht_ = rhs.ht_;
return *this;
}
unordered_set& operator=(unordered_set&& rhs)
{
ht_ = mystl::move(rhs.ht_);
return *this;
}
unordered_set& operator=(std::initializer_list<value_type> ilist)
{
ht_.clear();
ht_.reserve(ilist.size());
for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)
ht_.insert_unique_noresize(*first);
return *this;
}
~unordered_set() = default;
// 迭代器相关
iterator begin() noexcept
{ return ht_.begin(); }
const_iterator begin() const noexcept
{ return ht_.begin(); }
iterator end() noexcept
{ return ht_.end(); }
const_iterator end() const noexcept
{ return ht_.end(); }
const_iterator cbegin() const noexcept
{ return ht_.cbegin(); }
const_iterator cend() const noexcept
{ return ht_.cend(); }
// 容量相关
bool empty() const noexcept { return ht_.empty(); }
size_type size() const noexcept { return ht_.size(); }
size_type max_size() const noexcept { return ht_.max_size(); }
// 修改容器操作
// empalce / empalce_hint
template <class ...Args>
pair<iterator, bool> emplace(Args&& ...args)
{ return ht_.emplace_unique(mystl::forward<Args>(args)...); }
template <class ...Args>
iterator emplace_hint(const_iterator hint, Args&& ...args)
{ return ht_.emplace_unique_use_hint(hint, mystl::forward<Args>(args)...); }
// insert
pair<iterator, bool> insert(const value_type& value)
{ return ht_.insert_unique(value); }
pair<iterator, bool> insert(value_type&& value)
{ return ht_.emplace_unique(mystl::move(value)); }
iterator insert(const_iterator hint, const value_type& value)
{ return ht_.insert_unique_use_hint(hint, value); }
iterator insert(const_iterator hint, value_type&& value)
{ return ht_.emplace_unique_use_hint(hint, mystl::move(value)); }
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{ ht_.insert_unique(first, last); }
// erase / clear
void erase(iterator it)
{ ht_.erase(it); }
void erase(iterator first, iterator last)
{ ht_.erase(first, last); }
size_type erase(const key_type& key)
{ return ht_.erase_unique(key); }
void clear()
{ ht_.clear(); }
void swap(unordered_set& other) noexcept
{ ht_.swap(other.ht_); }
// 查找相关
size_type count(const key_type& key) const
{ return ht_.count(key); }
iterator find(const key_type& key)
{ return ht_.find(key); }
const_iterator find(const key_type& key) const
{ return ht_.find(key); }
pair<iterator, iterator> equal_range(const key_type& key)
{ return ht_.equal_range_unique(key); }
pair<const_iterator, const_iterator> equal_range(const key_type& key) const
{ return ht_.equal_range_unique(key); }
// bucket interface
local_iterator begin(size_type n) noexcept
{ return ht_.begin(n); }
const_local_iterator begin(size_type n) const noexcept
{ return ht_.begin(n); }
const_local_iterator cbegin(size_type n) const noexcept
{ return ht_.cbegin(n); }
local_iterator end(size_type n) noexcept
{ return ht_.end(n); }
const_local_iterator end(size_type n) const noexcept
{ return ht_.end(n); }
const_local_iterator cend(size_type n) const noexcept
{ return ht_.cend(n); }
size_type bucket_count() const noexcept
{ return ht_.bucket_count(); }
size_type max_bucket_count() const noexcept
{ return ht_.max_bucket_count(); }
size_type bucket_size(size_type n) const noexcept
{ return ht_.bucket_size(n); }
size_type bucket(const key_type& key) const
{ return ht_.bucket(key); }
// hash policy
float load_factor() const noexcept { return ht_.load_factor(); }
float max_load_factor() const noexcept { return ht_.max_load_factor(); }
void max_load_factor(float ml) { ht_.max_load_factor(ml); }
void rehash(size_type count) { ht_.rehash(count); }
void reserve(size_type count) { ht_.reserve(count); }
hasher hash_fcn() const { return ht_.hash_fcn(); }
key_equal key_eq() const { return ht_.key_eq(); }
public:
friend bool operator==(const unordered_set& lhs, const unordered_set& rhs)
{
return lhs.ht_.equal_range_unique(rhs.ht_);
}
friend bool operator!=(const unordered_set& lhs, const unordered_set& rhs)
{
return !lhs.ht_.equal_range_unique(rhs.ht_);
}
};
// 重载比较操作符
template <class Key, class Hash, class KeyEqual, class Alloc>
bool operator==(const unordered_set<Key, Hash, KeyEqual>& lhs,
const unordered_set<Key, Hash, KeyEqual>& rhs)
{
return lhs == rhs;
}
template <class Key, class Hash, class KeyEqual, class Alloc>
bool operator!=(const unordered_set<Key, Hash, KeyEqual>& lhs,
const unordered_set<Key, Hash, KeyEqual>& rhs)
{
return lhs != rhs;
}
// 重载 mystl 的 swap
template <class Key, class Hash, class KeyEqual, class Alloc>
void swap(unordered_set<Key, Hash, KeyEqual>& lhs,
unordered_set<Key, Hash, KeyEqual>& rhs)
{
lhs.swap(rhs);
}
/*****************************************************************************************/
// 模板类 unordered_multiset键值允许重复
// 参数一代表键值类型,参数二代表哈希函数,缺省使用 mystl::hash
// 参数三代表键值比较方式,缺省使用 mystl::equal_to
template <class Key, class Hash = mystl::hash<Key>, class KeyEqual = mystl::equal_to<Key>>
class unordered_multiset
{
private:
// 使用 hashtable 作为底层机制
typedef hashtable<Key, Hash, KeyEqual> base_type;
base_type ht_;
public:
// 使用 hashtable 的型别
typedef typename base_type::allocator_type allocator_type;
typedef typename base_type::key_type key_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::hasher hasher;
typedef typename base_type::key_equal key_equal;
typedef typename base_type::size_type size_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::pointer pointer;
typedef typename base_type::const_pointer const_pointer;
typedef typename base_type::reference reference;
typedef typename base_type::const_reference const_reference;
typedef typename base_type::const_iterator iterator;
typedef typename base_type::const_iterator const_iterator;
typedef typename base_type::const_local_iterator local_iterator;
typedef typename base_type::const_local_iterator const_local_iterator;
allocator_type get_allocator() const { return ht_.get_allocator(); }
public:
// 构造、复制、移动函数
unordered_multiset()
:ht_(100, Hash(), KeyEqual())
{
}
explicit unordered_multiset(size_type bucket_count,
const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual())
:ht_(bucket_count, hash, equal)
{
}
template <class InputIterator>
unordered_multiset(InputIterator first, InputIterator last,
const size_type bucket_count = 100,
const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual())
: ht_(mystl::max(bucket_count, static_cast<size_type>(mystl::distance(first, last))), hash, equal)
{
for (; first != last; ++first)
ht_.insert_multi_noresize(*first);
}
unordered_multiset(std::initializer_list<value_type> ilist,
const size_type bucket_count = 100,
const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual())
:ht_(mystl::max(bucket_count, static_cast<size_type>(ilist.size())), hash, equal)
{
for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)
ht_.insert_multi_noresize(*first);
}
unordered_multiset(const unordered_multiset& rhs)
:ht_(rhs.ht_)
{
}
unordered_multiset(unordered_multiset&& rhs) noexcept
: ht_(mystl::move(rhs.ht_))
{
}
unordered_multiset& operator=(const unordered_multiset& rhs)
{
ht_ = rhs.ht_;
return *this;
}
unordered_multiset& operator=(unordered_multiset&& rhs)
{
ht_ = mystl::move(rhs.ht_);
return *this;
}
unordered_multiset& operator=(std::initializer_list<value_type> ilist)
{
ht_.clear();
ht_.reserve(ilist.size());
for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first)
ht_.insert_multi_noresize(*first);
return *this;
}
~unordered_multiset() = default;
// 迭代器相关
iterator begin() noexcept
{ return ht_.begin(); }
const_iterator begin() const noexcept
{ return ht_.begin(); }
iterator end() noexcept
{ return ht_.end(); }
const_iterator end() const noexcept
{ return ht_.end(); }
const_iterator cbegin() const noexcept
{ return ht_.cbegin(); }
const_iterator cend() const noexcept
{ return ht_.cend(); }
// 容量相关
bool empty() const noexcept { return ht_.empty(); }
size_type size() const noexcept { return ht_.size(); }
size_type max_size() const noexcept { return ht_.max_size(); }
// 修改容器相关
// emplace / emplace_hint
template <class ...Args>
iterator emplace(Args&& ...args)
{ return ht_.emplace_multi(mystl::forward<Args>(args)...); }
template <class ...Args>
iterator emplace_hint(const_iterator hint, Args&& ...args)
{ return ht_.emplace_multi_use_hint(hint, mystl::forward<Args>(args)...); }
// insert
iterator insert(const value_type& value)
{ return ht_.insert_multi(value); }
iterator insert(value_type&& value)
{ return ht_.emplace_multi(mystl::move(value)); }
iterator insert(const_iterator hint, const value_type& value)
{ return ht_.insert_multi_use_hint(hint, value); }
iterator insert(const_iterator hint, value_type&& value)
{ return ht_.emplace_multi_use_hint(hint, mystl::move(value)); }
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{ ht_.insert_multi(first, last); }
// erase / clear
void erase(iterator it)
{ ht_.erase(it); }
void erase(iterator first, iterator last)
{ ht_.erase(first, last); }
size_type erase(const key_type& key)
{ return ht_.erase_multi(key); }
void clear()
{ ht_.clear(); }
void swap(unordered_multiset& other) noexcept
{ ht_.swap(other.ht_); }
// 查找相关
size_type count(const key_type& key) const
{ return ht_.count(key); }
iterator find(const key_type& key)
{ return ht_.find(key); }
const_iterator find(const key_type& key) const
{ return ht_.find(key); }
pair<iterator, iterator> equal_range(const key_type& key)
{ return ht_.equal_range_multi(key); }
pair<const_iterator, const_iterator> equal_range(const key_type& key) const
{ return ht_.equal_range_multi(key); }
// bucket interface
local_iterator begin(size_type n) noexcept
{ return ht_.begin(n); }
const_local_iterator begin(size_type n) const noexcept
{ return ht_.begin(n); }
const_local_iterator cbegin(size_type n) const noexcept
{ return ht_.cbegin(n); }
local_iterator end(size_type n) noexcept
{ return ht_.end(n); }
const_local_iterator end(size_type n) const noexcept
{ return ht_.end(n); }
const_local_iterator cend(size_type n) const noexcept
{ return ht_.cend(n); }
size_type bucket_count() const noexcept
{ return ht_.bucket_count(); }
size_type max_bucket_count() const noexcept
{ return ht_.max_bucket_count(); }
size_type bucket_size(size_type n) const noexcept
{ return ht_.bucket_size(n); }
size_type bucket(const key_type& key) const
{ return ht_.bucket(key); }
// hash policy
float load_factor() const noexcept { return ht_.load_factor(); }
float max_load_factor() const noexcept { return ht_.max_load_factor(); }
void max_load_factor(float ml) { ht_.max_load_factor(ml); }
void rehash(size_type count) { ht_.rehash(count); }
void reserve(size_type count) { ht_.reserve(count); }
hasher hash_fcn() const { return ht_.hash_fcn(); }
key_equal key_eq() const { return ht_.key_eq(); }
public:
friend bool operator==(const unordered_multiset& lhs, const unordered_multiset& rhs)
{
return lhs.ht_.equal_range_multi(rhs.ht_);
}
friend bool operator!=(const unordered_multiset& lhs, const unordered_multiset& rhs)
{
return !lhs.ht_.equal_range_multi(rhs.ht_);
}
};
// 重载比较操作符
template <class Key, class Hash, class KeyEqual, class Alloc>
bool operator==(const unordered_multiset<Key, Hash, KeyEqual>& lhs,
const unordered_multiset<Key, Hash, KeyEqual>& rhs)
{
return lhs == rhs;
}
template <class Key, class Hash, class KeyEqual, class Alloc>
bool operator!=(const unordered_multiset<Key, Hash, KeyEqual>& lhs,
const unordered_multiset<Key, Hash, KeyEqual>& rhs)
{
return lhs != rhs;
}
// 重载 mystl 的 swap
template <class Key, class Hash, class KeyEqual, class Alloc>
void swap(unordered_multiset<Key, Hash, KeyEqual>& lhs,
unordered_multiset<Key, Hash, KeyEqual>& rhs)
{
lhs.swap(rhs);
}
} // namespace mystl
#endif // !MYTINYSTL_UNORDERED_SET_H_

@ -0,0 +1,297 @@
#ifndef MYTINYSTL_UTIL_H_
#define MYTINYSTL_UTIL_H_
// 这个文件包含一些通用工具,包括 move, forward, swap 等函数,以及 pair 等
#include <cstddef>
#include "type_traits.h"
namespace mystl
{
// move
template <class T>
typename std::remove_reference<T>::type&& move(T&& arg) noexcept
{
return static_cast<typename std::remove_reference<T>::type&&>(arg);
}
// forward
template <class T>
T&& forward(typename std::remove_reference<T>::type& arg) noexcept
{
return static_cast<T&&>(arg);
}
template <class T>
T&& forward(typename std::remove_reference<T>::type&& arg) noexcept
{
static_assert(!std::is_lvalue_reference<T>::value, "bad forward");
return static_cast<T&&>(arg);
}
// swap
template <class Tp>
void swap(Tp& lhs, Tp& rhs)
{
auto tmp(mystl::move(lhs));
lhs = mystl::move(rhs);
rhs = mystl::move(tmp);
}
template <class ForwardIter1, class ForwardIter2>
ForwardIter2 swap_range(ForwardIter1 first1, ForwardIter1 last1, ForwardIter2 first2)
{
for (; first1 != last1; ++first1, (void) ++first2)
mystl::swap(*first1, *first2);
return first2;
}
template <class Tp, size_t N>
void swap(Tp(&a)[N], Tp(&b)[N])
{
mystl::swap_range(a, a + N, b);
}
// --------------------------------------------------------------------------------------
// pair
// 结构体模板 : pair
// 两个模板参数分别表示两个数据的类型
// 用 first 和 second 来分别取出第一个数据和第二个数据
template <class Ty1, class Ty2>
struct pair
{
typedef Ty1 first_type;
typedef Ty2 second_type;
first_type first; // 保存第一个数据
second_type second; // 保存第二个数据
// default constructiable
template <class Other1 = Ty1, class Other2 = Ty2,
typename = typename std::enable_if<
std::is_default_constructible<Other1>::value &&
std::is_default_constructible<Other2>::value, void>::type>
constexpr pair()
: first(), second()
{
}
// implicit constructiable for this type
template <class U1 = Ty1, class U2 = Ty2,
typename std::enable_if<
std::is_copy_constructible<U1>::value &&
std::is_copy_constructible<U2>::value &&
std::is_convertible<const U1&, Ty1>::value &&
std::is_convertible<const U2&, Ty2>::value, int>::type = 0>
constexpr pair(const Ty1& a, const Ty2& b)
: first(a), second(b)
{
}
// explicit constructible for this type
template <class U1 = Ty1, class U2 = Ty2,
typename std::enable_if<
std::is_copy_constructible<U1>::value &&
std::is_copy_constructible<U2>::value &&
(!std::is_convertible<const U1&, Ty1>::value ||
!std::is_convertible<const U2&, Ty2>::value), int>::type = 0>
explicit constexpr pair(const Ty1& a, const Ty2& b)
: first(a), second(b)
{
}
pair(const pair& rhs) = default;
pair(pair&& rhs) = default;
// implicit constructiable for other type
template <class Other1, class Other2,
typename std::enable_if<
std::is_constructible<Ty1, Other1>::value &&
std::is_constructible<Ty2, Other2>::value &&
std::is_convertible<Other1&&, Ty1>::value &&
std::is_convertible<Other2&&, Ty2>::value, int>::type = 0>
constexpr pair(Other1&& a, Other2&& b)
: first(mystl::forward<Other1>(a)),
second(mystl::forward<Other2>(b))
{
}
// explicit constructiable for other type
template <class Other1, class Other2,
typename std::enable_if<
std::is_constructible<Ty1, Other1>::value &&
std::is_constructible<Ty2, Other2>::value &&
(!std::is_convertible<Other1, Ty1>::value ||
!std::is_convertible<Other2, Ty2>::value), int>::type = 0>
explicit constexpr pair(Other1&& a, Other2&& b)
: first(mystl::forward<Other1>(a)),
second(mystl::forward<Other2>(b))
{
}
// implicit constructiable for other pair
template <class Other1, class Other2,
typename std::enable_if<
std::is_constructible<Ty1, const Other1&>::value &&
std::is_constructible<Ty2, const Other2&>::value &&
std::is_convertible<const Other1&, Ty1>::value &&
std::is_convertible<const Other2&, Ty2>::value, int>::type = 0>
constexpr pair(const pair<Other1, Other2>& other)
: first(other.first),
second(other.second)
{
}
// explicit constructiable for other pair
template <class Other1, class Other2,
typename std::enable_if<
std::is_constructible<Ty1, const Other1&>::value &&
std::is_constructible<Ty2, const Other2&>::value &&
(!std::is_convertible<const Other1&, Ty1>::value ||
!std::is_convertible<const Other2&, Ty2>::value), int>::type = 0>
explicit constexpr pair(const pair<Other1, Other2>& other)
: first(other.first),
second(other.second)
{
}
// implicit constructiable for other pair
template <class Other1, class Other2,
typename std::enable_if<
std::is_constructible<Ty1, Other1>::value &&
std::is_constructible<Ty2, Other2>::value &&
std::is_convertible<Other1, Ty1>::value &&
std::is_convertible<Other2, Ty2>::value, int>::type = 0>
constexpr pair(pair<Other1, Other2>&& other)
: first(mystl::forward<Other1>(other.first)),
second(mystl::forward<Other2>(other.second))
{
}
// explicit constructiable for other pair
template <class Other1, class Other2,
typename std::enable_if<
std::is_constructible<Ty1, Other1>::value &&
std::is_constructible<Ty2, Other2>::value &&
(!std::is_convertible<Other1, Ty1>::value ||
!std::is_convertible<Other2, Ty2>::value), int>::type = 0>
explicit constexpr pair(pair<Other1, Other2>&& other)
: first(mystl::forward<Other1>(other.first)),
second(mystl::forward<Other2>(other.second))
{
}
// copy assign for this pair
pair& operator=(const pair& rhs)
{
if (this != &rhs)
{
first = rhs.first;
second = rhs.second;
}
return *this;
}
// move assign for this pair
pair& operator=(pair&& rhs)
{
if (this != &rhs)
{
first = mystl::move(rhs.first);
second = mystl::move(rhs.second);
}
return *this;
}
// copy assign for other pair
template <class Other1, class Other2>
pair& operator=(const pair<Other1, Other2>& other)
{
first = other.first;
second = other.second;
return *this;
}
// move assign for other pair
template <class Other1, class Other2>
pair& operator=(pair<Other1, Other2>&& other)
{
first = mystl::forward<Other1>(other.first);
second = mystl::forward<Other2>(other.second);
return *this;
}
~pair() = default;
void swap(pair& other)
{
if (this != &other)
{
mystl::swap(first, other.first);
mystl::swap(second, other.second);
}
}
};
// 重载比较操作符
template <class Ty1, class Ty2>
bool operator==(const pair<Ty1, Ty2>& lhs, const pair<Ty1, Ty2>& rhs)
{
return lhs.first == rhs.first && lhs.second == rhs.second;
}
template <class Ty1, class Ty2>
bool operator<(const pair<Ty1, Ty2>& lhs, const pair<Ty1, Ty2>& rhs)
{
return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second < rhs.second);
}
template <class Ty1, class Ty2>
bool operator!=(const pair<Ty1, Ty2>& lhs, const pair<Ty1, Ty2>& rhs)
{
return !(lhs == rhs);
}
template <class Ty1, class Ty2>
bool operator>(const pair<Ty1, Ty2>& lhs, const pair<Ty1, Ty2>& rhs)
{
return rhs < lhs;
}
template <class Ty1, class Ty2>
bool operator<=(const pair<Ty1, Ty2>& lhs, const pair<Ty1, Ty2>& rhs)
{
return !(rhs < lhs);
}
template <class Ty1, class Ty2>
bool operator>=(const pair<Ty1, Ty2>& lhs, const pair<Ty1, Ty2>& rhs)
{
return !(lhs < rhs);
}
// 重载 mystl 的 swap
template <class Ty1, class Ty2>
void swap(pair<Ty1, Ty2>& lhs, pair<Ty1, Ty2>& rhs)
{
lhs.swap(rhs);
}
// 全局函数,让两个数据成为一个 pair
template <class Ty1, class Ty2>
pair<Ty1, Ty2> make_pair(Ty1&& first, Ty2&& second)
{
return pair<Ty1, Ty2>(mystl::forward<Ty1>(first), mystl::forward<Ty2>(second));
}
}
#endif // !MYTINYSTL_UTIL_H_

@ -0,0 +1,936 @@
#ifndef MYTINYSTL_VECTOR_H_
#define MYTINYSTL_VECTOR_H_
// 这个头文件包含一个模板类 vector
// vector : 向量
// notes:
//
// 异常保证:
// mystl::vecotr<T> 满足基本异常保证,部分函数无异常保证,并对以下函数做强异常安全保证:
// * emplace
// * emplace_back
// * push_back
// 当 std::is_nothrow_move_assignable<T>::value == true 时,以下函数也满足强异常保证:
// * reserve
// * resize
// * insert
#include <initializer_list>
#include "iterator.h"
#include "memory.h"
#include "util.h"
#include "exceptdef.h"
#include "algo.h"
namespace mystl
{
#ifdef max
#pragma message("#undefing marco max")
#undef max
#endif // max
#ifdef min
#pragma message("#undefing marco min")
#undef min
#endif // min
// 模板类: vector
// 模板参数 T 代表类型
template <class T>
class vector
{
static_assert(!std::is_same<bool, T>::value, "vector<bool> is abandoned in mystl");
public:
// vector 的嵌套型别定义
typedef mystl::allocator<T> allocator_type;
typedef mystl::allocator<T> data_allocator;
typedef typename allocator_type::value_type value_type;
typedef typename allocator_type::pointer pointer;
typedef typename allocator_type::const_pointer const_pointer;
typedef typename allocator_type::reference reference;
typedef typename allocator_type::const_reference const_reference;
typedef typename allocator_type::size_type size_type;
typedef typename allocator_type::difference_type difference_type;
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef mystl::reverse_iterator<iterator> reverse_iterator;
typedef mystl::reverse_iterator<const_iterator> const_reverse_iterator;
allocator_type get_allocator() { return data_allocator(); }
private:
iterator begin_; // 表示目前使用空间的头部
iterator end_; // 表示目前使用空间的尾部
iterator cap_; // 表示目前储存空间的尾部
public:
// 构造、复制、移动、析构函数
vector() noexcept
{ try_init(); }
explicit vector(size_type n)
{ fill_init(n, value_type()); }
vector(size_type n, const value_type& value)
{ fill_init(n, value); }
template <class Iter, typename std::enable_if<
mystl::is_input_iterator<Iter>::value, int>::type = 0>
vector(Iter first, Iter last)
{
MYSTL_DEBUG(!(last < first));
range_init(first, last);
}
vector(const vector& rhs)
{
range_init(rhs.begin_, rhs.end_);
}
vector(vector&& rhs) noexcept
:begin_(rhs.begin_),
end_(rhs.end_),
cap_(rhs.cap_)
{
rhs.begin_ = nullptr;
rhs.end_ = nullptr;
rhs.cap_ = nullptr;
}
vector(std::initializer_list<value_type> ilist)
{
range_init(ilist.begin(), ilist.end());
}
vector& operator=(const vector& rhs);
vector& operator=(vector&& rhs) noexcept;
vector& operator=(std::initializer_list<value_type> ilist)
{
vector tmp(ilist.begin(), ilist.end());
swap(tmp);
return *this;
}
~vector()
{
destroy_and_recover(begin_, end_, cap_ - begin_);
begin_ = end_ = cap_ = nullptr;
}
public:
// 迭代器相关操作
iterator begin() noexcept
{ return begin_; }
const_iterator begin() const noexcept
{ return begin_; }
iterator end() noexcept
{ return end_; }
const_iterator end() const noexcept
{ return end_; }
reverse_iterator rbegin() noexcept
{ return reverse_iterator(end()); }
const_reverse_iterator rbegin() const noexcept
{ return const_reverse_iterator(end()); }
reverse_iterator rend() noexcept
{ return reverse_iterator(begin()); }
const_reverse_iterator rend() const noexcept
{ return const_reverse_iterator(begin()); }
const_iterator cbegin() const noexcept
{ return begin(); }
const_iterator cend() const noexcept
{ return end(); }
const_reverse_iterator crbegin() const noexcept
{ return rbegin(); }
const_reverse_iterator crend() const noexcept
{ return rend(); }
// 容量相关操作
bool empty() const noexcept
{ return begin_ == end_; }
size_type size() const noexcept
{ return static_cast<size_type>(end_ - begin_); }
size_type max_size() const noexcept
{ return static_cast<size_type>(-1) / sizeof(T); }
size_type capacity() const noexcept
{ return static_cast<size_type>(cap_ - begin_); }
void reserve(size_type n);
void shrink_to_fit();
// 访问元素相关操作
reference operator[](size_type n)
{
MYSTL_DEBUG(n < size());
return *(begin_ + n);
}
const_reference operator[](size_type n) const
{
MYSTL_DEBUG(n < size());
return *(begin_ + n);
}
reference at(size_type n)
{
THROW_OUT_OF_RANGE_IF(!(n < size()), "vector<T>::at() subscript out of range");
return (*this)[n];
}
const_reference at(size_type n) const
{
THROW_OUT_OF_RANGE_IF(!(n < size()), "vector<T>::at() subscript out of range");
return (*this)[n];
}
reference front()
{
MYSTL_DEBUG(!empty());
return *begin_;
}
const_reference front() const
{
MYSTL_DEBUG(!empty());
return *begin_;
}
reference back()
{
MYSTL_DEBUG(!empty());
return *(end_ - 1);
}
const_reference back() const
{
MYSTL_DEBUG(!empty());
return *(end_ - 1);
}
pointer data() noexcept { return begin_; }
const_pointer data() const noexcept { return begin_; }
// 修改容器相关操作
// assign
void assign(size_type n, const value_type& value)
{ fill_assign(n, value); }
template <class Iter, typename std::enable_if<
mystl::is_input_iterator<Iter>::value, int>::type = 0>
void assign(Iter first, Iter last)
{
MYSTL_DEBUG(!(last < first));
copy_assign(first, last, iterator_category(first));
}
void assign(std::initializer_list<value_type> il)
{ copy_assign(il.begin(), il.end(), mystl::forward_iterator_tag{}); }
// emplace / emplace_back
template <class... Args>
iterator emplace(const_iterator pos, Args&& ...args);
template <class... Args>
void emplace_back(Args&& ...args);
// push_back / pop_back
void push_back(const value_type& value);
void push_back(value_type&& value)
{ emplace_back(mystl::move(value)); }
void pop_back();
// insert
iterator insert(const_iterator pos, const value_type& value);
iterator insert(const_iterator pos, value_type&& value)
{ return emplace(pos, mystl::move(value)); }
iterator insert(const_iterator pos, size_type n, const value_type& value)
{
MYSTL_DEBUG(pos >= begin() && pos <= end());
return fill_insert(const_cast<iterator>(pos), n, value);
}
template <class Iter, typename std::enable_if<
mystl::is_input_iterator<Iter>::value, int>::type = 0>
void insert(const_iterator pos, Iter first, Iter last)
{
MYSTL_DEBUG(pos >= begin() && pos <= end() && !(last < first));
copy_insert(const_cast<iterator>(pos), first, last);
}
// erase / clear
iterator erase(const_iterator pos);
iterator erase(const_iterator first, const_iterator last);
void clear() { erase(begin(), end()); }
// resize / reverse
void resize(size_type new_size) { return resize(new_size, value_type()); }
void resize(size_type new_size, const value_type& value);
void reverse() { mystl::reverse(begin(), end()); }
// swap
void swap(vector& rhs) noexcept;
private:
// helper functions
// initialize / destroy
void try_init() noexcept;
void init_space(size_type size, size_type cap);
void fill_init(size_type n, const value_type& value);
template <class Iter>
void range_init(Iter first, Iter last);
void destroy_and_recover(iterator first, iterator last, size_type n);
// calculate the growth size
size_type get_new_cap(size_type add_size);
// assign
void fill_assign(size_type n, const value_type& value);
template <class IIter>
void copy_assign(IIter first, IIter last, input_iterator_tag);
template <class FIter>
void copy_assign(FIter first, FIter last, forward_iterator_tag);
// reallocate
template <class... Args>
void reallocate_emplace(iterator pos, Args&& ...args);
void reallocate_insert(iterator pos, const value_type& value);
// insert
iterator fill_insert(iterator pos, size_type n, const value_type& value);
template <class IIter>
void copy_insert(iterator pos, IIter first, IIter last);
// shrink_to_fit
void reinsert(size_type size);
};
/*****************************************************************************************/
// 复制赋值操作符
template <class T>
vector<T>& vector<T>::operator=(const vector& rhs)
{
if (this != &rhs)
{
const auto len = rhs.size();
if (len > capacity())
{
vector tmp(rhs.begin(), rhs.end());
swap(tmp);
}
else if (size() >= len)
{
auto i = mystl::copy(rhs.begin(), rhs.end(), begin());
data_allocator::destroy(i, end_);
end_ = begin_ + len;
}
else
{
mystl::copy(rhs.begin(), rhs.begin() + size(), begin_);
mystl::uninitialized_copy(rhs.begin() + size(), rhs.end(), end_);
cap_ = end_ = begin_ + len;
}
}
return *this;
}
// 移动赋值操作符
template <class T>
vector<T>& vector<T>::operator=(vector&& rhs) noexcept
{
destroy_and_recover(begin_, end_, cap_ - begin_);
begin_ = rhs.begin_;
end_ = rhs.end_;
cap_ = rhs.cap_;
rhs.begin_ = nullptr;
rhs.end_ = nullptr;
rhs.cap_ = nullptr;
return *this;
}
// 预留空间大小,当原容量小于要求大小时,才会重新分配
template <class T>
void vector<T>::reserve(size_type n)
{
if (capacity() < n)
{
THROW_LENGTH_ERROR_IF(n > max_size(),
"n can not larger than max_size() in vector<T>::reserve(n)");
const auto old_size = size();
auto tmp = data_allocator::allocate(n);
mystl::uninitialized_move(begin_, end_, tmp);
data_allocator::deallocate(begin_, cap_ - begin_);
begin_ = tmp;
end_ = tmp + old_size;
cap_ = begin_ + n;
}
}
// 放弃多余的容量
template <class T>
void vector<T>::shrink_to_fit()
{
if (end_ < cap_)
{
reinsert(size());
}
}
// 在 pos 位置就地构造元素,避免额外的复制或移动开销
template <class T>
template <class ...Args>
typename vector<T>::iterator
vector<T>::emplace(const_iterator pos, Args&& ...args)
{
MYSTL_DEBUG(pos >= begin() && pos <= end());
iterator xpos = const_cast<iterator>(pos);
const size_type n = xpos - begin_;
if (end_ != cap_ && xpos == end_)
{
data_allocator::construct(mystl::address_of(*end_), mystl::forward<Args>(args)...);
++end_;
}
else if (end_ != cap_)
{
auto new_end = end_;
data_allocator::construct(mystl::address_of(*end_), *(end_ - 1));
++new_end;
mystl::copy_backward(xpos, end_ - 1, end_);
*xpos = value_type(mystl::forward<Args>(args)...);
end_ = new_end;
}
else
{
reallocate_emplace(xpos, mystl::forward<Args>(args)...);
}
return begin() + n;
}
// 在尾部就地构造元素,避免额外的复制或移动开销
template <class T>
template <class ...Args>
void vector<T>::emplace_back(Args&& ...args)
{
if (end_ < cap_)
{
data_allocator::construct(mystl::address_of(*end_), mystl::forward<Args>(args)...);
++end_;
}
else
{
reallocate_emplace(end_, mystl::forward<Args>(args)...);
}
}
// 在尾部插入元素
template <class T>
void vector<T>::push_back(const value_type& value)
{
if (end_ != cap_)
{
data_allocator::construct(mystl::address_of(*end_), value);
++end_;
}
else
{
reallocate_insert(end_, value);
}
}
// 弹出尾部元素
template <class T>
void vector<T>::pop_back()
{
MYSTL_DEBUG(!empty());
data_allocator::destroy(end_ - 1);
--end_;
}
// 在 pos 处插入元素
template <class T>
typename vector<T>::iterator
vector<T>::insert(const_iterator pos, const value_type& value)
{
MYSTL_DEBUG(pos >= begin() && pos <= end());
iterator xpos = const_cast<iterator>(pos);
const size_type n = pos - begin_;
if (end_ != cap_ && xpos == end_)
{
data_allocator::construct(mystl::address_of(*end_), value);
++end_;
}
else if (end_ != cap_)
{
auto new_end = end_;
data_allocator::construct(mystl::address_of(*end_), *(end_ - 1));
++new_end;
auto value_copy = value; // 避免元素因以下复制操作而被改变
mystl::copy_backward(xpos, end_ - 1, end_);
*xpos = mystl::move(value_copy);
end_ = new_end;
}
else
{
reallocate_insert(xpos, value);
}
return begin_ + n;
}
// 删除 pos 位置上的元素
template <class T>
typename vector<T>::iterator
vector<T>::erase(const_iterator pos)
{
MYSTL_DEBUG(pos >= begin() && pos < end());
iterator xpos = begin_ + (pos - begin());
mystl::move(xpos + 1, end_, xpos);
data_allocator::destroy(end_ - 1);
--end_;
return xpos;
}
// 删除[first, last)上的元素
template <class T>
typename vector<T>::iterator
vector<T>::erase(const_iterator first, const_iterator last)
{
MYSTL_DEBUG(first >= begin() && last <= end() && !(last < first));
const auto n = first - begin();
iterator r = begin_ + (first - begin());
data_allocator::destroy(mystl::move(r + (last - first), end_, r), end_);
end_ = end_ - (last - first);
return begin_ + n;
}
// 重置容器大小
template <class T>
void vector<T>::resize(size_type new_size, const value_type& value)
{
if (new_size < size())
{
erase(begin() + new_size, end());
}
else
{
insert(end(), new_size - size(), value);
}
}
// 与另一个 vector 交换
template <class T>
void vector<T>::swap(vector<T>& rhs) noexcept
{
if (this != &rhs)
{
mystl::swap(begin_, rhs.begin_);
mystl::swap(end_, rhs.end_);
mystl::swap(cap_, rhs.cap_);
}
}
/*****************************************************************************************/
// helper function
// try_init 函数,若分配失败则忽略,不抛出异常
template <class T>
void vector<T>::try_init() noexcept
{
try
{
begin_ = data_allocator::allocate(16);
end_ = begin_;
cap_ = begin_ + 16;
}
catch (...)
{
begin_ = nullptr;
end_ = nullptr;
cap_ = nullptr;
}
}
// init_space 函数
template <class T>
void vector<T>::init_space(size_type size, size_type cap)
{
try
{
begin_ = data_allocator::allocate(cap);
end_ = begin_ + size;
cap_ = begin_ + cap;
}
catch (...)
{
begin_ = nullptr;
end_ = nullptr;
cap_ = nullptr;
throw;
}
}
// fill_init 函数
template <class T>
void vector<T>::
fill_init(size_type n, const value_type& value)
{
const size_type init_size = mystl::max(static_cast<size_type>(16), n);
init_space(n, init_size);
mystl::uninitialized_fill_n(begin_, n, value);
}
// range_init 函数
template <class T>
template <class Iter>
void vector<T>::
range_init(Iter first, Iter last)
{
const size_type len = mystl::distance(first, last);
const size_type init_size = mystl::max(len, static_cast<size_type>(16));
init_space(len, init_size);
mystl::uninitialized_copy(first, last, begin_);
}
// destroy_and_recover 函数
template <class T>
void vector<T>::
destroy_and_recover(iterator first, iterator last, size_type n)
{
data_allocator::destroy(first, last);
data_allocator::deallocate(first, n);
}
// get_new_cap 函数
template <class T>
typename vector<T>::size_type
vector<T>::
get_new_cap(size_type add_size)
{
const auto old_size = capacity();
THROW_LENGTH_ERROR_IF(old_size > max_size() - add_size,
"vector<T>'s size too big");
if (old_size > max_size() - old_size / 2)
{
return old_size + add_size > max_size() - 16
? old_size + add_size : old_size + add_size + 16;
}
const size_type new_size = old_size == 0
? mystl::max(add_size, static_cast<size_type>(16))
: mystl::max(old_size + old_size / 2, old_size + add_size);
return new_size;
}
// fill_assign 函数
template <class T>
void vector<T>::
fill_assign(size_type n, const value_type& value)
{
if (n > capacity())
{
vector tmp(n, value);
swap(tmp);
}
else if (n > size())
{
mystl::fill(begin(), end(), value);
end_ = mystl::uninitialized_fill_n(end_, n - size(), value);
}
else
{
erase(mystl::fill_n(begin_, n, value), end_);
}
}
// copy_assign 函数
template <class T>
template <class IIter>
void vector<T>::
copy_assign(IIter first, IIter last, input_iterator_tag)
{
auto cur = begin_;
for (; first != last && cur != end_; ++first, ++cur)
{
*cur = *first;
}
if (first == last)
{
erase(cur, end_);
}
else
{
insert(end_, first, last);
}
}
// 用 [first, last) 为容器赋值
template <class T>
template <class FIter>
void vector<T>::
copy_assign(FIter first, FIter last, forward_iterator_tag)
{
const size_type len = mystl::distance(first, last);
if (len > capacity())
{
vector tmp(first, last);
swap(tmp);
}
else if (size() >= len)
{
auto new_end = mystl::copy(first, last, begin_);
data_allocator::destroy(new_end, end_);
end_ = new_end;
}
else
{
auto mid = first;
mystl::advance(mid, size());
mystl::copy(first, mid, begin_);
auto new_end = mystl::uninitialized_copy(mid, last, end_);
end_ = new_end;
}
}
// 重新分配空间并在 pos 处就地构造元素
template <class T>
template <class ...Args>
void vector<T>::
reallocate_emplace(iterator pos, Args&& ...args)
{
const auto new_size = get_new_cap(1);
auto new_begin = data_allocator::allocate(new_size);
auto new_end = new_begin;
try
{
new_end = mystl::uninitialized_move(begin_, pos, new_begin);
data_allocator::construct(mystl::address_of(*new_end), mystl::forward<Args>(args)...);
++new_end;
new_end = mystl::uninitialized_move(pos, end_, new_end);
}
catch (...)
{
data_allocator::deallocate(new_begin, new_size);
throw;
}
destroy_and_recover(begin_, end_, cap_ - begin_);
begin_ = new_begin;
end_ = new_end;
cap_ = new_begin + new_size;
}
// 重新分配空间并在 pos 处插入元素
template <class T>
void vector<T>::reallocate_insert(iterator pos, const value_type& value)
{
const auto new_size = get_new_cap(1);
auto new_begin = data_allocator::allocate(new_size);
auto new_end = new_begin;
const value_type& value_copy = value;
try
{
new_end = mystl::uninitialized_move(begin_, pos, new_begin);
data_allocator::construct(mystl::address_of(*new_end), value_copy);
++new_end;
new_end = mystl::uninitialized_move(pos, end_, new_end);
}
catch (...)
{
data_allocator::deallocate(new_begin, new_size);
throw;
}
destroy_and_recover(begin_, end_, cap_ - begin_);
begin_ = new_begin;
end_ = new_end;
cap_ = new_begin + new_size;
}
// fill_insert 函数
template <class T>
typename vector<T>::iterator
vector<T>::
fill_insert(iterator pos, size_type n, const value_type& value)
{
if (n == 0)
return pos;
const size_type xpos = pos - begin_;
const value_type value_copy = value; // 避免被覆盖
if (static_cast<size_type>(cap_ - end_) >= n)
{ // 如果备用空间大于等于增加的空间
const size_type after_elems = end_ - pos;
auto old_end = end_;
if (after_elems > n)
{
mystl::uninitialized_copy(end_ - n, end_, end_);
end_ += n;
mystl::move_backward(pos, old_end - n, old_end);
mystl::uninitialized_fill_n(pos, n, value_copy);
}
else
{
end_ = mystl::uninitialized_fill_n(end_, n - after_elems, value_copy);
end_ = mystl::uninitialized_move(pos, old_end, end_);
mystl::uninitialized_fill_n(pos, after_elems, value_copy);
}
}
else
{ // 如果备用空间不足
const auto new_size = get_new_cap(n);
auto new_begin = data_allocator::allocate(new_size);
auto new_end = new_begin;
try
{
new_end = mystl::uninitialized_move(begin_, pos, new_begin);
new_end = mystl::uninitialized_fill_n(new_end, n, value);
new_end = mystl::uninitialized_move(pos, end_, new_end);
}
catch (...)
{
destroy_and_recover(new_begin, new_end, new_size);
throw;
}
data_allocator::deallocate(begin_, cap_ - begin_);
begin_ = new_begin;
end_ = new_end;
cap_ = begin_ + new_size;
}
return begin_ + xpos;
}
// copy_insert 函数
template <class T>
template <class IIter>
void vector<T>::
copy_insert(iterator pos, IIter first, IIter last)
{
if (first == last)
return;
const auto n = mystl::distance(first, last);
if ((cap_ - end_) >= n)
{ // 如果备用空间大小足够
const auto after_elems = end_ - pos;
auto old_end = end_;
if (after_elems > n)
{
end_ = mystl::uninitialized_copy(end_ - n, end_, end_);
mystl::move_backward(pos, old_end - n, old_end);
mystl::uninitialized_copy(first, last, pos);
}
else
{
auto mid = first;
mystl::advance(mid, after_elems);
end_ = mystl::uninitialized_copy(mid, last, end_);
end_ = mystl::uninitialized_move(pos, old_end, end_);
mystl::uninitialized_copy(first, mid, pos);
}
}
else
{ // 备用空间不足
const auto new_size = get_new_cap(n);
auto new_begin = data_allocator::allocate(new_size);
auto new_end = new_begin;
try
{
new_end = mystl::uninitialized_move(begin_, pos, new_begin);
new_end = mystl::uninitialized_copy(first, last, new_end);
new_end = mystl::uninitialized_move(pos, end_, new_end);
}
catch (...)
{
destroy_and_recover(new_begin, new_end, new_size);
throw;
}
data_allocator::deallocate(begin_, cap_ - begin_);
begin_ = new_begin;
end_ = new_end;
cap_ = begin_ + new_size;
}
}
// reinsert 函数
template <class T>
void vector<T>::reinsert(size_type size)
{
auto new_begin = data_allocator::allocate(size);
try
{
mystl::uninitialized_move(begin_, end_, new_begin);
}
catch (...)
{
data_allocator::deallocate(new_begin, size);
throw;
}
data_allocator::deallocate(begin_, cap_ - begin_);
begin_ = new_begin;
end_ = begin_ + size;
cap_ = begin_ + size;
}
/*****************************************************************************************/
// 重载比较操作符
template <class T>
bool operator==(const vector<T>& lhs, const vector<T>& rhs)
{
return lhs.size() == rhs.size() &&
mystl::equal(lhs.begin(), lhs.end(), rhs.begin());
}
template <class T>
bool operator<(const vector<T>& lhs, const vector<T>& rhs)
{
return mystl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template <class T>
bool operator!=(const vector<T>& lhs, const vector<T>& rhs)
{
return !(lhs == rhs);
}
template <class T>
bool operator>(const vector<T>& lhs, const vector<T>& rhs)
{
return rhs < lhs;
}
template <class T>
bool operator<=(const vector<T>& lhs, const vector<T>& rhs)
{
return !(rhs < lhs);
}
template <class T>
bool operator>=(const vector<T>& lhs, const vector<T>& rhs)
{
return !(lhs < rhs);
}
// 重载 mystl 的 swap
template <class T>
void swap(vector<T>& lhs, vector<T>& rhs)
{
lhs.swap(rhs);
}
} // namespace mystl
#endif // !MYTINYSTL_VECTOR_H_

@ -0,0 +1,101 @@
MyTinySTL
=====
[![Build Status](https://travis-ci.org/Alinshans/MyTinySTL.svg?branch=master)](https://travis-ci.org/Alinshans/MyTinySTL) [![Build Status](https://ci.appveyor.com/api/projects/status/github/Alinshans/MyTinySTL?branch=master&svg=true)](https://ci.appveyor.com/project/Alinshans/mytinystl) [![Release](https://img.shields.io/github/release/Alinshans/MyTinySTL.svg)](https://github.com/Alinshans/MyTinySTL/releases) [![License](https://img.shields.io/badge/License-MIT%20License-blue.svg)](https://opensource.org/licenses/MIT) [![Chat](https://img.shields.io/badge/chat-on%20gitter-FF6EB4.svg)](https://gitter.im/alinshans/MyTinySTL)
## 简介
基于 `C++11``tinySTL`,这是我的第一个项目,使用了中文文档与中文注释,有不规范或不当的地方还请海涵。刚开始是作为新手练习用途,直到现在已经发布了 `2.x.x` 版本。实现了大部分 STL 中的容器与函数,但仍存在许多不足与 bug 。从 `2.x.x` 版本开始,本项目会进入长期维护的阶段,即基本不会增加新的内容,只修复发现的 bug。如发现错误还请在 [`Issues`](https://github.com/Alinshans/MyTinySTL/issues) 中指出,欢迎 `Fork` 和 [`Pull requests`](https://github.com/Alinshans/MyTinySTL/pulls) 改善代码,谢谢!
## 支持
* 操作系统
* linux
* windows
* osx
* 编译器
* g++ 5.4 或以上
* clang++ 3.5 或以上
* msvc 14.0 或以上
## 需要
* 使用 cmake 2.8 来构建项目(**可选**
## 运行
如果你想要运行测试,请先阅读 [这个](https://github.com/Alinshans/MyTinySTL/blob/master/Test/README.md) 。
* gcc/clang on linux/osx
1. 克隆仓库
```bash
$ git clone git@github.com:Alinshans/MyTinySTL.git
$ cd MyTinySTL
```
2. 构建并运行
```bash
$ mkdir build && cd build
$ cmake ..
$ make
$ cd ../bin && ./stltest
```
* msvc on windows
1. 克隆仓库或 [Download ZIP](https://github.com/Alinshans/MyTinySTL/archive/master.zip)
2. 使用 `vs2015`(或 `vs2017`)打开 `MSVC/MyTinySTL_VS2015.sln`,配置成 `Release` 模式Ctrl + F5开始执行。
## 文档
见 [Wiki](https://github.com/Alinshans/MyTinySTL/wiki)。
## 测试
见 [Test](https://github.com/Alinshans/MyTinySTL/tree/master/Test)。
---
## Introduction
This is a `tinySTL` based on `C++11`, which is my first project for practice. I use the Chinese documents and annotations for convenience, maybe there will be an English version later, but now I have no time to do that yet. Now I have released version `2.0.0`. I have achieved the vast majority of the containers and functions of `STL`, and there may be some deficiencies and bugs. From the version `2.x.x`, the project will enter the stage of long-term maintenance, i.e., I probably will not add new content but only fix bugs found. If you find any bugs, please point out that in [`Issues`](https://github.com/Alinshans/MyTinySTL/issues), or make a [`Pull requests`](https://github.com/Alinshans/MyTinySTL/pulls) to improve it, thanks!
## Supported
* os
* linux
* windows
* osx
* complier
* g++ 5.4 or later
* clang++ 3.5 or later
* msvc 14.0 or later
## Required
* Use cmake 2.8 to build this project (**Optional**)
## Run test
If you want to run the test, please read [this](https://github.com/Alinshans/MyTinySTL/blob/master/Test/README.md) first.
* gcc/clang on linux/osx
1. git clone
```bash
$ git clone git@github.com:Alinshans/MyTinySTL.git
$ cd MyTinySTL
```
2. build and run
```bash
$ mkdir build && cd build
$ cmake ..
$ make
$ cd ../bin && ./stltest
```
* msvc on windows
1. git clone or [Download ZIP](https://github.com/Alinshans/MyTinySTL/archive/master.zip)
2. use `vs2015`(or `vs2017`) open the file `MSVC/MyTinySTL_VS2015.sln`, configured in `Release`, run this project(Ctrl + F5).
## Documents
See [Wiki](https://github.com/Alinshans/MyTinySTL/wiki).
## Test
See [Test](https://github.com/Alinshans/MyTinySTL/tree/master/Test).

@ -0,0 +1,4 @@
include_directories(${PROJECT_SOURCE_DIR}/MyTinySTL)
set(APP_SRC test.cpp)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
add_executable(stltest ${APP_SRC})

@ -0,0 +1,351 @@
// ============================================================================
// Copyright (c) 2017 Alinshans. All rights reserved.
// Licensed under the MIT License. See LICENSE for details.
//
// Header File : redbud/io/color.h
//
// This file is used to control font format and color in the terminal, which
// refers to a project on github, see https://github.com/agauniyal/rang .
// ============================================================================
#ifndef ALINSHANS_REDBUD_IO_COLOR_H_
#define ALINSHANS_REDBUD_IO_COLOR_H_
#include "../platform.h"
#if defined(REDBUD_LINUX) || defined(REDBUD_OSX)
#include <unistd.h> // getenv
#include <cstring> // strstr
#elif defined(REDBUD_WIN)
#include <Windows.h>
#include <io.h>
#endif
#include <cstdlib>
#include <iostream>
#include <type_traits>
namespace redbud
{
namespace io
{
// ============================================================================
// Enumerates the ANSI escape code corresponding to the font attributes.
// See https://en.wikipedia.org/wiki/ANSI_escape_code for details.
//
// Example:
// using namespace redbud::io;
// std::cout << fg::red << "This text has a red foreground color\n";
// std::cout << bg::green << "This text has a green background color\n"
// ============================================================================
// Sets the text format, some of them is not widely supported.
enum class format
{
reset = 0, // All attributes off.
bold = 1, // Bold or increased intensity.
faint = 2, // Faint (decreased intensity).
italic = 3, // Italian font.
underline = 4, // Underline.
blinkslow = 5, // Blink slowly.
blinkrapid = 6, // Blink quickly.
inverse = 7, // Swap foreground and background.
conceal = 8, // Hide the text.
strikeline = 9 // Characters legible, but marked for deletion.
};
// Sets the foreground color.
enum class fg
{
black = 30,
red = 31,
green = 32,
yellow = 33,
blue = 34,
purple = 35,
cyan = 36,
white = 37,
reserve = 38,
reset = 39
};
// Sets the background color.
enum class bg
{
black = 40,
red = 41,
green = 42,
yellow = 43,
blue = 44,
purple = 45,
cyan = 46,
white = 47,
reserve = 38,
reset = 39
};
// Sets the highlight foreground color.
enum class hfg
{
black = 90,
red = 91,
green = 92,
yellow = 93,
blue = 94,
purple = 95,
cyan = 96,
white = 97
};
// Sets the highlight background color.
enum class hbg
{
black = 100,
red = 101,
green = 102,
yellow = 103,
blue = 104,
purple = 105,
cyan = 106,
white = 107
};
// Sets the control state.
enum class state
{
automatic = 0, // Automatic control.
manual = 1 // Manual control.
};
// ----------------------------------------------------------------------------
// Details
namespace details
{
// Manages associated stream buffer.
inline const std::streambuf*& get_coutbuf()
{
static const std::streambuf* pout = std::cout.rdbuf();
return pout;
}
inline const std::streambuf*& get_cerrbuf()
{
static const std::streambuf* perr = std::cerr.rdbuf();
return perr;
}
inline const std::streambuf*& get_clogbuf()
{
static const std::streambuf* plog = std::clog.rdbuf();
return plog;
}
// Gets an unique integer to use as index to iword()
inline int get_iword()
{
static int i = std::ios_base::xalloc();
return i;
}
// Determines whether the terminal color of this system can be modified.
inline bool is_modifiable()
{
#if defined(REDBUD_LINUX) || defined(REDBUD_OSX)
static constexpr const char* terms[] = {
"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm",
"linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"
};
const char *penv = std::getenv("TERM");
if (penv == nullptr)
{
return false;
}
bool result = false;
for (const auto& t : terms)
{
if (std::strstr(penv, t) != nullptr)
{
result = true;
break;
}
}
#elif defined(REDBUD_WIN)
static constexpr bool result = true;
#endif
return result;
}
/// Determines whether the buffer stream reaches the end.
inline bool is_terminal(const std::streambuf* buf)
{
if (buf == get_coutbuf())
{
#if defined(REDBUD_LINUX) || defined(REDBUD_OSX)
return isatty(fileno(stdout)) ? true : false;
#elif defined(REDBUD_WIN)
return _isatty(_fileno(stdout)) ? true : false;
#endif
}
if (buf == get_cerrbuf() || buf == get_clogbuf())
{
#if defined(REDBUD_LINUX) || defined(REDBUD_OSX)
return isatty(fileno(stderr)) ? true : false;
#elif defined(REDBUD_WIN)
return _isatty(_fileno(stderr)) ? true : false;
#endif
}
return false;
}
// For overloading standard output stream.
template <typename T>
using color_return_t = typename std::enable_if<
std::is_same<T, redbud::io::format>::value ||
std::is_same<T, redbud::io::fg>::value ||
std::is_same<T, redbud::io::bg>::value ||
std::is_same<T, redbud::io::hfg>::value ||
std::is_same<T, redbud::io::hbg>::value,
std::ostream&>::type;
template <typename T>
using state_return_t = typename std::enable_if<
std::is_same<T, redbud::io::state>::value,
std::ostream&>::type;
// Sets the format and color of the text.
#if defined(REDBUD_LINUX) || defined(REDBUD_OSX)
template <typename T>
inline color_return_t<T> set_color(std::ostream& os, const T& value)
{
return os << "\033[" << static_cast<int>(value) << "m";
}
#elif defined(REDBUD_WIN)
static constexpr WORD default_state = (FOREGROUND_BLUE |
FOREGROUND_GREEN |
FOREGROUND_RED);
// Gets the corresponding RGB value on Windows.
inline WORD get_rgb(WORD rgb)
{
static constexpr WORD cor[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
return cor[rgb];
}
// Sets font attributes on Windows.
inline void set_attributes(redbud::io::fg color, WORD& state)
{
if (color == redbud::io::fg::reserve)
{
return;
}
state &= 0xFFF0;
if (color == redbud::io::fg::reset)
{
state |= default_state;
return;
}
state |= get_rgb(static_cast<WORD>(color) - 30);
}
inline void set_attributes(redbud::io::bg color, WORD& state)
{
if (color == redbud::io::bg::reserve)
{
return;
}
state &= 0xFF0F;
if (color == redbud::io::bg::reset)
{
return;
}
state |= get_rgb(static_cast<WORD>(color) - 40) << 4;
}
inline void set_attributes(redbud::io::hfg color, WORD& state)
{
state &= 0xFFF0;
state |= (static_cast<WORD>(0x8) |
get_rgb(static_cast<WORD>(color) - 90));
}
inline void set_attributes(redbud::io::hbg color, WORD& state)
{
state &= 0xFF0F;
state |= (static_cast<WORD>(0x80) |
get_rgb(static_cast<WORD>(color) - 100) << 4);
}
inline void set_attributes(redbud::io::format format, WORD& state)
{
if (format == redbud::io::format::reset)
{
state = default_state;
}
}
inline WORD& current_state()
{
static WORD state = default_state;
return state;
}
inline HANDLE get_console_handle()
{
static HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
return h;
}
template <typename T>
inline color_return_t<T> set_color(std::ostream& os, const T& value)
{
HANDLE h = get_console_handle();
if (h && is_terminal(os.rdbuf()))
{
set_attributes(value, current_state());
SetConsoleTextAttribute(h, current_state());
return os;
}
return os;
}
#endif
} // namespace details
// ----------------------------------------------------------------------------
// Overloads standard output stream to control the color of text.
template <typename T>
inline details::color_return_t<T>
operator<<(std::ostream& os, const T& value)
{
return (os.iword(details::get_iword()) ||
(details::is_modifiable() &&
details::is_terminal(os.rdbuf())))
? details::set_color(os, value)
: os;
}
template <typename T>
inline details::state_return_t<T>
operator<<(std::ostream& os, const T& value)
{
if (value == redbud::io::state::automatic)
{
os.iword(details::get_iword()) = 0;
}
else if (value == redbud::io::state::manual)
{
os.iword(details::get_iword()) = 1;
}
return os;
}
} // namespace io
} // namespace redbud
#endif // !ALINSHANS_REDBUD_IO_COLOR_H_

@ -0,0 +1,108 @@
// ============================================================================
// Copyright (c) 2017 Alinshans. All rights reserved.
// Licensed under the MIT License. See LICENSE for details.
//
// Header File : redbud/platform.h
//
// This file contains some preprocessing macros related to the platform.
// ============================================================================
#ifndef ALINSHANS_REDBUD_PLATFORM_H_
#define ALINSHANS_REDBUD_PLATFORM_H_
// ----------------------------------------------------------------------------
// os
#if defined(WIN32) || defined(_WIN32) || defined(_WIN64)
#define REDBUD_WIN 1
#elif defined(__unix__) || defined(__unix) || defined(__linux__)
#define REDBUD_LINUX 1
#elif defined(__APPLE__) || defined(__MACH__)
#define REDBUD_OSX 1
#else
#error "System that is not supported yet."
#endif
// ----------------------------------------------------------------------------
// complier
#if defined(__clang__)
#define REDBUD_CLANG __clang__
#elif defined(__GNUC__)
#define REDBUD_GNUC __GNUC__
#elif defined(_MSC_VER)
#define REDBUD_MSVC _MSC_VER
#else
#error "Complier that is not supported yet."
#endif
// ----------------------------------------------------------------------------
// stringify
#define REDBUD_TO_STRING(x) #x
#define REDBUD_STRING(x) REDBUD_TO_STRING(x)
// ----------------------------------------------------------------------------
// join
#define REDBUD_DO_JOIN(x ,y) x##y
#define REDBUD_JOIN(x, y) REDBUD_DO_JOIN(x, y)
// ----------------------------------------------------------------------------
// version
#define REDBUD_MAJOR 1
#define REDBUD_MINOR 0
#define REDBUD_PATCH 0
#define REDBUD_VERSION \
REDBUD_STRING(REDBUD_MAJOR.REDBUD_MINOR.REDBUD_PATCH)
#define _VERSION_CODE(x,y,z) \
(((x)*100000) + ((y)*100) + (z))
#define GNUC_VERSION \
_VERSION_CODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#define CLANG_VERSION \
_VERSION_CODE(__clang_major__, __clang_minor__, __clang_patchlevel__)
// ----------------------------------------------------------------------------
// redbud API
#ifndef _REDBUD_API
#define _REDBUD_API ::redbud::
#endif
// ----------------------------------------------------------------------------
// C++11 required
#ifndef REDBUD_HAS_CXX11
#if defined(REDBUD_MSVC) && (REDBUD_MSVC >= 1900)
#define REDBUD_HAS_CXX11 1
#elif defined(REDBUD_GNUC) && (GNUC_VERSION >= _VERSION_CODE(4,8,0)) && \
defined(__GXX_EXPERIMENTAL_CXX0X__)
#define REDBUD_HAS_CXX11 1
#elif defined(REDBUD_CLANG) && (CLANG_VERSION >= _VERSION_CODE(3,3,0))
#define REDBUD_HAS_CXX11 1
#else
#define REDBUD_HAS_CXX11 0
#endif
#endif // !REDBUD_HAS_CXX11
#if REDBUD_HAS_CXX11 == 0
#error "C++11 required."
#endif
// ----------------------------------------------------------------------------
// Undefines macro min and max in MSVC.
namespace redbud
{
#if REDBUD_MSVC
#define NOMINMAX
#endif
}
#endif // !ALINSHANS_REDBUD_PLATFORM_H_

@ -0,0 +1,51 @@
单元测试 (Unit test)
=====
## 测试环境 (Test environment)
测试直接在 `Travis CI``AppVeyor` 上构建并运行,已在以下环境中做过测试:
Tests were built and run directly on `Tracis CI` and `AppVeyor` and had been tested in the following environments:
* linux, ubuntu 14.04, gcc5/6/7
* osx, xcode5/6/7/8
* windows, VS2015/VS2017, [x64|x86], [Release|Debug]
## 测试框架 (Test frame)
在 [test.h](https://github.com/Alinshans/MyTinySTL/blob/master/Test/test.h) 中,用了两个类实现了一个简单的测试框架,并定义了大量宏来封装测试过程。</br>
In this file [test.h](https://github.com/Alinshans/MyTinySTL/blob/master/Test/test.h), I used two class to implement a simple test framework, and defined a lot of macros to package testing process.
## 测试内容 (Test content)
在 [test.h](https://github.com/Alinshans/MyTinySTL/blob/master/Test/test.h) 中定义了两个宏,`PERFORMANCE_TEST_ON` 和 `LARGER_TEST_DATA_ON`。`PERFORMANCE_TEST_ON` 代表开启性能测试,默认定义为 `1`。`LARGER_TEST_DATA_ON` 代表增大测试数据,默认定义为 `0`。**如果你想把 `LARGER_TEST_DATA_ON` 设置为 `1`,建议电脑配置为:处理器 i5 或以上,内存 8G 以上。**<br>
In this file [test.h](https://github.com/Alinshans/MyTinySTL/blob/master/Test/test.h), I defined two marcos: `PERFORMANCE_TEST_ON` and `LARGER_TEST_DATA_ON`. `PERFORMANCE_TEST_ON` means to run performance test, the default is defined as `1`. `LARGER_TEST_DATA_ON` means to increase the test data, the default is defined as `0`. **If you want to set `LARGER_TEST_DATA_ON` to `1`, the proposed computer configuration is: CPU i5 or above, memory 8G or more.**
测试案例如下:<br>
The test cases are as follows:
* [algorithm](https://github.com/Alinshans/MyTinySTL/blob/master/Test/algorithm_test.h) *(100%/100%)*
* [algorithm_performance](https://github.com/Alinshans/MyTinySTL/blob/master/Test/algorithm_performance_test.h) *(100%/100%)*
* [deque](https://github.com/Alinshans/MyTinySTL/blob/master/Test/deque_test.h) *(100%/100%)*
* [list](https://github.com/Alinshans/MyTinySTL/blob/master/Test/list_test.h) *(100%/100%)*
* [map](https://github.com/Alinshans/MyTinySTL/blob/master/Test/map_test.h) *(100%/100%)*
* map
* multimap
* [queue](https://github.com/Alinshans/MyTinySTL/blob/master/Test/queue_test.h) *(100%/100%)*
* queue
* priority_queue
* [set](https://github.com/Alinshans/MyTinySTL/blob/master/Test/set_test.h) *(100%/100%)*
* set
* multiset
* [stack](https://github.com/Alinshans/MyTinySTL/blob/master/Test/stack_test.h) *(100%/100%)*
* [string_test](https://github.com/Alinshans/MyTinySTL/blob/master/Test/string_test.h) *(100%/100%)*
* [unordered_map](https://github.com/Alinshans/MyTinySTL/blob/master/Test/unordered_map_test.h) *(100%/100%)*
* unordered_map
* unordered_multimap
* [unordered_set](https://github.com/Alinshans/MyTinySTL/blob/master/Test/unordered_set_test.h) *(100%/100%)*
* unordered_set
* unordered_multiset
* [vector](https://github.com/Alinshans/MyTinySTL/blob/master/Test/vector_test.h) *(100%/100%)*
## 测试结果 (Test result)
见 [Travis CI](https://travis-ci.org/Alinshans/MyTinySTL) 和 [AppVeyor](https://ci.appveyor.com/project/Alinshans/mytinystl)。
See [Travis CI](https://travis-ci.org/Alinshans/MyTinySTL) and [AppVeyor](https://ci.appveyor.com/project/Alinshans/mytinystl).

@ -0,0 +1,108 @@
#ifndef MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_
#define MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_
// 仅仅针对 sort, binary_search 做了性能测试
#include <algorithm>
#include "../MyTinySTL/algorithm.h"
#include "test.h"
namespace mystl
{
namespace test
{
namespace algorithm_performance_test
{
// 函数性能测试宏定义
#define FUN_TEST1(mode, fun, count) do { \
std::string fun_name = #fun; \
srand((int)time(0)); \
char buf[10]; \
clock_t start, end; \
int *arr = new int[count]; \
for(size_t i = 0; i < count; ++i) *(arr + i) = rand(); \
start = clock(); \
mode::fun(arr, arr + count); \
end = clock(); \
int n = static_cast<int>(static_cast<double>(end - start) \
/ CLOCKS_PER_SEC * 1000); \
std::snprintf(buf, sizeof(buf), "%d", n); \
std::string t = buf; \
t += "ms |"; \
std::cout << std::setw(WIDE) << t; \
delete []arr; \
} while(0)
#define FUN_TEST2(mode, fun, count) do { \
std::string fun_name = #fun; \
srand((int)time(0)); \
char buf[10]; \
clock_t start, end; \
int *arr = new int[count]; \
for(size_t i = 0; i < count; ++i) *(arr + i) = rand(); \
start = clock(); \
for(size_t i = 0; i < count; ++i) \
mode::fun(arr, arr + count, rand()); \
end = clock(); \
int n = static_cast<int>(static_cast<double>(end - start) \
/ CLOCKS_PER_SEC * 1000); \
std::snprintf(buf, sizeof(buf), "%d", n); \
std::string t = buf; \
t += "ms |"; \
std::cout << std::setw(WIDE) << t; \
delete []arr; \
} while(0)
void binary_search_test()
{
std::cout << "[------------------- function : binary_search ------------------]" << std::endl;
std::cout << "| orders of magnitude |";
TEST_LEN(LEN1, LEN2, LEN3, WIDE);
std::cout << "| std |";
FUN_TEST2(std, binary_search, LEN1);
FUN_TEST2(std, binary_search, LEN2);
FUN_TEST2(std, binary_search, LEN3);
std::cout << std::endl << "| mystl |";
FUN_TEST2(mystl, binary_search, LEN1);
FUN_TEST2(mystl, binary_search, LEN2);
FUN_TEST2(mystl, binary_search, LEN3);
std::cout << std::endl;
}
void sort_test()
{
std::cout << "[----------------------- function : sort -----------------------]" << std::endl;
std::cout << "| orders of magnitude |";
TEST_LEN(LEN1, LEN2, LEN3, WIDE);
std::cout << "| std |";
FUN_TEST1(std, sort, LEN1);
FUN_TEST1(std, sort, LEN2);
FUN_TEST1(std, sort, LEN3);
std::cout << std::endl << "| mystl |";
FUN_TEST1(mystl, sort, LEN1);
FUN_TEST1(mystl, sort, LEN2);
FUN_TEST1(mystl, sort, LEN3);
std::cout << std::endl;
}
void algorithm_performance_test()
{
#if PERFORMANCE_TEST_ON
std::cout << "[===============================================================]" << std::endl;
std::cout << "[--------------- Run algorithm performance test ----------------]" << std::endl;
sort_test();
binary_search_test();
std::cout << "[--------------- End algorithm performance test ----------------]" << std::endl;
std::cout << "[===============================================================]" << std::endl;
#endif // PERFORMANCE_TEST_ON
}
} // namespace algorithm_performance_test
} // namespace test
} // namespace mystl
#endif // !MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_

File diff suppressed because it is too large Load Diff

@ -0,0 +1,102 @@
#ifndef MYTINYSTL_DEQUE_TEST_H_
#define MYTINYSTL_DEQUE_TEST_H_
// deque test : 测试 deque 的接口和 push_front/push_back 的性能
#include <deque>
#include "../MyTinySTL/deque.h"
#include "test.h"
namespace mystl
{
namespace test
{
namespace deque_test
{
void deque_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[----------------- Run container test : deque ------------------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
int a[] = { 1,2,3,4,5 };
mystl::deque<int> d1;
mystl::deque<int> d2(5);
mystl::deque<int> d3(5, 1);
mystl::deque<int> d4(a, a + 5);
mystl::deque<int> d5(d2);
mystl::deque<int> d6(std::move(d2));
mystl::deque<int> d7;
d7 = d3;
mystl::deque<int> d8;
d8 = std::move(d3);
mystl::deque<int> d9{ 1,2,3,4,5,6,7,8,9 };
mystl::deque<int> d10;
d10 = { 1,2,3,4,5,6,7,8,9 };
FUN_AFTER(d1, d1.assign(5, 1));
FUN_AFTER(d1, d1.assign(8, 8));
FUN_AFTER(d1, d1.assign(a, a + 5));
FUN_AFTER(d1, d1.assign({ 1,2,3,4,5 }));
FUN_AFTER(d1, d1.insert(d1.end(), 6));
FUN_AFTER(d1, d1.insert(d1.end() - 1, 2, 7));
FUN_AFTER(d1, d1.insert(d1.begin(), a, a + 5));
FUN_AFTER(d1, d1.erase(d1.begin()));
FUN_AFTER(d1, d1.erase(d1.begin(), d1.begin() + 4));
FUN_AFTER(d1, d1.emplace_back(8));
FUN_AFTER(d1, d1.emplace_front(8));
FUN_AFTER(d1, d1.emplace(d1.begin() + 1, 9));
FUN_AFTER(d1, d1.push_front(1));
FUN_AFTER(d1, d1.push_back(2));
FUN_AFTER(d1, d1.pop_back());
FUN_AFTER(d1, d1.pop_front());
FUN_AFTER(d1, d1.shrink_to_fit());
FUN_AFTER(d1, d1.resize(5));
FUN_AFTER(d1, d1.resize(8, 8));
FUN_AFTER(d1, d1.clear());
FUN_AFTER(d1, d1.shrink_to_fit());
FUN_AFTER(d1, d1.swap(d4));
FUN_VALUE(*(d1.begin()));
FUN_VALUE(*(d1.end() - 1));
FUN_VALUE(*(d1.rbegin()));
FUN_VALUE(*(d1.rend() - 1));
FUN_VALUE(d1.front());
FUN_VALUE(d1.back());
FUN_VALUE(d1.at(1));
FUN_VALUE(d1[2]);
std::cout << std::boolalpha;
FUN_VALUE(d1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(d1.size());
FUN_VALUE(d1.max_size());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| push_front |";
#if LARGER_TEST_DATA_ON
CON_TEST_P1(deque<int>, push_front, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));
#else
CON_TEST_P1(deque<int>, push_front, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| push_back |";
#if LARGER_TEST_DATA_ON
CON_TEST_P1(deque<int>, push_back, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));
#else
CON_TEST_P1(deque<int>, push_back, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[----------------- End container test : deque ------------------]" << std::endl;
}
} // namespace deque_test
} // namespace test
} // namespace mystl
#endif // !MYTINYSTL_DEQUE_TEST_H_

@ -0,0 +1,118 @@
#ifndef MYTINYSTL_LIST_TEST_H_
#define MYTINYSTL_LIST_TEST_H_
// list test : 测试 list 的接口与 insert, sort 的性能
#include <list>
#include "../MyTinySTL/list.h"
#include "test.h"
namespace mystl
{
namespace test
{
namespace list_test
{
// 一个辅助测试函数
bool is_odd(int x) { return x & 1; }
void list_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[------------------ Run container test : list ------------------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
int a[] = { 1,2,3,4,5 };
mystl::list<int> l1;
mystl::list<int> l2(5);
mystl::list<int> l3(5, 1);
mystl::list<int> l4(a, a + 5);
mystl::list<int> l5(l2);
mystl::list<int> l6(std::move(l2));
mystl::list<int> l7{ 1,2,3,4,5,6,7,8,9 };
mystl::list<int> l8;
l8 = l3;
mystl::list<int> l9;
l9 = std::move(l3);
mystl::list<int> l10;
l10 = { 1, 2, 2, 3, 5, 6, 7, 8, 9 };
FUN_AFTER(l1, l1.assign(8, 8));
FUN_AFTER(l1, l1.assign(a, a + 5));
FUN_AFTER(l1, l1.assign({ 1,2,3,4,5,6 }));
FUN_AFTER(l1, l1.insert(l1.end(), 6));
FUN_AFTER(l1, l1.insert(l1.end(), 2, 7));
FUN_AFTER(l1, l1.insert(l1.begin(), a, a + 5));
FUN_AFTER(l1, l1.push_back(2));
FUN_AFTER(l1, l1.push_front(1));
FUN_AFTER(l1, l1.emplace(l1.begin(),1));
FUN_AFTER(l1, l1.emplace_front(0));
FUN_AFTER(l1, l1.emplace_back(10));
FUN_VALUE(l1.size());
FUN_AFTER(l1, l1.pop_front());
FUN_AFTER(l1, l1.pop_back());
FUN_AFTER(l1, l1.erase(l1.begin()));
FUN_AFTER(l1, l1.erase(l1.begin(), l1.end()));
FUN_VALUE(l1.size());
FUN_AFTER(l1, l1.resize(10));
FUN_AFTER(l1, l1.resize(5, 1));
FUN_AFTER(l1, l1.resize(8, 2));
FUN_VALUE(l1.size());
FUN_AFTER(l1, l1.splice(l1.end(), l4));
FUN_AFTER(l1, l1.splice(l1.begin(), l5, l5.begin()));
FUN_AFTER(l1, l1.splice(l1.end(), l6, l6.begin(), ++l6.begin()));
FUN_VALUE(l1.size());
FUN_AFTER(l1, l1.remove(0));
FUN_AFTER(l1, l1.remove_if(is_odd));
FUN_VALUE(l1.size());
FUN_AFTER(l1, l1.assign({ 9,5,3,3,7,1,3,2,2,0,10 }));
FUN_VALUE(l1.size());
FUN_AFTER(l1, l1.sort());
FUN_AFTER(l1, l1.unique());
FUN_AFTER(l1, l1.unique([&](int a, int b) {return b == a + 1; }));
FUN_AFTER(l1, l1.merge(l7));
FUN_AFTER(l1, l1.sort(mystl::greater<int>()));
FUN_AFTER(l1, l1.merge(l8, mystl::greater<int>()));
FUN_AFTER(l1, l1.reverse());
FUN_AFTER(l1, l1.clear());
FUN_AFTER(l1, l1.swap(l9));
FUN_VALUE(*l1.begin());
FUN_VALUE(*l1.rbegin());
FUN_VALUE(l1.front());
FUN_VALUE(l1.back());
std::cout << std::boolalpha;
FUN_VALUE(l1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(l1.size());
FUN_VALUE(l1.max_size());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| insert |";
#if LARGER_TEST_DATA_ON
CON_TEST_P2(list<int>, insert, end, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));
#else
CON_TEST_P2(list<int>, insert, end, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| sort |";
#if LARGER_TEST_DATA_ON
LIST_SORT_TEST(SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));
#else
LIST_SORT_TEST(SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[------------------ End container test : list ------------------]" << std::endl;
}
} // namespace list_test
} // namespace test
} // namespace mystl
#endif // !MYTINYSTL_LIST_TEST_H_

@ -0,0 +1,202 @@
#ifndef MYTINYSTL_MAP_TEST_H_
#define MYTINYSTL_MAP_TEST_H_
// map test : 测试 map, multimap 的接口与它们 insert 的性能
#include <map>
#include "../MyTinySTL/map.h"
#include "../MyTinySTL/vector.h"
#include "test.h"
namespace mystl
{
namespace test
{
namespace map_test
{
// pair 的宏定义
#define PAIR mystl::pair<int, int>
// map 的遍历输出
#define MAP_COUT(m) do { \
std::string m_name = #m; \
std::cout << " " << m_name << " :"; \
for (auto it : m) std::cout << " <" << it.first << "," << it.second << ">"; \
std::cout << std::endl; \
} while(0)
// map 的函数操作
#define MAP_FUN_AFTER(con, fun) do { \
std::string str = #fun; \
std::cout << " After " << str << " :" << std::endl; \
fun; \
MAP_COUT(con); \
} while(0)
// map 的函数值
#define MAP_VALUE(fun) do { \
std::string str = #fun; \
auto it = fun; \
std::cout << " " << str << " : <" << it.first << "," << it.second << ">\n"; \
} while(0)
void map_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[------------------ Run container test : map -------------------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
mystl::vector<PAIR> v;
for (int i = 0; i < 5; ++i)
v.push_back(PAIR(i, i));
mystl::map<int, int> m1;
mystl::map<int, int, mystl::greater<int>> m2;
mystl::map<int, int> m3(v.begin(), v.end());
mystl::map<int, int> m4(v.begin(), v.end());
mystl::map<int, int> m5(m3);
mystl::map<int, int> m6(std::move(m3));
mystl::map<int, int> m7;
m7 = m4;
mystl::map<int, int> m8;
m8 = std::move(m4);
mystl::map<int, int> m9{ PAIR(1,1),PAIR(3,2),PAIR(2,3) };
mystl::map<int, int> m10;
m10 = { PAIR(1,1),PAIR(3,2),PAIR(2,3) };
for (int i = 5; i > 0; --i)
{
MAP_FUN_AFTER(m1, m1.emplace(i, i));
}
MAP_FUN_AFTER(m1, m1.emplace_hint(m1.begin(), 0, 0));
MAP_FUN_AFTER(m1, m1.erase(m1.begin()));
MAP_FUN_AFTER(m1, m1.erase(0));
MAP_FUN_AFTER(m1, m1.erase(1));
MAP_FUN_AFTER(m1, m1.erase(m1.begin(), m1.end()));
for (int i = 0; i < 5; ++i)
{
MAP_FUN_AFTER(m1, m1.insert(PAIR(i, i)));
}
MAP_FUN_AFTER(m1, m1.insert(v.begin(), v.end()));
MAP_FUN_AFTER(m1, m1.insert(m1.end(), PAIR(5, 5)));
FUN_VALUE(m1.count(1));
MAP_VALUE(*m1.find(3));
MAP_VALUE(*m1.lower_bound(3));
MAP_VALUE(*m1.upper_bound(2));
auto first = *m1.equal_range(2).first;
auto second = *m1.equal_range(2).second;
std::cout << " m1.equal_range(2) : from <" << first.first << ", " << first.second
<< "> to <" << second.first << ", " << second.second << ">" << std::endl;
MAP_FUN_AFTER(m1, m1.erase(m1.begin()));
MAP_FUN_AFTER(m1, m1.erase(1));
MAP_FUN_AFTER(m1, m1.erase(m1.begin(), m1.find(3)));
MAP_FUN_AFTER(m1, m1.clear());
MAP_FUN_AFTER(m1, m1.swap(m9));
MAP_VALUE(*m1.begin());
MAP_VALUE(*m1.rbegin());
FUN_VALUE(m1[1]);
MAP_FUN_AFTER(m1, m1[1] = 3);
FUN_VALUE(m1.at(1));
std::cout << std::boolalpha;
FUN_VALUE(m1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(m1.size());
FUN_VALUE(m1.max_size());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| emplace |";
#if LARGER_TEST_DATA_ON
MAP_EMPLACE_TEST(map, SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));
#else
MAP_EMPLACE_TEST(map, SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[------------------ End container test : map -------------------]" << std::endl;
}
void multimap_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[---------------- Run container test : multimap ----------------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
mystl::vector<PAIR> v;
for (int i = 0; i < 5; ++i)
v.push_back(PAIR(i, i));
mystl::multimap<int, int> m1;
mystl::multimap<int, int, mystl::greater<int>> m2;
mystl::multimap<int, int> m3(v.begin(), v.end());
mystl::multimap<int, int> m4(v.begin(), v.end());
mystl::multimap<int, int> m5(m3);
mystl::multimap<int, int> m6(std::move(m3));
mystl::multimap<int, int> m7;
m7 = m4;
mystl::multimap<int, int> m8;
m8 = std::move(m4);
mystl::multimap<int, int> m9{ PAIR(1,1),PAIR(3,2),PAIR(2,3) };
mystl::multimap<int, int> m10;
m10 = { PAIR(1,1),PAIR(3,2),PAIR(2,3) };
for (int i = 5; i > 0; --i)
{
MAP_FUN_AFTER(m1, m1.emplace(i, i));
}
MAP_FUN_AFTER(m1, m1.emplace_hint(m1.begin(), 0, 0));
MAP_FUN_AFTER(m1, m1.erase(m1.begin()));
MAP_FUN_AFTER(m1, m1.erase(0));
MAP_FUN_AFTER(m1, m1.erase(1));
MAP_FUN_AFTER(m1, m1.erase(m1.begin(), m1.end()));
for (int i = 0; i < 5; ++i)
{
MAP_FUN_AFTER(m1, m1.insert(mystl::make_pair(i, i)));
}
MAP_FUN_AFTER(m1, m1.insert(v.begin(), v.end()));
MAP_FUN_AFTER(m1, m1.insert(PAIR(5, 5)));
MAP_FUN_AFTER(m1, m1.insert(m1.end(), PAIR(5, 5)));
FUN_VALUE(m1.count(3));
MAP_VALUE(*m1.find(3));
MAP_VALUE(*m1.lower_bound(3));
MAP_VALUE(*m1.upper_bound(2));
auto first = *m1.equal_range(2).first;
auto second = *m1.equal_range(2).second;
std::cout << " m1.equal_range(2) : from <" << first.first << ", " << first.second
<< "> to <" << second.first << ", " << second.second << ">" << std::endl;
MAP_FUN_AFTER(m1, m1.erase(m1.begin()));
MAP_FUN_AFTER(m1, m1.erase(1));
MAP_FUN_AFTER(m1, m1.erase(m1.begin(), m1.find(3)));
MAP_FUN_AFTER(m1, m1.clear());
MAP_FUN_AFTER(m1, m1.swap(m9));
MAP_FUN_AFTER(m1, m1.insert(PAIR(3, 3)));
MAP_VALUE(*m1.begin());
MAP_VALUE(*m1.rbegin());
std::cout << std::boolalpha;
FUN_VALUE(m1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(m1.size());
FUN_VALUE(m1.max_size());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| emplace |";
#if LARGER_TEST_DATA_ON
MAP_EMPLACE_TEST(multimap, SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));
#else
MAP_EMPLACE_TEST(multimap, SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[---------------- End container test : multimap ----------------]" << std::endl;
}
} // namespace map_test
} // namespace test
} // namespace mystl
#endif // !MYTINYSTL_MAP_TEST_H_

@ -0,0 +1,186 @@
#ifndef MYTINYSTL_QUEUE_TEST_H_
#define MYTINYSTL_QUEUE_TEST_H_
// queue test : 测试 queue, priority_queue 的接口和它们 push 的性能
#include <queue>
#include "../MyTinySTL/queue.h"
#include "test.h"
namespace mystl
{
namespace test
{
namespace queue_test
{
void queue_print(mystl::queue<int> q)
{
while (!q.empty())
{
std::cout << " " << q.front();
q.pop();
}
std::cout << std::endl;
}
void p_queue_print(mystl::priority_queue<int> p)
{
while (!p.empty())
{
std::cout << " " << p.top();
p.pop();
}
std::cout << std::endl;
}
// queue 的遍历输出
#define QUEUE_COUT(q) do { \
std::string q_name = #q; \
std::cout << " " << q_name << " :"; \
queue_print(q); \
} while(0)
// priority_queue 的遍历输出
#define P_QUEUE_COUT(p) do { \
std::string p_name = #p; \
std::cout << " " << p_name << " :"; \
p_queue_print(p); \
} while(0)
#define QUEUE_FUN_AFTER(con, fun) do { \
std::string fun_name = #fun; \
std::cout << " After " << fun_name << " :\n"; \
fun; \
QUEUE_COUT(con); \
} while(0)
#define P_QUEUE_FUN_AFTER(con, fun) do { \
std::string fun_name = #fun; \
std::cout << " After " << fun_name << " :\n"; \
fun; \
P_QUEUE_COUT(con); \
} while(0)
void queue_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[----------------- Run container test : queue ------------------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
int a[] = { 1,2,3,4,5 };
mystl::deque<int> d1(5);
mystl::queue<int> q1;
mystl::queue<int> q2(5);
mystl::queue<int> q3(5, 1);
mystl::queue<int> q4(a, a + 5);
mystl::queue<int> q5(d1);
mystl::queue<int> q6(std::move(d1));
mystl::queue<int> q7(q2);
mystl::queue<int> q8(std::move(q2));
mystl::queue<int> q9;
q9 = q3;
mystl::queue<int> q10;
q10 = std::move(q3);
mystl::queue<int> q11{ 1,2,3,4,5 };
mystl::queue<int> q12;
q12 = { 1,2,3,4,5 };
QUEUE_FUN_AFTER(q1, q1.push(1));
QUEUE_FUN_AFTER(q1, q1.push(2));
QUEUE_FUN_AFTER(q1, q1.push(3));
QUEUE_FUN_AFTER(q1, q1.pop());
QUEUE_FUN_AFTER(q1, q1.emplace(4));
QUEUE_FUN_AFTER(q1, q1.emplace(5));
std::cout << std::boolalpha;
FUN_VALUE(q1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(q1.size());
FUN_VALUE(q1.front());
FUN_VALUE(q1.back());
while (!q1.empty())
{
QUEUE_FUN_AFTER(q1, q1.pop());
}
QUEUE_FUN_AFTER(q1, q1.swap(q4));
QUEUE_FUN_AFTER(q1, q1.clear());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| push |";
#if LARGER_TEST_DATA_ON
CON_TEST_P1(queue<int>, push, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));
#else
CON_TEST_P1(queue<int>, push, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[----------------- End container test : queue ------------------]" << std::endl;
}
void priority_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[------------- Run container test : priority_queue -------------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
int a[] = { 1,2,3,4,5 };
mystl::vector<int> v1(5);
mystl::priority_queue<int> p1;
mystl::priority_queue<int> p2(5);
mystl::priority_queue<int> p3(5, 1);
mystl::priority_queue<int> p4(a, a + 5);
mystl::priority_queue<int> p5(v1);
mystl::priority_queue<int> p6(std::move(v1));
mystl::priority_queue<int> p7(p2);
mystl::priority_queue<int> p8(std::move(p2));
mystl::priority_queue<int> p9;
p9 = p3;
mystl::priority_queue<int> p10;
p10 = std::move(p3);
mystl::priority_queue<int> p11{ 1,2,3,4,5 };
mystl::priority_queue<int> p12;
p12 = { 1,2,3,4,5 };
P_QUEUE_FUN_AFTER(p1, p1.push(1));
P_QUEUE_FUN_AFTER(p1, p1.push(5));
P_QUEUE_FUN_AFTER(p1, p1.push(3));
P_QUEUE_FUN_AFTER(p1, p1.pop());
P_QUEUE_FUN_AFTER(p1, p1.emplace(7));
P_QUEUE_FUN_AFTER(p1, p1.emplace(2));
P_QUEUE_FUN_AFTER(p1, p1.emplace(8));
std::cout << std::boolalpha;
FUN_VALUE(p1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(p1.size());
FUN_VALUE(p1.top());
while (!p1.empty())
{
P_QUEUE_FUN_AFTER(p1, p1.pop());
}
P_QUEUE_FUN_AFTER(p1, p1.swap(p4));
P_QUEUE_FUN_AFTER(p1, p1.clear());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| push |";
#if LARGER_TEST_DATA_ON
CON_TEST_P1(priority_queue<int>, push, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));
#else
CON_TEST_P1(priority_queue<int>, push, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[------------- End container test : priority_queue -------------]" << std::endl;
}
} // namespace queue_test
} // namespace test
} // namespace mystl
#endif // !MYTINYSTL_QUEUE_TEST_H_

@ -0,0 +1,166 @@
#ifndef MYTINYSTL_SET_TEST_H_
#define MYTINYSTL_SET_TEST_H_
// set test : 测试 set, multiset 的接口与它们 insert 的性能
#include <set>
#include "../MyTinySTL/set.h"
#include "test.h"
namespace mystl
{
namespace test
{
namespace set_test
{
void set_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[------------------ Run container test : set -------------------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
int a[] = { 5,4,3,2,1 };
mystl::set<int> s1;
mystl::set<int, mystl::greater<int>> s2;
mystl::set<int> s3(a, a + 5);
mystl::set<int> s4(a, a + 5);
mystl::set<int> s5(s3);
mystl::set<int> s6(std::move(s3));
mystl::set<int> s7;
s7 = s4;
mystl::set<int> s8;
s8 = std::move(s4);
mystl::set<int> s9{ 1,2,3,4,5 };
mystl::set<int> s10;
s10 = { 1,2,3,4,5 };
for (int i = 5; i > 0; --i)
{
FUN_AFTER(s1, s1.emplace(i));
}
FUN_AFTER(s1, s1.emplace_hint(s1.begin(), 0));
FUN_AFTER(s1, s1.erase(s1.begin()));
FUN_AFTER(s1, s1.erase(0));
FUN_AFTER(s1, s1.erase(1));
FUN_AFTER(s1, s1.erase(s1.begin(), s1.end()));
for (int i = 0; i < 5; ++i)
{
FUN_AFTER(s1, s1.insert(i));
}
FUN_AFTER(s1, s1.insert(a, a + 5));
FUN_AFTER(s1, s1.insert(5));
FUN_AFTER(s1, s1.insert(s1.end(), 5));
FUN_VALUE(s1.count(5));
FUN_VALUE(*s1.find(3));
FUN_VALUE(*s1.lower_bound(3));
FUN_VALUE(*s1.upper_bound(3));
auto first = *s1.equal_range(3).first;
auto second = *s1.equal_range(3).second;
std::cout << " s1.equal_range(3) : from " << first << " to " << second << std::endl;
FUN_AFTER(s1, s1.erase(s1.begin()));
FUN_AFTER(s1, s1.erase(1));
FUN_AFTER(s1, s1.erase(s1.begin(), s1.find(3)));
FUN_AFTER(s1, s1.clear());
FUN_AFTER(s1, s1.swap(s5));
FUN_VALUE(*s1.begin());
FUN_VALUE(*s1.rbegin());
std::cout << std::boolalpha;
FUN_VALUE(s1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(s1.size());
FUN_VALUE(s1.max_size());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| emplace |";
#if LARGER_TEST_DATA_ON
CON_TEST_P1(set<int>, emplace, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));
#else
CON_TEST_P1(set<int>, emplace, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[------------------ End container test : set -------------------]" << std::endl;
}
void multiset_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[---------------- Run container test : multiset ----------------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
int a[] = { 5,4,3,2,1 };
mystl::multiset<int> s1;
mystl::multiset<int, mystl::greater<int>> s2;
mystl::multiset<int> s3(a, a + 5);
mystl::multiset<int> s4(a, a + 5);
mystl::multiset<int> s5(s3);
mystl::multiset<int> s6(std::move(s3));
mystl::multiset<int> s7;
s7 = s4;
mystl::multiset<int> s8;
s8 = std::move(s4);
mystl::multiset<int> s9{ 1,2,3,4,5 };
mystl::multiset<int> s10;
s10 = { 1,2,3,4,5 };
for (int i = 5; i > 0; --i)
{
FUN_AFTER(s1, s1.emplace(i));
}
FUN_AFTER(s1, s1.emplace_hint(s1.begin(), 0));
FUN_AFTER(s1, s1.erase(s1.begin()));
FUN_AFTER(s1, s1.erase(0));
FUN_AFTER(s1, s1.erase(1));
FUN_AFTER(s1, s1.erase(s1.begin(), s1.end()));
for (int i = 0; i < 5; ++i)
{
FUN_AFTER(s1, s1.insert(i));
}
FUN_AFTER(s1, s1.insert(a, a + 5));
FUN_AFTER(s1, s1.insert(5));
FUN_AFTER(s1, s1.insert(s1.end(), 5));
FUN_VALUE(s1.count(5));
FUN_VALUE(*s1.find(3));
FUN_VALUE(*s1.lower_bound(3));
FUN_VALUE(*s1.upper_bound(3));
auto first = *s1.equal_range(3).first;
auto second = *s1.equal_range(3).second;
std::cout << " s1.equal_range(3) : from " << first << " to " << second << std::endl;
FUN_AFTER(s1, s1.erase(s1.begin()));
FUN_AFTER(s1, s1.erase(1));
FUN_AFTER(s1, s1.erase(s1.begin(), s1.find(3)));
FUN_AFTER(s1, s1.clear());
FUN_AFTER(s1, s1.swap(s5));
FUN_VALUE(*s1.begin());
FUN_VALUE(*s1.rbegin());
std::cout << std::boolalpha;
FUN_VALUE(s1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(s1.size());
FUN_VALUE(s1.max_size());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| emplace |";
#if LARGER_TEST_DATA_ON
CON_TEST_P1(multiset<int>, emplace, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));
#else
CON_TEST_P1(multiset<int>, emplace, rand(), SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[---------------- End container test : multiset ----------------]" << std::endl;
}
} // namespace set_test
} // namespace test
} // namespace mystl
#endif // !MYTINYSTL_SET_TEST_H_

@ -0,0 +1,103 @@
#ifndef MYTINYSTL_STACK_TEST_H_
#define MYTINYSTL_STACK_TEST_H_
// stack test : 测试 stack 的接口 和 push 的性能
#include <stack>
#include "../MyTinySTL/stack.h"
#include "test.h"
namespace mystl
{
namespace test
{
namespace stack_test
{
void stack_print(mystl::stack<int> s)
{
while (!s.empty())
{
std::cout << " " << s.top();
s.pop();
}
std::cout << std::endl;
}
// stack 的遍历输出
#define STACK_COUT(s) do { \
std::string s_name = #s; \
std::cout << " " << s_name << " :"; \
stack_print(s); \
} while(0)
#define STACK_FUN_AFTER(con, fun) do { \
std::string fun_name = #fun; \
std::cout << " After " << fun_name << " :\n"; \
fun; \
STACK_COUT(con); \
} while(0)
void stack_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[----------------- Run container test : stack ------------------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
int a[] = { 1,2,3,4,5 };
mystl::deque<int> d1(5);
mystl::stack<int> s1;
mystl::stack<int> s2(5);
mystl::stack<int> s3(5, 1);
mystl::stack<int> s4(a, a + 5);
mystl::stack<int> s5(d1);
mystl::stack<int> s6(std::move(d1));
mystl::stack<int> s7(s2);
mystl::stack<int> s8(std::move(s2));
mystl::stack<int> s9;
s9 = s3;
mystl::stack<int> s10;
s10 = std::move(s3);
mystl::stack<int> s11{ 1,2,3,4,5 };
mystl::stack<int> s12;
s12 = { 1,2,3,4,5 };
STACK_FUN_AFTER(s1, s1.push(1));
STACK_FUN_AFTER(s1, s1.push(2));
STACK_FUN_AFTER(s1, s1.push(3));
STACK_FUN_AFTER(s1, s1.pop());
STACK_FUN_AFTER(s1, s1.emplace(4));
STACK_FUN_AFTER(s1, s1.emplace(5));
std::cout << std::boolalpha;
FUN_VALUE(s1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(s1.size());
FUN_VALUE(s1.top());
while (!s1.empty())
{
STACK_FUN_AFTER(s1, s1.pop());
}
STACK_FUN_AFTER(s1, s1.swap(s4));
STACK_FUN_AFTER(s1, s1.clear());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| push |";
#if LARGER_TEST_DATA_ON
CON_TEST_P1(stack<int>, push, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));
#else
CON_TEST_P1(stack<int>, push, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[----------------- End container test : stack ------------------]" << std::endl;
}
} // namespace stack_test
} // namespace test
} // namespace mystl
#endif // !MYTINYSTL_STACK_TEST_H_

@ -0,0 +1,207 @@
#ifndef MYTINYSTL_STRING_TEST_H_
#define MYTINYSTL_STRING_TEST_H_
// string test : 测试 string 的接口和 insert 的性能
#include <string>
#include "../MyTinySTL/astring.h"
#include "test.h"
namespace mystl
{
namespace test
{
namespace string_test
{
void string_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[----------------- Run container test : string -----------------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
const char* s = "abcdefg";
mystl::string str;
mystl::string str1(5, 'a');
mystl::string str2(str1, 3);
mystl::string str3(str1, 0, 3);
mystl::string str4("abc");
mystl::string str5("abcde",3);
mystl::string str6(s, s + 5);
mystl::string str7(str1);
mystl::string str8(std::move(str1));
mystl::string str9;
str9 = str2;
mystl::string str10;
str10 = std::move(str2);
mystl::string str11;
str11 = "123";
mystl::string str12;
str12 = 'A';
STR_FUN_AFTER(str, str = 'a');
STR_FUN_AFTER(str, str = "string");
FUN_VALUE(*str.begin());
FUN_VALUE(*str.rbegin());
FUN_VALUE(*(str.end() - 1));
FUN_VALUE(*(str.rend() - 1));
FUN_VALUE(str.front());
FUN_VALUE(str.back());
FUN_VALUE(str[1]);
FUN_VALUE(str.at(2));
STR_COUT(str.data());
STR_COUT(str.c_str());
std::cout << std::boolalpha;
FUN_VALUE(str.empty());
std::cout << std::noboolalpha;
FUN_VALUE(str.size());
FUN_VALUE(str.length());
FUN_VALUE(str.capacity());
FUN_VALUE(str.max_size());
STR_FUN_AFTER(str, str.shrink_to_fit());
FUN_VALUE(str.capacity());
STR_FUN_AFTER(str, str.insert(str.begin(), 'a'));
STR_FUN_AFTER(str, str.insert(str.end(), 3, 'x'));
STR_FUN_AFTER(str, str.insert(str.end(), s, s + 3));
STR_FUN_AFTER(str, str.erase(str.begin()));
STR_FUN_AFTER(str, str.erase(str.begin(), str.begin() + 3));
STR_FUN_AFTER(str, str.clear());
STR_FUN_AFTER(str, str.push_back('s'));
STR_FUN_AFTER(str, str.push_back('t'));
STR_FUN_AFTER(str, str.pop_back());
STR_FUN_AFTER(str, str.append(1, 't'));
STR_FUN_AFTER(str, str.append(str4));
STR_FUN_AFTER(str, str.append(str4, 1));
STR_FUN_AFTER(str, str.append(str4, 2, 1));
STR_FUN_AFTER(str, str.append("str"));
STR_FUN_AFTER(str, str.append("inging", 3));
STR_FUN_AFTER(str, str.append(s, s + 3));
STR_FUN_AFTER(str, str.resize(10));
FUN_VALUE(str.size());
STR_FUN_AFTER(str, str.resize(20, 'x'));
FUN_VALUE(str.size());
STR_FUN_AFTER(str, str.clear());
STR_FUN_AFTER(str, str = "string");
STR_FUN_AFTER(str3, str3 = "astrings");
FUN_VALUE(str.compare(str3));
FUN_VALUE(str.compare(0, 6, str3));
FUN_VALUE(str.compare(0, 6, str3, 1, 6));
FUN_VALUE(str.compare("atringgg"));
FUN_VALUE(str.compare("zzz"));
FUN_VALUE(str.compare(0, 3, "str"));
FUN_VALUE(str.compare(0, 3, "stri", 4));
FUN_VALUE(str.compare(0, 3, "s", 2));
FUN_VALUE(str.compare(0, 9, "stringabc", 9));
FUN_VALUE(str.substr(0));
FUN_VALUE(str.substr(3));
FUN_VALUE(str.substr(0, 3));
FUN_VALUE(str.substr(0, 10));
STR_FUN_AFTER(str, str.replace(0, 6, str3));
STR_FUN_AFTER(str, str.replace(str.end() - 1, str.end(), str3));
STR_FUN_AFTER(str, str.replace(0, 1, "my "));
STR_FUN_AFTER(str, str.replace(str.end() - 8, str.end(), " test"));
STR_FUN_AFTER(str, str.replace(10, 4, "replace"));
STR_FUN_AFTER(str, str.replace(str.end(), str.end(), " test"));
STR_FUN_AFTER(str, str.replace(0, 2, 3, '6'));
STR_FUN_AFTER(str, str.replace(str.begin(), str.begin() + 3, 6, '6'));
STR_FUN_AFTER(str, str.replace(0, 3, str3, 1, 3));
STR_FUN_AFTER(str, str.replace(str.begin(), str.begin() + 6, s, s + 3));
STR_FUN_AFTER(str, str.reverse());
STR_FUN_AFTER(str, str.reverse());
STR_FUN_AFTER(str, str = "abcabc stringgg");
STR_FUN_AFTER(str3, str3 = "abc");
FUN_VALUE(str.find('a'));
FUN_VALUE(str.find('a', 3));
FUN_VALUE(str.find('a', 4));
FUN_VALUE(str.find("abc"));
FUN_VALUE(str.find("abc", 1));
FUN_VALUE(str.find("abc", 1, 1));
FUN_VALUE(str.find(str3));
FUN_VALUE(str.find(str3, 1));
FUN_VALUE(str.rfind('g'));
FUN_VALUE(str.rfind('g', 3));
FUN_VALUE(str.rfind("gg"));
FUN_VALUE(str.rfind("bc", 10));
FUN_VALUE(str.rfind(str3));
FUN_VALUE(str.rfind(str3, 3));
FUN_VALUE(str.find_first_of('g'));
FUN_VALUE(str.find_first_of('k'));
FUN_VALUE(str.find_first_of("bca"));
FUN_VALUE(str.find_first_of("defg", 10));
FUN_VALUE(str.find_first_of("gnirts"));
FUN_VALUE(str.find_first_of("abc", 6));
FUN_VALUE(str.find_first_of("abcdf", 2, 3));
FUN_VALUE(str.find_first_of(str3, 1));
FUN_VALUE(str.find_first_of(str3, 10));
FUN_VALUE(str.find_first_not_of('a'));
FUN_VALUE(str.find_first_not_of('d'));
FUN_VALUE(str.find_first_not_of('g', 14));
FUN_VALUE(str.find_first_not_of("abc"));
FUN_VALUE(str.find_first_not_of("ggggg", 14, 4));
FUN_VALUE(str.find_first_not_of(str3));
FUN_VALUE(str.find_first_not_of(str3, 3));
FUN_VALUE(str.find_last_of('a'));
FUN_VALUE(str.find_last_of('a', 4));
FUN_VALUE(str.find_last_of('g'));
FUN_VALUE(str.find_last_of("gg"));
FUN_VALUE(str.find_last_of("gg", 14));
FUN_VALUE(str.find_last_of("ggg", 14, 1));
FUN_VALUE(str.find_last_of(str3));
FUN_VALUE(str.find_last_of(str3, 3));
FUN_VALUE(str.find_last_not_of('g'));
FUN_VALUE(str.find_last_not_of('a'));
FUN_VALUE(str.find_last_not_of('a', 1));
FUN_VALUE(str.find_last_not_of("ggg"));
FUN_VALUE(str.find_last_not_of("ggg", 14));
FUN_VALUE(str.find_last_not_of("abc", 3, 1));
FUN_VALUE(str.find_last_not_of(str3));
FUN_VALUE(str.find_last_not_of(str3, 2));
FUN_VALUE(str.count('a'));
FUN_VALUE(str.count('a', 2));
FUN_VALUE(str.count('d', 10));
STR_FUN_AFTER(str, str.swap(str3));
FUN_VALUE(str.size());
FUN_VALUE(str.length());
FUN_VALUE(str.capacity());
STR_FUN_AFTER(str, str += str);
STR_FUN_AFTER(str, str += 'a');
STR_FUN_AFTER(str, str += "bc");
FUN_VALUE(str.size());
FUN_VALUE(str.length());
FUN_VALUE(str.capacity());
STR_FUN_AFTER(str, str.shrink_to_fit());
FUN_VALUE(str.capacity());
STR_FUN_AFTER(str, str.reserve(50));
FUN_VALUE(str.capacity());
STR_FUN_AFTER(str3, str3 = "test");
STR_FUN_AFTER(str4, str4 = " ok!");
std::cout << " str3 + '!' : " << str3 + '!' << std::endl;
std::cout << " '#' + str3 : " << '#' + str3 << std::endl;
std::cout << " str3 + \" success\" : " << str3 + " success" << std::endl;
std::cout << " \"My \" + str3 : " << "My " + str3 << std::endl;
std::cout << " str3 + str4 : " << str3 + str4 << std::endl;
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| append |";
#if LARGER_TEST_DATA_ON
CON_TEST_P1(string, append, "s", SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));
#else
CON_TEST_P1(string, append, "s", SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[----------------- End container test : string -----------------]" << std::endl;
}
} // namespace string_test
} // namespace test
} // namespace mystl
#endif // !MYTINYSTL_STRING_TEST_H_

@ -0,0 +1,52 @@
#ifdef _MSC_VER
#define _SCL_SECURE_NO_WARNINGS
#endif
#if defined(_MSC_VER) && defined(_DEBUG)
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif // check memory leaks
#include "algorithm_performance_test.h"
#include "algorithm_test.h"
#include "vector_test.h"
#include "list_test.h"
#include "deque_test.h"
#include "queue_test.h"
#include "stack_test.h"
#include "map_test.h"
#include "set_test.h"
#include "unordered_map_test.h"
#include "unordered_set_test.h"
#include "string_test.h"
int main()
{
using namespace mystl::test;
std::cout.sync_with_stdio(false);
RUN_ALL_TESTS();
algorithm_performance_test::algorithm_performance_test();
vector_test::vector_test();
list_test::list_test();
deque_test::deque_test();
queue_test::queue_test();
queue_test::priority_test();
stack_test::stack_test();
map_test::map_test();
map_test::multimap_test();
set_test::set_test();
set_test::multiset_test();
unordered_map_test::unordered_map_test();
unordered_map_test::unordered_multimap_test();
unordered_set_test::unordered_set_test();
unordered_set_test::unordered_multiset_test();
string_test::string_test();
#if defined(_MSC_VER) && defined(_DEBUG)
_CrtDumpMemoryLeaks();
#endif // check memory leaks
}

@ -0,0 +1,717 @@
#ifndef MYTINYSTL_TEST_H_
#define MYTINYSTL_TEST_H_
// 一个简单的单元测试框架,定义了两个类 TestCase 和 UnitTest以及一系列用于测试的宏
#include <ctime>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <vector>
#include "Lib/redbud/io/color.h"
namespace mystl
{
namespace test
{
#define green redbud::io::state::manual << redbud::io::hfg::green
#define red redbud::io::state::manual << redbud::io::hfg::red
#if defined(_MSC_VER)
#pragma warning(disable : 4244)
#pragma warning(disable : 4996)
#endif
} // namespace test
namespace test
{
// TestCase 类
// 封装单个测试案例
class TestCase
{
public:
// 构造函数,接受一个字符串代表案例名称
TestCase(const char* case_name) : testcase_name(case_name) {}
// 一个纯虚函数,用于测试案例
virtual void Run() = 0;
public:
const char* testcase_name; // 测试案例的名称
int nTestResult; // 测试案例的执行结果
double nFailed; // 测试失败的案例数
double nPassed; // 测试通过的案例数
};
// UnitTest 类
// 单元测试,把所有测试案例加入到 vector 中,依次执行测试案例
class UnitTest
{
public:
// 获取一个案例
static UnitTest* GetInstance();
// 将案例依次加入 vector
TestCase* RegisterTestCase(TestCase* testcase);
void Run();
public:
TestCase* CurrentTestCase; // 当前执行的测试案例
double nPassed; // 通过案例数
double nFailed; // 失败案例数
protected:
std::vector<TestCase*> testcases_; // 保存案例集合
};
UnitTest* UnitTest::GetInstance()
{
static UnitTest instance;
return &instance;
}
TestCase* UnitTest::RegisterTestCase(TestCase* testcase)
{
testcases_.push_back(testcase);
return testcase;
}
void UnitTest::Run()
{
for (auto it : testcases_)
{
TestCase* testcase = it;
CurrentTestCase = testcase;
testcase->nTestResult = 1;
testcase->nFailed = 0;
testcase->nPassed = 0;
std::cout << green << "============================================\n";
std::cout << green << " Run TestCase:" << testcase->testcase_name << "\n";
testcase->Run();
if (testcase->nFailed == 0)
std::cout << green;
else
std::cout << red;
std::cout << " " << testcase->nPassed << " / " << testcase->nFailed + testcase->nPassed
<< " Cases passed. ( " << testcase->nPassed /
(testcase->nFailed + testcase->nPassed) * 100 << "% )\n";
std::cout << green << " End TestCase:" << testcase->testcase_name << "\n";
if (testcase->nTestResult)
++nPassed;
else
++nFailed;
}
std::cout << green << "============================================\n";
std::cout << green << " Total TestCase : " << nPassed + nFailed << "\n";
std::cout << green << " Total Passed : " << nPassed << "\n";
std::cout << red << " Total Failed : " << nFailed << "\n";
std::cout << green << " " << nPassed << " / " << nFailed + nPassed
<< " TestCases passed. ( " << nPassed / (nFailed + nPassed) * 100 << "% )\n";
}
/*****************************************************************************************/
// 测试案例的类名,替换为 test_cast_TEST
#define TESTCASE_NAME(testcase_name) \
testcase_name##_TEST
// 使用宏定义掩盖复杂的测试样例封装过程,把 TEXT 中的测试案例放到单元测试中
#define MYTINYSTL_TEST_(testcase_name) \
class TESTCASE_NAME(testcase_name) : public TestCase { \
public: \
TESTCASE_NAME(testcase_name)(const char* case_name) \
: TestCase(case_name) {}; \
virtual void Run(); \
private: \
static TestCase* const testcase_; \
}; \
\
TestCase* const TESTCASE_NAME(testcase_name) \
::testcase_ = UnitTest::GetInstance()->RegisterTestCase( \
new TESTCASE_NAME(testcase_name)(#testcase_name)); \
void TESTCASE_NAME(testcase_name)::Run()
/*
Run() Run
TEST(AddTestDemo)
{
EXPECT_EQ(3, Add(1, 2));
EXPECT_EQ(2, Add(1, 1));
}
{ EXPECT_EQ(3, Add(1, 2)); EXPECT_EQ(2, Add(1, 1)); } Run()
*/
/*****************************************************************************************/
// 简单测试的宏定义
// 断言 : 宏定义形式为 EXPECT_* ,符合验证条件的,案例测试通过,否则失败
// 使用一系列的宏来封装验证条件,分为以下几大类 :
/*
EXPECT_TRUE : Condition true
EXPECT_FALSE : Condition false
Example:
bool isPrime(int n);
EXPECT_TRUE(isPrime(2));
EXPECT_FALSE(isPrime(4));
EXPECT_TRUE(isPrime(6));
EXPECT_FALSE(isPrime(3));
*/
#define EXPECT_TRUE(Condition) do { \
if (Condition) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_TRUE succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_TRUE failed!\n"; \
}} while(0)
#define EXPECT_FALSE(Condition) do { \
if (!Condition) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_FALSE succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_FALSE failed!\n"; \
}} while(0)
/*
EXPECT_EQ(v1, v2) : v1 == v2
EXPECT_NE(v1, v2) : v1 != v2
EXPECT_LT(v1, v2) : v1 < v2
EXPECT_LE(v1, v2) : v1 <= v2
EXPECT_GT(v1, v2) : v1 > v2
EXPECT_GE(v1, v2) : v1 >= v2
Note:
1. EXPECT_*(Expect, Actual)
2.
3. <<
ostream
4. == <
5. EXPECT_EQ
C (const char*)
使 EXPECT_STREQ C (NULL)
使 EXPECT_STREQ(NULL, c_str) string
使 EXPECT_EQ
Example:
EXPECT_EQ(3, foo());
EXPECT_NE(NULL, pointer);
EXPECT_LT(len, v.size());
*/
#define EXPECT_EQ(v1, v2) do { \
if (v1 == v2) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_EQ succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_EQ failed!\n"; \
std::cout << red << " Expect:" << v1 << "\n"; \
std::cout << red << " Actual:" << v2 << "\n"; \
}} while(0)
#define EXPECT_NE(v1, v2) do { \
if (v1 != v2) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_NE succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_NE failed!\n"; \
std::cout << red << " Expect:" << v1 << "\n"; \
std::cout << red << " Actual:" << v2 << "\n"; \
}} while(0)
#define EXPECT_LT(v1, v2) do { \
if (v1 < v2) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_LT succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_LT failed!\n"; \
std::cout << red << " Expect:" << v1 << "\n"; \
std::cout << red << " Actual:" << v2 << "\n"; \
}} while(0)
#define EXPECT_LE(v1, v2) do { \
if (v1 <= v2) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_LE succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_LE failed!\n"; \
std::cout << red << " Expect:" << v1 << "\n"; \
std::cout << red << " Actual:" << v2 << "\n"; \
}} while(0)
#define EXPECT_GT(v1, v2) do { \
if (v1 > v2) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_GT succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_GT failed!\n"; \
std::cout << red << " Expect:" << v1 << "\n"; \
std::cout << red << " Actual:" << v2 << "\n"; \
}} while(0)
#define EXPECT_GE(v1, v2) do { \
if (v1 >= v2) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_GE succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_GE failed!\n"; \
std::cout << red << " Expect:" << v1 << "\n"; \
std::cout << red << " Actual:" << v2 << "\n"; \
}} while(0)
/*
EXPECT_STREQ(s1, s2) : C
EXPECT_STRNE(s1, s2) : C
Note:
1. EXPECT_STR*(Expect, Actual)
2. C string 使
EXPECT_EQEXPECT_NE
3. EXPECT_STREQ EXPECT_STRNE wchar_t*
4. NULL
Example:
char* s1 = "", char* s2 = "abc", char* s3 = NULL;
EXPECT_STREQ("abc", s2);
EXPECT_STREQ(s1, s3);
EXPECT_STREQ(NULL, s3);
EXPECT_STRNE(" ", s1);
*/
#define EXPECT_STREQ(s1, s2) do { \
if (s1 == NULL || s2 == NULL) { \
if (s1 == NULL && s2 == NULL) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_STRED succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_STRED failed!\n"; \
if(s1 == NULL) std::cout << " Expect: NULL\n"; \
else std::cout << " Expect:\"" << s1 << "\"\n"; \
if(s2 == NULL) std::cout << " Actual: NULL\n"; \
else std::cout << " Actual:\"" << s2 << "\"\n"; \
} \
} \
else if (strcmp(s1, s2) == 0) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_STRED succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_STRED failed!\n"; \
std::cout << red << " Expect:\"" << s1 << "\"\n"; \
std::cout << red << " Actual:\"" << s2 << "\"\n"; \
}} while(0)
#define EXPECT_STRNE(s1, s2) do { \
if (s1 == NULL || s2 == NULL) { \
if (s1 != NULL || s2 != NULL) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_STRNE succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_STRNE failed!\n"; \
if(s1 == NULL) std::cout << " Expect: NULL\n"; \
else std::cout << " Expect:\"" << s1 << "\"\n"; \
if(s2 == NULL) std::cout << " Actual: NULL\n"; \
else std::cout << " Actual:\"" << s2 << "\"\n"; \
} \
} \
else if (strcmp(s1, s2) != 0) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_STRNE succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_STRNE failed!\n"; \
std::cout << red << " Expect:\"" << s1 << "\"\n"; \
std::cout << red << " Actual:\"" << s2 << "\"\n"; \
}} while(0)
/*
EXPECT_PTR_EQ(p1, p2) : *p1 == *p2
EXPECT_PTR_NE(p1, p2) : *p1 != *p2
EXPECT_PTR_RANGE_EQ(p1, p2, len) : i (*p1 + i) == (*p2 + i) i[0,len)
EXPECT_PTR_RANGE_NE(p1, p2, len) : i (*p1 + i) != (*p2 + i) i[0,len)
Note:
1. EXPECT_PTR_*(Expect, Actual)
EXPECT_PTR_RANGE_*(Expect, Actual, len)
2. EXPECT_PTR_EQ
EXPECT_EQ
3. EXPECT_PTR_RANGE_* p1p2
len
Example:
int a[] = {1,2,3,4,5};
int b[] = {1,2,3,4,6};
int *p1 = a, *p2 = b;
EXPECT_PTR_EQ(p1, p2);
p1 = a + 4, p2 = b + 4;
EXPECT_PTR_EQ(p1, p2);
EXPECT_PTR_EQ(p1, std::find(a, a + 5, 5));
EXPECT_PTR_RANGE_EQ(a, b, 5);
EXPECT_PTR_RANGE_EQ(a, b, 4);
*/
#define EXPECT_PTR_EQ(p1, p2) do { \
if (*p1 == *p2) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_PTR_EQ succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_PTR_EQ failed!\n"; \
std::cout << red << " Expect:" << *p1 << "\n"; \
std::cout << red << " Actual:" << *p2 << "\n"; \
}} while(0)
#define EXPECT_PTR_NE(p1, p2) do { \
if (*p1 != *p2) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_PTR_NE succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_PTR_NE failed!\n"; \
std::cout << red << " Expect:" << *p1 << "\n"; \
std::cout << red << " Actual:" << *p2 << "\n"; \
}} while(0)
#define EXPECT_PTR_RANGE_EQ(p1, p2, len) do { \
if (std::equal(p1, p1 + len, p2)) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_PTR_RANGE_EQ succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_PTR_RANGE_EQ failed!\n"; \
}} while(0)
#define EXPECT_PTR_RANGE_NE(p1, p2, len) do { \
if (!std::equal(p1, p1 + len, p2)) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_PTR_RANGE_NE succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_PTR_RANGE_NE failed!\n"; \
}} while(0)
/*
EXPECT_CON_EQ(c1, c2) : c1 == c2
EXPECT_CON_NE(c1, c2) : c1 != c2
Note:
1. STL
2.
3. EXPECT_CON_EQ
Example:
int arr[] = {1,2,3};
std::vector<int> v1{1, 2, 3};
std::vector<int> v2{2, 3, 4};
mystl::vector<long> v3(arr, arr + 3);
EXPECT_CON_NE(v1, v2) ok
EXPECT_CON_EQ(arr, v1) ok
EXPECT_CON_EQ(v1, v3) ok
*/
#define EXPECT_CON_EQ(c1, c2) do { \
auto first1 = std::begin(c1), last1 = std::end(c1); \
auto first2 = std::begin(c2), last2 = std::end(c2); \
for (; first1 != last1 && first2 != last2; ++first1, ++first2) { \
if (*first1 != *first2) break; \
} \
if (first1 == last1 && first2 == last2) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_CON_EQ succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_CON_EQ failed!\n"; \
std::cout << red << " Expect:" << *first1 << "\n"; \
std::cout << red << " Actual:" << *first2 << "\n"; \
}} while(0)
#define EXPECT_CON_NE(c1, c2) do { \
auto first1 = std::begin(c1), last1 = std::end(c1); \
auto first2 = std::begin(c2), last2 = std::end(c2); \
for (; first1 != last1 && first2 != last2; ++first1, ++first2) { \
if (*first1 != *first2) break; \
} \
if (first1 != last1 || first2 != last2) { \
UnitTest::GetInstance()->CurrentTestCase->nPassed++; \
std::cout << green << " EXPECT_CON_NE succeeded!\n"; \
} \
else { \
UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \
UnitTest::GetInstance()->CurrentTestCase->nFailed++; \
std::cout << red << " EXPECT_CON_NE failed!\n"; \
}} while(0)
/*****************************************************************************************/
// 常用的宏定义
// 不同情况的测试数量级
#if defined(_DEBUG) || defined(DEBUG)
#define LEN1 10000
#define LEN2 100000
#define LEN3 1000000
#else
#define LEN1 100000
#define LEN2 1000000
#define LEN3 10000000
#endif
#define SCALE_LLL(N) (N * 20)
#define SCALE_LL(N) (N * 10)
#define SCALE_L(N) (N * 5)
#define SCALE_M(N) (N)
#define SCALE_S(N) (N / 5)
#define SCALE_SS(N) (N / 10)
#define SCALE_SSS(N) (N / 20)
#define WIDE 14
// 输出通过提示
#define PASSED std::cout << "[ PASSED ]\n"
// 遍历输出容器
#define COUT(container) do { \
std::string con_name = #container; \
std::cout << " " << con_name << " :"; \
for (auto it : container) \
std::cout << " " << it; \
std::cout << "\n"; \
} while(0)
#define STR_COUT(str) do { \
std::string str_name = #str; \
std::cout << " " << str_name << " : " << str << "\n"; \
} while(0)
// 输出容器调用函数后的结果
#define FUN_AFTER(con, fun) do { \
std::string fun_name = #fun; \
std::cout << " After " << fun_name << " :\n"; \
fun; \
COUT(con); \
} while(0)
#define STR_FUN_AFTER(str, fun) do { \
std::string fun_name = #fun; \
std::cout << " After " << fun_name << " :\n"; \
fun; \
STR_COUT(str); \
} while(0)
// 输出容器调用函数的值
#define FUN_VALUE(fun) do { \
std::string fun_name = #fun; \
std::cout << " " << fun_name << " : " << fun << "\n"; \
} while(0)
// 输出测试数量级
void test_len(size_t len1, size_t len2, size_t len3, size_t wide)
{
std::string str1, str2, str3;
std::stringstream ss;
ss << len1 << " " << len2 << " " << len3;
ss >> str1 >> str2 >> str3;
str1 += " |";
std::cout << std::setw(wide) << str1;
str2 += " |";
std::cout << std::setw(wide) << str2;
str3 += " |";
std::cout << std::setw(wide) << str3 << "\n";
}
#define TEST_LEN(len1, len2, len3, wide) \
test_len(len1, len2, len3, wide)
// 常用测试性能的宏
#define FUN_TEST_FORMAT1(mode, fun, arg, count) do { \
srand((int)time(0)); \
clock_t start, end; \
mode c; \
char buf[10]; \
start = clock(); \
for (size_t i = 0; i < count; ++i) \
c.fun(arg); \
end = clock(); \
int n = static_cast<int>(static_cast<double>(end - start) \
/ CLOCKS_PER_SEC * 1000); \
std::snprintf(buf, sizeof(buf), "%d", n); \
std::string t = buf; \
t += "ms |"; \
std::cout << std::setw(WIDE) << t; \
} while(0)
#define FUN_TEST_FORMAT2(mode, fun, arg1, arg2, count) do { \
srand((int)time(0)); \
clock_t start, end; \
mode c; \
char buf[10]; \
start = clock(); \
for (size_t i = 0; i < count; ++i) \
c.fun(c.arg1(), arg2); \
end = clock(); \
int n = static_cast<int>(static_cast<double>(end - start) \
/ CLOCKS_PER_SEC * 1000); \
std::snprintf(buf, sizeof(buf), "%d", n); \
std::string t = buf; \
t += "ms |"; \
std::cout << std::setw(WIDE) << t; \
} while(0)
#define LIST_SORT_DO_TEST(mode, count) do { \
srand((int)time(0)); \
clock_t start, end; \
mode::list<int> l; \
char buf[10]; \
for (size_t i = 0; i < count; ++i) \
l.insert(l.end(), rand()); \
start = clock(); \
l.sort(); \
end = clock(); \
int n = static_cast<int>(static_cast<double>(end - start) \
/ CLOCKS_PER_SEC * 1000); \
std::snprintf(buf, sizeof(buf), "%d", n); \
std::string t = buf; \
t += "ms |"; \
std::cout << std::setw(WIDE) << t; \
} while(0)
#define MAP_EMPLACE_DO_TEST(mode, con, count) do { \
srand((int)time(0)); \
clock_t start, end; \
mode::con<int, int> c; \
char buf[10]; \
start = clock(); \
for (size_t i = 0; i < count; ++i) \
c.emplace(mode::make_pair(rand(), rand())); \
end = clock(); \
int n = static_cast<int>(static_cast<double>(end - start) \
/ CLOCKS_PER_SEC * 1000); \
std::snprintf(buf, sizeof(buf), "%d", n); \
std::string t = buf; \
t += "ms |"; \
std::cout << std::setw(WIDE) << t; \
} while(0)
// 重构重复代码
#define CON_TEST_P1(con, fun, arg, len1, len2, len3) \
TEST_LEN(len1, len2, len3, WIDE); \
std::cout << "| std |"; \
FUN_TEST_FORMAT1(std::con, fun, arg, len1); \
FUN_TEST_FORMAT1(std::con, fun, arg, len2); \
FUN_TEST_FORMAT1(std::con, fun, arg, len3); \
std::cout << "\n| mystl |"; \
FUN_TEST_FORMAT1(mystl::con, fun, arg, len1); \
FUN_TEST_FORMAT1(mystl::con, fun, arg, len2); \
FUN_TEST_FORMAT1(mystl::con, fun, arg, len3);
#define CON_TEST_P2(con, fun, arg1, arg2, len1, len2, len3) \
TEST_LEN(len1, len2, len3, WIDE); \
std::cout << "| std |"; \
FUN_TEST_FORMAT2(std::con, fun, arg1, arg2, len1); \
FUN_TEST_FORMAT2(std::con, fun, arg1, arg2, len2); \
FUN_TEST_FORMAT2(std::con, fun, arg1, arg2, len3); \
std::cout << "\n| mystl |"; \
FUN_TEST_FORMAT2(mystl::con, fun, arg1, arg2, len1); \
FUN_TEST_FORMAT2(mystl::con, fun, arg1, arg2, len2); \
FUN_TEST_FORMAT2(mystl::con, fun, arg1, arg2, len3);
#define MAP_EMPLACE_TEST(con, len1, len2, len3) \
TEST_LEN(len1, len2, len3, WIDE); \
std::cout << "| std |"; \
MAP_EMPLACE_DO_TEST(std, con, len1); \
MAP_EMPLACE_DO_TEST(std, con, len2); \
MAP_EMPLACE_DO_TEST(std, con, len3); \
std::cout << "\n| mystl |"; \
MAP_EMPLACE_DO_TEST(mystl, con, len1); \
MAP_EMPLACE_DO_TEST(mystl, con, len2); \
MAP_EMPLACE_DO_TEST(mystl, con, len3);
#define LIST_SORT_TEST(len1, len2, len3) \
TEST_LEN(len1, len2, len3, WIDE); \
std::cout << "| std |"; \
LIST_SORT_DO_TEST(std, len1); \
LIST_SORT_DO_TEST(std, len2); \
LIST_SORT_DO_TEST(std, len3); \
std::cout << "\n| mystl |"; \
LIST_SORT_DO_TEST(mystl, len1); \
LIST_SORT_DO_TEST(mystl, len2); \
LIST_SORT_DO_TEST(mystl, len3);
// 简单测试的宏定义
#define TEST(testcase_name) \
MYTINYSTL_TEST_(testcase_name)
// 运行所有测试案例
#define RUN_ALL_TESTS() \
mystl::test::UnitTest::GetInstance()->Run()
// 是否开启性能测试
#ifndef PERFORMANCE_TEST_ON
#define PERFORMANCE_TEST_ON 1
#endif // !PERFORMANCE_TEST_ON
// 是否开启大数据量测试
#ifndef LARGER_TEST_DATA_ON
#define LARGER_TEST_DATA_ON 0
#endif // !LARGER_TEST_DATA_ON
} // namespace test
} // namespace mystl
#endif // !MYTINYSTL_TEST_H_

@ -0,0 +1,203 @@
#ifndef MYTINYSTL_UNORDERED_MAP_TEST_H_
#define MYTINYSTL_UNORDERED_MAP_TEST_H_
// unordered_map test : 测试 unordered_map, unordered_multimap 的接口与它们 insert 的性能
#include <unordered_map>
#include "../MyTinySTL/unordered_map.h"
#include "map_test.h"
#include "test.h"
namespace mystl
{
namespace test
{
namespace unordered_map_test
{
void unordered_map_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[-------------- Run container test : unordered_map -------------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
mystl::vector<PAIR> v;
for (int i = 0; i < 5; ++i)
v.push_back(PAIR(5 - i, 5 - i));
mystl::unordered_map<int, int> um1;
mystl::unordered_map<int, int> um2(520);
mystl::unordered_map<int, int> um3(520, mystl::hash<int>());
mystl::unordered_map<int, int> um4(520, mystl::hash<int>(), mystl::equal_to<int>());
mystl::unordered_map<int, int> um5(v.begin(), v.end());
mystl::unordered_map<int, int> um6(v.begin(), v.end(), 100);
mystl::unordered_map<int, int> um7(v.begin(), v.end(), 100, mystl::hash<int>());
mystl::unordered_map<int, int> um8(v.begin(), v.end(), 100, mystl::hash<int>(), mystl::equal_to<int>());
mystl::unordered_map<int, int> um9(um5);
mystl::unordered_map<int, int> um10(std::move(um5));
mystl::unordered_map<int, int> um11;
um11 = um6;
mystl::unordered_map<int, int> um12;
um12 = std::move(um6);
mystl::unordered_map<int, int> um13{ PAIR(1,1),PAIR(2,3),PAIR(3,3) };
mystl::unordered_map<int, int> um14;
um14 = { PAIR(1,1),PAIR(2,3),PAIR(3,3) };
MAP_FUN_AFTER(um1, um1.emplace(1, 1));
MAP_FUN_AFTER(um1, um1.emplace_hint(um1.begin(), 1, 2));
MAP_FUN_AFTER(um1, um1.insert(PAIR(2, 2)));
MAP_FUN_AFTER(um1, um1.insert(um1.end(), PAIR(3, 3)));
MAP_FUN_AFTER(um1, um1.insert(v.begin(), v.end()));
MAP_FUN_AFTER(um1, um1.erase(um1.begin()));
MAP_FUN_AFTER(um1, um1.erase(um1.begin(), um1.find(3)));
MAP_FUN_AFTER(um1, um1.erase(1));
std::cout << std::boolalpha;
FUN_VALUE(um1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(um1.size());
FUN_VALUE(um1.bucket_count());
FUN_VALUE(um1.max_bucket_count());
FUN_VALUE(um1.bucket(1));
FUN_VALUE(um1.bucket_size(um1.bucket(5)));
MAP_FUN_AFTER(um1, um1.clear());
MAP_FUN_AFTER(um1, um1.swap(um7));
MAP_VALUE(*um1.begin());
FUN_VALUE(um1.at(1));
FUN_VALUE(um1[1]);
std::cout << std::boolalpha;
FUN_VALUE(um1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(um1.size());
FUN_VALUE(um1.max_size());
FUN_VALUE(um1.bucket_count());
FUN_VALUE(um1.max_bucket_count());
FUN_VALUE(um1.bucket(1));
FUN_VALUE(um1.bucket_size(um1.bucket(1)));
MAP_FUN_AFTER(um1, um1.reserve(1000));
FUN_VALUE(um1.size());
FUN_VALUE(um1.bucket_count());
FUN_VALUE(um1.bucket_size(1));
FUN_VALUE(um1.bucket_size(2));
FUN_VALUE(um1.bucket_size(3));
MAP_FUN_AFTER(um1, um1.rehash(150));
FUN_VALUE(um1.bucket_count());
FUN_VALUE(um1.count(1));
MAP_VALUE(*um1.find(3));
auto first = *um1.equal_range(3).first;
auto second = *um1.equal_range(3).second;
std::cout << " um1.equal_range(3) : from <" << first.first << ", " << first.second
<< "> to <" << second.first << ", " << second.second << ">" << std::endl;
FUN_VALUE(um1.load_factor());
FUN_VALUE(um1.max_load_factor());
MAP_FUN_AFTER(um1, um1.max_load_factor(1.5f));
FUN_VALUE(um1.max_load_factor());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| emplace |";
#if LARGER_TEST_DATA_ON
MAP_EMPLACE_TEST(unordered_map, SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));
#else
MAP_EMPLACE_TEST(unordered_map, SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[-------------- End container test : unordered_map -------------]" << std::endl;
}
void unordered_multimap_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[----------- Run container test : unordered_multimap -----------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
mystl::vector<PAIR> v;
for (int i = 0; i < 5; ++i)
v.push_back(PAIR(5 - i, 5 - i));
mystl::unordered_multimap<int, int> um1;
mystl::unordered_multimap<int, int> um2(520);
mystl::unordered_multimap<int, int> um3(520, mystl::hash<int>());
mystl::unordered_multimap<int, int> um4(520, mystl::hash<int>(), mystl::equal_to<int>());
mystl::unordered_multimap<int, int> um5(v.begin(), v.end());
mystl::unordered_multimap<int, int> um6(v.begin(), v.end(), 100);
mystl::unordered_multimap<int, int> um7(v.begin(), v.end(), 100, mystl::hash<int>());
mystl::unordered_multimap<int, int> um8(v.begin(), v.end(), 100, mystl::hash<int>(), mystl::equal_to<int>());
mystl::unordered_multimap<int, int> um9(um5);
mystl::unordered_multimap<int, int> um10(std::move(um5));
mystl::unordered_multimap<int, int> um11;
um11 = um6;
mystl::unordered_multimap<int, int> um12;
um12 = std::move(um6);
mystl::unordered_multimap<int, int> um13{ PAIR(1,1),PAIR(2,3),PAIR(3,3) };
mystl::unordered_multimap<int, int> um14;
um14 = { PAIR(1,1),PAIR(2,3),PAIR(3,3) };
MAP_FUN_AFTER(um1, um1.emplace(1, 1));
MAP_FUN_AFTER(um1, um1.emplace_hint(um1.begin(), 1, 2));
MAP_FUN_AFTER(um1, um1.insert(PAIR(2, 2)));
MAP_FUN_AFTER(um1, um1.insert(um1.end(), PAIR(3, 3)));
MAP_FUN_AFTER(um1, um1.insert(v.begin(), v.end()));
MAP_FUN_AFTER(um1, um1.erase(um1.begin()));
MAP_FUN_AFTER(um1, um1.erase(um1.begin(), um1.find(3)));
MAP_FUN_AFTER(um1, um1.erase(1));
std::cout << std::boolalpha;
FUN_VALUE(um1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(um1.size());
FUN_VALUE(um1.bucket_count());
FUN_VALUE(um1.max_bucket_count());
FUN_VALUE(um1.bucket(1));
FUN_VALUE(um1.bucket_size(um1.bucket(5)));
MAP_FUN_AFTER(um1, um1.clear());
MAP_FUN_AFTER(um1, um1.swap(um7));
MAP_VALUE(*um1.begin());
std::cout << std::boolalpha;
FUN_VALUE(um1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(um1.size());
FUN_VALUE(um1.max_size());
FUN_VALUE(um1.bucket_count());
FUN_VALUE(um1.max_bucket_count());
FUN_VALUE(um1.bucket(1));
FUN_VALUE(um1.bucket_size(um1.bucket(1)));
MAP_FUN_AFTER(um1, um1.reserve(1000));
FUN_VALUE(um1.size());
FUN_VALUE(um1.bucket_count());
FUN_VALUE(um1.bucket_size(1));
FUN_VALUE(um1.bucket_size(2));
FUN_VALUE(um1.bucket_size(3));
MAP_FUN_AFTER(um1, um1.rehash(150));
FUN_VALUE(um1.bucket_count());
FUN_VALUE(um1.count(1));
MAP_VALUE(*um1.find(3));
auto first = *um1.equal_range(3).first;
auto second = *um1.equal_range(3).second;
std::cout << " um1.equal_range(3) : from <" << first.first << ", " << first.second
<< "> to <" << second.first << ", " << second.second << ">" << std::endl;
FUN_VALUE(um1.load_factor());
FUN_VALUE(um1.max_load_factor());
MAP_FUN_AFTER(um1, um1.max_load_factor(1.5f));
FUN_VALUE(um1.max_load_factor());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| emplace |";
#if LARGER_TEST_DATA_ON
MAP_EMPLACE_TEST(unordered_multimap, SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));
#else
MAP_EMPLACE_TEST(unordered_multimap, SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[----------- End container test : unordered_multimap -----------]" << std::endl;
}
} // namespace unordered_map_test
} // namespace test
} // namespace mystl
#endif // !MYTINYSTL_UNORDERED_MAP_TEST_H_

@ -0,0 +1,191 @@
#ifndef MYTINYSTL_UNORDERED_SET_TEST_H_
#define MYTINYSTL_UNORDERED_SET_TEST_H_
// unordered_set test : 测试 unordered_set, unordered_multiset 的接口与它们 insert 的性能
#include <unordered_set>
#include "../MyTinySTL/unordered_set.h"
#include "set_test.h"
#include "test.h"
namespace mystl
{
namespace test
{
namespace unordered_set_test
{
void unordered_set_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[-------------- Run container test : unordered_set -------------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
int a[] = { 5,4,3,2,1 };
mystl::unordered_set<int> us1;
mystl::unordered_set<int> us2(520);
mystl::unordered_set<int> us3(520, mystl::hash<int>());
mystl::unordered_set<int> us4(520, mystl::hash<int>(), mystl::equal_to<int>());
mystl::unordered_set<int> us5(a, a + 5);
mystl::unordered_set<int> us6(a, a + 5, 100);
mystl::unordered_set<int> us7(a, a + 5, 100, mystl::hash<int>());
mystl::unordered_set<int> us8(a, a + 5, 100, mystl::hash<int>(), mystl::equal_to<int>());
mystl::unordered_set<int> us9(us5);
mystl::unordered_set<int> us10(std::move(us5));
mystl::unordered_set<int> us11;
us11 = us6;
mystl::unordered_set<int> us12;
us12 = std::move(us6);
mystl::unordered_set<int> us13{ 1,2,3,4,5 };
mystl::unordered_set<int> us14;
us13 = { 1,2,3,4,5 };
FUN_AFTER(us1, us1.emplace(1));
FUN_AFTER(us1, us1.emplace_hint(us1.end(), 2));
FUN_AFTER(us1, us1.insert(5));
FUN_AFTER(us1, us1.insert(us1.begin(), 5));
FUN_AFTER(us1, us1.insert(a, a + 5));
FUN_AFTER(us1, us1.erase(us1.begin()));
FUN_AFTER(us1, us1.erase(us1.begin(), us1.find(3)));
FUN_AFTER(us1, us1.erase(1));
std::cout << std::boolalpha;
FUN_VALUE(us1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(us1.size());
FUN_VALUE(us1.bucket_count());
FUN_VALUE(us1.max_bucket_count());
FUN_VALUE(us1.bucket(1));
FUN_VALUE(us1.bucket_size(us1.bucket(5)));
FUN_AFTER(us1, us1.clear());
FUN_AFTER(us1, us1.swap(us7));
FUN_VALUE(*us1.begin());
std::cout << std::boolalpha;
FUN_VALUE(us1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(us1.size());
FUN_VALUE(us1.max_size());
FUN_VALUE(us1.bucket_count());
FUN_AFTER(us1, us1.reserve(1000));
FUN_VALUE(*us1.begin(us1.bucket(1)));
FUN_VALUE(us1.size());
FUN_VALUE(us1.bucket_count());
FUN_VALUE(us1.bucket_size(1));
FUN_VALUE(us1.bucket_size(2));
FUN_VALUE(us1.bucket_size(3));
FUN_AFTER(us1, us1.rehash(150));
FUN_VALUE(us1.bucket_count());
FUN_VALUE(us1.count(1));
FUN_VALUE(*us1.find(3));
auto first = *us1.equal_range(3).first;
auto second = *us1.equal_range(3).second;
std::cout << " us1.equal_range(3) : from " << first << " to " << second << std::endl;
FUN_VALUE(us1.load_factor());
FUN_VALUE(us1.max_load_factor());
FUN_AFTER(us1, us1.max_load_factor(1.5f));
FUN_VALUE(us1.max_load_factor());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| emplace |";
#if LARGER_TEST_DATA_ON
CON_TEST_P1(unordered_set<int>, emplace, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));
#else
CON_TEST_P1(unordered_set<int>, emplace, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[-------------- End container test : unordered_set -------------]" << std::endl;
}
void unordered_multiset_test()
{
std::cout << "[===============================================================]" << std::endl;
std::cout << "[------------ Run container test : unordered_multiset ----------]" << std::endl;
std::cout << "[-------------------------- API test ---------------------------]" << std::endl;
int a[] = { 5,4,3,2,1 };
mystl::unordered_multiset<int> us1;
mystl::unordered_multiset<int> us2(520);
mystl::unordered_multiset<int> us3(520, mystl::hash<int>());
mystl::unordered_multiset<int> us4(520, mystl::hash<int>(), mystl::equal_to<int>());
mystl::unordered_multiset<int> us5(a, a + 5);
mystl::unordered_multiset<int> us6(a, a + 5, 100);
mystl::unordered_multiset<int> us7(a, a + 5, 100, mystl::hash<int>());
mystl::unordered_multiset<int> us8(a, a + 5, 100, mystl::hash<int>(), mystl::equal_to<int>());
mystl::unordered_multiset<int> us9(us5);
mystl::unordered_multiset<int> us10(std::move(us5));
mystl::unordered_multiset<int> us11;
us11 = us6;
mystl::unordered_multiset<int> us12;
us12 = std::move(us6);
mystl::unordered_multiset<int> us13{ 1,2,3,4,5 };
mystl::unordered_multiset<int> us14;
us14 = { 1,2,3,4,5 };
FUN_AFTER(us1, us1.emplace(1));
FUN_AFTER(us1, us1.emplace_hint(us1.end(), 2));
FUN_AFTER(us1, us1.insert(5));
FUN_AFTER(us1, us1.insert(us1.begin(), 5));
FUN_AFTER(us1, us1.insert(a, a + 5));
FUN_AFTER(us1, us1.erase(us1.begin()));
FUN_AFTER(us1, us1.erase(us1.begin(), us1.find(3)));
FUN_AFTER(us1, us1.erase(1));
std::cout << std::boolalpha;
FUN_VALUE(us1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(us1.size());
FUN_VALUE(us1.bucket_count());
FUN_VALUE(us1.max_bucket_count());
FUN_VALUE(us1.bucket(1));
FUN_VALUE(us1.bucket_size(us1.bucket(5)));
FUN_AFTER(us1, us1.clear());
FUN_AFTER(us1, us1.swap(us7));
FUN_VALUE(*us1.begin());
std::cout << std::boolalpha;
FUN_VALUE(us1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(us1.size());
FUN_VALUE(us1.max_size());
FUN_VALUE(us1.bucket_count());
FUN_AFTER(us1, us1.reserve(1000));
FUN_VALUE(*us1.begin(us1.bucket(1)));
FUN_VALUE(us1.size());
FUN_VALUE(us1.bucket_count());
FUN_VALUE(us1.bucket_size(1));
FUN_VALUE(us1.bucket_size(2));
FUN_VALUE(us1.bucket_size(3));
FUN_AFTER(us1, us1.rehash(150));
FUN_VALUE(us1.bucket_count());
FUN_VALUE(us1.count(1));
FUN_VALUE(*us1.find(3));
auto first = *us1.equal_range(3).first;
auto second = *us1.equal_range(3).second;
std::cout << " us1.equal_range(3) : from " << first << " to " << second << std::endl;
FUN_VALUE(us1.load_factor());
FUN_VALUE(us1.max_load_factor());
FUN_AFTER(us1, us1.max_load_factor(1.5f));
FUN_VALUE(us1.max_load_factor());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
std::cout << "| emplace |";
#if LARGER_TEST_DATA_ON
CON_TEST_P1(unordered_multiset<int>, emplace, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3));
#else
CON_TEST_P1(unordered_multiset<int>, emplace, rand(), SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3));
#endif
std::cout << std::endl;
std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl;
PASSED;
#endif
std::cout << "[------------ End container test : unordered_multiset ----------]" << std::endl;
}
} // namespace unordered_set_test
} // namespace test
} // namespace mystl
#endif // !MYTINYSTL_UNORDERED_SET_TEST_H_

@ -0,0 +1,114 @@
#ifndef MYTINYSTL_VECTOR_TEST_H_
#define MYTINYSTL_VECTOR_TEST_H_
// vector test : 测试 vector 的接口与 push_back 的性能
#include <vector>
#include "../MyTinySTL/vector.h"
#include "test.h"
namespace mystl
{
namespace test
{
namespace vector_test
{
void vector_test()
{
std::cout << "[===============================================================]\n";
std::cout << "[----------------- Run container test : vector -----------------]\n";
std::cout << "[-------------------------- API test ---------------------------]\n";
int a[] = { 1,2,3,4,5 };
mystl::vector<int> v1;
mystl::vector<int> v2(10);
mystl::vector<int> v3(10, 1);
mystl::vector<int> v4(a, a + 5);
mystl::vector<int> v5(v2);
mystl::vector<int> v6(std::move(v2));
mystl::vector<int> v7{ 1,2,3,4,5,6,7,8,9 };
mystl::vector<int> v8, v9, v10;
v8 = v3;
v9 = std::move(v3);
v10 = { 1,2,3,4,5,6,7,8,9 };
FUN_AFTER(v1, v1.assign(8, 8));
FUN_AFTER(v1, v1.assign(a, a + 5));
FUN_AFTER(v1, v1.emplace(v1.begin(), 0));
FUN_AFTER(v1, v1.emplace_back(6));
FUN_AFTER(v1, v1.push_back(6));
FUN_AFTER(v1, v1.insert(v1.end(), 7));
FUN_AFTER(v1, v1.insert(v1.begin() + 3, 2, 3));
FUN_AFTER(v1, v1.insert(v1.begin(), a, a + 5));
FUN_AFTER(v1, v1.pop_back());
FUN_AFTER(v1, v1.erase(v1.begin()));
FUN_AFTER(v1, v1.erase(v1.begin(), v1.begin() + 2));
FUN_AFTER(v1, v1.reverse());
FUN_AFTER(v1, v1.swap(v4));
FUN_VALUE(*v1.begin());
FUN_VALUE(*(v1.end() - 1));
FUN_VALUE(*v1.rbegin());
FUN_VALUE(*(v1.rend() - 1));
FUN_VALUE(v1.front());
FUN_VALUE(v1.back());
FUN_VALUE(v1[0]);
FUN_VALUE(v1.at(1));
int* p = v1.data();
*p = 10;
*++p = 20;
p[1] = 30;
std::cout << " After change v1.data() :" << "\n";
COUT(v1);
std::cout << std::boolalpha;
FUN_VALUE(v1.empty());
std::cout << std::noboolalpha;
FUN_VALUE(v1.size());
FUN_VALUE(v1.max_size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.resize(10));
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.shrink_to_fit());
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.resize(6, 6));
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.shrink_to_fit());
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.clear());
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.reserve(5));
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.reserve(20));
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
FUN_AFTER(v1, v1.shrink_to_fit());
FUN_VALUE(v1.size());
FUN_VALUE(v1.capacity());
PASSED;
#if PERFORMANCE_TEST_ON
std::cout << "[--------------------- Performance Testing ---------------------]\n";
std::cout << "|---------------------|-------------|-------------|-------------|\n";
std::cout << "| push_back |";
#if LARGER_TEST_DATA_ON
CON_TEST_P1(vector<int>, push_back, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3));
#else
CON_TEST_P1(vector<int>, push_back, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3));
#endif
std::cout << "\n";
std::cout << "|---------------------|-------------|-------------|-------------|\n";
PASSED;
#endif
std::cout << "[----------------- End container test : vector -----------------]\n";
}
} // namespace vector_test
} // namespace test
} // namespace mystl
#endif // !MYTINYSTL_VECTOR_TEST_H_

@ -0,0 +1,21 @@
version: 2.0.1{build}
branches:
only:
- master
image:
- Visual Studio 2015
- Visual Studio 2017
configuration:
- Release
build:
parallel: true
project: MSVC\MyTinySTL_VS2015.sln
test_script:
- cmd: cd .\MSVC\x64\Release\
- cmd: MyTinySTL.exe
Loading…
Cancel
Save